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,16 @@
import { createElement } from "react";
/**
* WordPress dependencies
*/
import { SVG, Circle } from '@wordpress/primitives';
export const PageControlIcon = () => createElement(SVG, {
width: "8",
height: "8",
fill: "none",
xmlns: "http://www.w3.org/2000/svg"
}, createElement(Circle, {
cx: "4",
cy: "4",
r: "4"
}));
//# sourceMappingURL=icons.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["SVG","Circle","PageControlIcon","createElement","width","height","fill","xmlns","cx","cy","r"],"sources":["@wordpress/components/src/guide/icons.tsx"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { SVG, Circle } from '@wordpress/primitives';\n\nexport const PageControlIcon = () => (\n\t<SVG width=\"8\" height=\"8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n\t\t<Circle cx=\"4\" cy=\"4\" r=\"4\" />\n\t</SVG>\n);\n"],"mappings":";AAAA;AACA;AACA;AACA,SAASA,GAAG,EAAEC,MAAM,QAAQ,uBAAuB;AAEnD,OAAO,MAAMC,eAAe,GAAGA,CAAA,KAC9BC,aAAA,CAACH,GAAG;EAACI,KAAK,EAAC,GAAG;EAACC,MAAM,EAAC,GAAG;EAACC,IAAI,EAAC,MAAM;EAACC,KAAK,EAAC;AAA4B,GACvEJ,aAAA,CAACF,MAAM;EAACO,EAAE,EAAC,GAAG;EAACC,EAAE,EAAC,GAAG;EAACC,CAAC,EAAC;AAAG,CAAE,CACzB,CACL"}

View File

@@ -0,0 +1,140 @@
import { createElement } from "react";
/**
* External dependencies
*/
import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { useState, useEffect, Children, useRef } from '@wordpress/element';
import deprecated from '@wordpress/deprecated';
import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import Modal from '../modal';
import Button from '../button';
import PageControl from './page-control';
/**
* `Guide` is a React component that renders a _user guide_ in a modal. The guide consists of several pages which the user can step through one by one. The guide is finished when the modal is closed or when the user clicks _Finish_ on the last page of the guide.
*
* ```jsx
* function MyTutorial() {
* const [ isOpen, setIsOpen ] = useState( true );
*
* if ( ! isOpen ) {
* return null;
* }
*
* return (
* <Guide
* onFinish={ () => setIsOpen( false ) }
* pages={ [
* {
* content: <p>Welcome to the ACME Store!</p>,
* },
* {
* image: <img src="https://acmestore.com/add-to-cart.png" />,
* content: (
* <p>
* Click <i>Add to Cart</i> to buy a product.
* </p>
* ),
* },
* ] }
* />
* );
* }
* ```
*/
function Guide({
children,
className,
contentLabel,
finishButtonText = __('Finish'),
onFinish,
pages = []
}) {
const ref = useRef(null);
const [currentPage, setCurrentPage] = useState(0);
useEffect(() => {
// Place focus at the top of the guide on mount and when the page changes.
const frame = ref.current?.querySelector('.components-guide');
if (frame instanceof HTMLElement) {
frame.focus();
}
}, [currentPage]);
useEffect(() => {
if (Children.count(children)) {
deprecated('Passing children to <Guide>', {
since: '5.5',
alternative: 'the `pages` prop'
});
}
}, [children]);
if (Children.count(children)) {
var _Children$map;
pages = (_Children$map = Children.map(children, child => ({
content: child
}))) !== null && _Children$map !== void 0 ? _Children$map : [];
}
const canGoBack = currentPage > 0;
const canGoForward = currentPage < pages.length - 1;
const goBack = () => {
if (canGoBack) {
setCurrentPage(currentPage - 1);
}
};
const goForward = () => {
if (canGoForward) {
setCurrentPage(currentPage + 1);
}
};
if (pages.length === 0) {
return null;
}
return createElement(Modal, {
className: classnames('components-guide', className),
contentLabel: contentLabel,
isDismissible: pages.length > 1,
onRequestClose: onFinish,
onKeyDown: event => {
if (event.code === 'ArrowLeft') {
goBack();
// Do not scroll the modal's contents.
event.preventDefault();
} else if (event.code === 'ArrowRight') {
goForward();
// Do not scroll the modal's contents.
event.preventDefault();
}
},
ref: ref
}, createElement("div", {
className: "components-guide__container"
}, createElement("div", {
className: "components-guide__page"
}, pages[currentPage].image, pages.length > 1 && createElement(PageControl, {
currentPage: currentPage,
numberOfPages: pages.length,
setCurrentPage: setCurrentPage
}), pages[currentPage].content), createElement("div", {
className: "components-guide__footer"
}, canGoBack && createElement(Button, {
className: "components-guide__back-button",
variant: "tertiary",
onClick: goBack
}, __('Previous')), canGoForward && createElement(Button, {
className: "components-guide__forward-button",
variant: "primary",
onClick: goForward
}, __('Next')), !canGoForward && createElement(Button, {
className: "components-guide__finish-button",
variant: "primary",
onClick: onFinish
}, finishButtonText))));
}
export default Guide;
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,35 @@
import { createElement } from "react";
/**
* WordPress dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import Button from '../button';
import { PageControlIcon } from './icons';
export default function PageControl({
currentPage,
numberOfPages,
setCurrentPage
}) {
return createElement("ul", {
className: "components-guide__page-control",
"aria-label": __('Guide controls')
}, Array.from({
length: numberOfPages
}).map((_, page) => createElement("li", {
key: page
// Set aria-current="step" on the active page, see https://www.w3.org/TR/wai-aria-1.1/#aria-current
,
"aria-current": page === currentPage ? 'step' : undefined
}, createElement(Button, {
key: page,
icon: createElement(PageControlIcon, null),
"aria-label": sprintf( /* translators: 1: current page number 2: total number of pages */
__('Page %1$d of %2$d'), page + 1, numberOfPages),
onClick: () => setCurrentPage(page)
}))));
}
//# sourceMappingURL=page-control.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["__","sprintf","Button","PageControlIcon","PageControl","currentPage","numberOfPages","setCurrentPage","createElement","className","Array","from","length","map","_","page","key","undefined","icon","onClick"],"sources":["@wordpress/components/src/guide/page-control.tsx"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { __, sprintf } from '@wordpress/i18n';\n\n/**\n * Internal dependencies\n */\nimport Button from '../button';\nimport { PageControlIcon } from './icons';\nimport type { PageControlProps } from './types';\n\nexport default function PageControl( {\n\tcurrentPage,\n\tnumberOfPages,\n\tsetCurrentPage,\n}: PageControlProps ) {\n\treturn (\n\t\t<ul\n\t\t\tclassName=\"components-guide__page-control\"\n\t\t\taria-label={ __( 'Guide controls' ) }\n\t\t>\n\t\t\t{ Array.from( { length: numberOfPages } ).map( ( _, page ) => (\n\t\t\t\t<li\n\t\t\t\t\tkey={ page }\n\t\t\t\t\t// Set aria-current=\"step\" on the active page, see https://www.w3.org/TR/wai-aria-1.1/#aria-current\n\t\t\t\t\taria-current={ page === currentPage ? 'step' : undefined }\n\t\t\t\t>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tkey={ page }\n\t\t\t\t\t\ticon={ <PageControlIcon /> }\n\t\t\t\t\t\taria-label={ sprintf(\n\t\t\t\t\t\t\t/* translators: 1: current page number 2: total number of pages */\n\t\t\t\t\t\t\t__( 'Page %1$d of %2$d' ),\n\t\t\t\t\t\t\tpage + 1,\n\t\t\t\t\t\t\tnumberOfPages\n\t\t\t\t\t\t) }\n\t\t\t\t\t\tonClick={ () => setCurrentPage( page ) }\n\t\t\t\t\t/>\n\t\t\t\t</li>\n\t\t\t) ) }\n\t\t</ul>\n\t);\n}\n"],"mappings":";AAAA;AACA;AACA;AACA,SAASA,EAAE,EAAEC,OAAO,QAAQ,iBAAiB;;AAE7C;AACA;AACA;AACA,OAAOC,MAAM,MAAM,WAAW;AAC9B,SAASC,eAAe,QAAQ,SAAS;AAGzC,eAAe,SAASC,WAAWA,CAAE;EACpCC,WAAW;EACXC,aAAa;EACbC;AACiB,CAAC,EAAG;EACrB,OACCC,aAAA;IACCC,SAAS,EAAC,gCAAgC;IAC1C,cAAaT,EAAE,CAAE,gBAAiB;EAAG,GAEnCU,KAAK,CAACC,IAAI,CAAE;IAAEC,MAAM,EAAEN;EAAc,CAAE,CAAC,CAACO,GAAG,CAAE,CAAEC,CAAC,EAAEC,IAAI,KACvDP,aAAA;IACCQ,GAAG,EAAGD;IACN;IAAA;IACA,gBAAeA,IAAI,KAAKV,WAAW,GAAG,MAAM,GAAGY;EAAW,GAE1DT,aAAA,CAACN,MAAM;IACNc,GAAG,EAAGD,IAAM;IACZG,IAAI,EAAGV,aAAA,CAACL,eAAe,MAAE,CAAG;IAC5B,cAAaF,OAAO,EACnB;IACAD,EAAE,CAAE,mBAAoB,CAAC,EACzBe,IAAI,GAAG,CAAC,EACRT,aACD,CAAG;IACHa,OAAO,EAAGA,CAAA,KAAMZ,cAAc,CAAEQ,IAAK;EAAG,CACxC,CACE,CACH,CACC,CAAC;AAEP"}

View File

@@ -0,0 +1,23 @@
import { createElement } from "react";
/**
* WordPress dependencies
*/
import { useEffect } from '@wordpress/element';
import deprecated from '@wordpress/deprecated';
/**
* Internal dependencies
*/
export default function GuidePage(props) {
useEffect(() => {
deprecated('<GuidePage>', {
since: '5.5',
alternative: 'the `pages` prop in <Guide>'
});
}, []);
return createElement("div", {
...props
});
}
//# sourceMappingURL=page.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["useEffect","deprecated","GuidePage","props","since","alternative","createElement"],"sources":["@wordpress/components/src/guide/page.tsx"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { useEffect } from '@wordpress/element';\nimport deprecated from '@wordpress/deprecated';\n\n/**\n * Internal dependencies\n */\nimport type { WordPressComponentProps } from '../context';\n\nexport default function GuidePage(\n\tprops: WordPressComponentProps< {}, 'div', false >\n) {\n\tuseEffect( () => {\n\t\tdeprecated( '<GuidePage>', {\n\t\t\tsince: '5.5',\n\t\t\talternative: 'the `pages` prop in <Guide>',\n\t\t} );\n\t}, [] );\n\n\treturn <div { ...props } />;\n}\n"],"mappings":";AAAA;AACA;AACA;AACA,SAASA,SAAS,QAAQ,oBAAoB;AAC9C,OAAOC,UAAU,MAAM,uBAAuB;;AAE9C;AACA;AACA;;AAGA,eAAe,SAASC,SAASA,CAChCC,KAAkD,EACjD;EACDH,SAAS,CAAE,MAAM;IAChBC,UAAU,CAAE,aAAa,EAAE;MAC1BG,KAAK,EAAE,KAAK;MACZC,WAAW,EAAE;IACd,CAAE,CAAC;EACJ,CAAC,EAAE,EAAG,CAAC;EAEP,OAAOC,aAAA;IAAA,GAAUH;EAAK,CAAI,CAAC;AAC5B"}

View File

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

View File

@@ -0,0 +1 @@
{"version":3,"names":[],"sources":["@wordpress/components/src/guide/types.ts"],"sourcesContent":["/**\n * External dependencies\n */\nimport type { ReactNode } from 'react';\n\n/**\n * Internal dependencies\n */\nimport type { ModalProps } from '../modal/types';\n\nexport type Page = {\n\t/**\n\t * Content of the page.\n\t */\n\tcontent: ReactNode;\n\t/**\n\t * Image displayed above the page content.\n\t */\n\timage?: ReactNode;\n};\n\nexport type GuideProps = {\n\t/**\n\t * Deprecated. Use `pages` prop instead.\n\t *\n\t * @deprecated since 5.5\n\t */\n\tchildren?: ReactNode;\n\t/**\n\t * A custom class to add to the modal.\n\t */\n\tclassName?: string;\n\t/**\n\t * Used as the modal's accessibility label.\n\t */\n\tcontentLabel: ModalProps[ 'contentLabel' ];\n\t/**\n\t * Use this to customize the label of the _Finish_ button shown at the end of the guide.\n\t *\n\t * @default 'Finish'\n\t */\n\tfinishButtonText?: string;\n\t/**\n\t * A function which is called when the guide is finished.\n\t */\n\tonFinish: ModalProps[ 'onRequestClose' ];\n\t/**\n\t * A list of objects describing each page in the guide. Each object **must** contain a `'content'` property and may optionally contain a `'image'` property.\n\t *\n\t * @default []\n\t */\n\tpages?: Page[];\n};\n\nexport type PageControlProps = {\n\t/**\n\t * Current page index.\n\t */\n\tcurrentPage: number;\n\t/**\n\t * Total number of pages.\n\t */\n\tnumberOfPages: number;\n\t/**\n\t * Called when user clicks on a `PageControlIcon` button.\n\t */\n\tsetCurrentPage: ( page: number ) => void;\n};\n"],"mappings":""}