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,239 @@
import { createElement } from "react";
/**
* WordPress dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { useInstanceId } from '@wordpress/compose';
import { useCallback, useMemo } from '@wordpress/element';
import deprecated from '@wordpress/deprecated';
/**
* Internal dependencies
*/
import CircularOptionPicker from '../circular-option-picker';
import CustomGradientPicker from '../custom-gradient-picker';
import { VStack } from '../v-stack';
import { ColorHeading } from '../color-palette/styles';
import { Spacer } from '../spacer';
// The Multiple Origin Gradients have a `gradients` property (an array of
// gradient objects), while Single Origin ones have a `gradient` property.
const isMultipleOriginObject = obj => Array.isArray(obj.gradients) && !('gradient' in obj);
const isMultipleOriginArray = arr => {
return arr.length > 0 && arr.every(gradientObj => isMultipleOriginObject(gradientObj));
};
function SingleOrigin({
className,
clearGradient,
gradients,
onChange,
value,
...additionalProps
}) {
const gradientOptions = useMemo(() => {
return gradients.map(({
gradient,
name,
slug
}, index) => createElement(CircularOptionPicker.Option, {
key: slug,
value: gradient,
isSelected: value === gradient,
tooltipText: name ||
// translators: %s: gradient code e.g: "linear-gradient(90deg, rgba(98,16,153,1) 0%, rgba(172,110,22,1) 100%);".
sprintf(__('Gradient code: %s'), gradient),
style: {
color: 'rgba( 0,0,0,0 )',
background: gradient
},
onClick: value === gradient ? clearGradient : () => onChange(gradient, index),
"aria-label": name ?
// translators: %s: The name of the gradient e.g: "Angular red to blue".
sprintf(__('Gradient: %s'), name) :
// translators: %s: gradient code e.g: "linear-gradient(90deg, rgba(98,16,153,1) 0%, rgba(172,110,22,1) 100%);".
sprintf(__('Gradient code: %s'), gradient)
}));
}, [gradients, value, onChange, clearGradient]);
return createElement(CircularOptionPicker.OptionGroup, {
className: className,
options: gradientOptions,
...additionalProps
});
}
function MultipleOrigin({
className,
clearGradient,
gradients,
onChange,
value,
headingLevel
}) {
const instanceId = useInstanceId(MultipleOrigin);
return createElement(VStack, {
spacing: 3,
className: className
}, gradients.map(({
name,
gradients: gradientSet
}, index) => {
const id = `color-palette-${instanceId}-${index}`;
return createElement(VStack, {
spacing: 2,
key: index
}, createElement(ColorHeading, {
level: headingLevel,
id: id
}, name), createElement(SingleOrigin, {
clearGradient: clearGradient,
gradients: gradientSet,
onChange: gradient => onChange(gradient, index),
value: value,
"aria-labelledby": id
}));
}));
}
function Component(props) {
const {
asButtons,
loop,
actions,
headingLevel,
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledby,
...additionalProps
} = props;
const options = isMultipleOriginArray(props.gradients) ? createElement(MultipleOrigin, {
headingLevel: headingLevel,
...additionalProps
}) : createElement(SingleOrigin, {
...additionalProps
});
let metaProps;
if (asButtons) {
metaProps = {
asButtons: true
};
} else {
const _metaProps = {
asButtons: false,
loop
};
if (ariaLabel) {
metaProps = {
..._metaProps,
'aria-label': ariaLabel
};
} else if (ariaLabelledby) {
metaProps = {
..._metaProps,
'aria-labelledby': ariaLabelledby
};
} else {
metaProps = {
..._metaProps,
'aria-label': __('Custom color picker.')
};
}
}
return createElement(CircularOptionPicker, {
...metaProps,
actions: actions,
options: options
});
}
/**
* GradientPicker is a React component that renders a color gradient picker to
* define a multi step gradient. There's either a _linear_ or a _radial_ type
* available.
*
* ```jsx
*import { GradientPicker } from '@wordpress/components';
*import { useState } from '@wordpress/element';
*
*const myGradientPicker = () => {
* const [ gradient, setGradient ] = useState( null );
*
* return (
* <GradientPicker
* __nextHasNoMargin
* value={ gradient }
* onChange={ ( currentGradient ) => setGradient( currentGradient ) }
* gradients={ [
* {
* name: 'JShine',
* gradient:
* 'linear-gradient(135deg,#12c2e9 0%,#c471ed 50%,#f64f59 100%)',
* slug: 'jshine',
* },
* {
* name: 'Moonlit Asteroid',
* gradient:
* 'linear-gradient(135deg,#0F2027 0%, #203A43 0%, #2c5364 100%)',
* slug: 'moonlit-asteroid',
* },
* {
* name: 'Rastafarie',
* gradient:
* 'linear-gradient(135deg,#1E9600 0%, #FFF200 0%, #FF0000 100%)',
* slug: 'rastafari',
* },
* ] }
* />
* );
*};
*```
*
*/
export function GradientPicker({
/** Start opting into the new margin-free styles that will become the default in a future version. */
__nextHasNoMargin = false,
className,
gradients = [],
onChange,
value,
clearable = true,
disableCustomGradients = false,
__experimentalIsRenderedInSidebar,
headingLevel = 2,
...additionalProps
}) {
const clearGradient = useCallback(() => onChange(undefined), [onChange]);
if (!__nextHasNoMargin) {
deprecated('Outer margin styles for wp.components.GradientPicker', {
since: '6.1',
version: '6.4',
hint: 'Set the `__nextHasNoMargin` prop to true to start opting into the new styles, which will become the default in a future version'
});
}
const deprecatedMarginSpacerProps = !__nextHasNoMargin ? {
marginTop: !gradients.length ? 3 : undefined,
marginBottom: !clearable ? 6 : 0
} : {};
return (
// Outmost Spacer wrapper can be removed when deprecation period is over
createElement(Spacer, {
marginBottom: 0,
...deprecatedMarginSpacerProps
}, createElement(VStack, {
spacing: gradients.length ? 4 : 0
}, !disableCustomGradients && createElement(CustomGradientPicker, {
__nextHasNoMargin: true,
__experimentalIsRenderedInSidebar: __experimentalIsRenderedInSidebar,
value: value,
onChange: onChange
}), (gradients.length > 0 || clearable) && createElement(Component, {
...additionalProps,
className: className,
clearGradient: clearGradient,
gradients: gradients,
onChange: onChange,
value: value,
actions: clearable && !disableCustomGradients && createElement(CircularOptionPicker.ButtonAction, {
onClick: clearGradient
}, __('Clear')),
headingLevel: headingLevel
})))
);
}
export default GradientPicker;
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

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

View File

@@ -0,0 +1 @@
{"version":3,"names":[],"sources":["@wordpress/components/src/gradient-picker/types.ts"],"sourcesContent":["/**\n * Internal dependencies\n */\nimport type { HeadingSize } from '../heading/types';\n\nexport type GradientObject = {\n\tgradient: string;\n\tname: string;\n\tslug: string;\n};\nexport type OriginObject = { name: string; gradients: GradientObject[] };\nexport type GradientsProp = GradientObject[] | OriginObject[];\n\ntype GradientPickerBaseProps = {\n\t/**\n\t * The class name added to the wrapper.\n\t */\n\tclassName?: string;\n\t/**\n\t * The function called when a new gradient has been defined. It is passed to\n\t * the `currentGradient` as an argument.\n\t */\n\tonChange: ( currentGradient: string | undefined ) => void;\n\t/**\n\t * The current value of the gradient. Pass a css gradient string (See default value for example).\n\t * Optionally pass in a `null` value to specify no gradient is currently selected.\n\t *\n\t * @default 'linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%)'\n\t */\n\tvalue?: GradientObject[ 'gradient' ] | null;\n\t/**\n\t * Whether the palette should have a clearing button or not.\n\t *\n\t * @default true\n\t */\n\tclearable?: boolean;\n\t/**\n\t * The heading level. Only applies in cases where gradients are provided\n\t * from multiple origins (ie. when the array passed as the `gradients` prop\n\t * contains two or more items).\n\t *\n\t * @default 2\n\t */\n\theadingLevel?: HeadingSize;\n\t/**\n\t * Whether the control should present as a set of buttons,\n\t * each with its own tab stop.\n\t *\n\t * @default false\n\t */\n\tasButtons?: boolean;\n\t/**\n\t * Prevents keyboard interaction from wrapping around.\n\t * Only used when `asButtons` is not true.\n\t *\n\t * @default true\n\t */\n\tloop?: boolean;\n} & (\n\t| {\n\t\t\t/**\n\t\t\t * A label to identify the purpose of the control.\n\t\t\t *\n\t\t\t * @todo [#54055] Either this or `aria-labelledby` should be required\n\t\t\t */\n\t\t\t'aria-label'?: string;\n\t\t\t'aria-labelledby'?: never;\n\t }\n\t| {\n\t\t\t/**\n\t\t\t * An ID of an element to provide a label for the control.\n\t\t\t *\n\t\t\t * @todo [#54055] Either this or `aria-label` should be required\n\t\t\t */\n\t\t\t'aria-labelledby'?: string;\n\t\t\t'aria-label'?: never;\n\t }\n);\n\nexport type GradientPickerComponentProps = GradientPickerBaseProps & {\n\t/**\n\t * An array of objects as predefined gradients displayed above the gradient\n\t * selector. Alternatively, if there are multiple sets (or 'origins') of\n\t * gradients, you can pass an array of objects each with a `name` and a\n\t * `gradients` array which will in turn contain the predefined gradient objects.\n\t *\n\t * @default []\n\t */\n\tgradients?: GradientsProp;\n\t/**\n\t * Start opting in to the new margin-free styles that will become the default\n\t * in a future version, currently scheduled to be WordPress 6.4. (The prop\n\t * can be safely removed once this happens.)\n\t *\n\t * @default false\n\t */\n\t__nextHasNoMargin?: boolean;\n\t/**\n\t * If true, the gradient picker will not be displayed and only defined\n\t * gradients from `gradients` will be shown.\n\t *\n\t * @default false\n\t */\n\tdisableCustomGradients?: boolean;\n\t/**\n\t * Whether this is rendered in the sidebar.\n\t *\n\t * @default false\n\t */\n\t__experimentalIsRenderedInSidebar?: boolean;\n};\n\nexport type PickerProps< TOriginType extends GradientObject | OriginObject > =\n\tGradientPickerBaseProps & {\n\t\tclearGradient: () => void;\n\t\tonChange: (\n\t\t\tcurrentGradient: string | undefined,\n\t\t\tindex: number\n\t\t) => void;\n\t\tactions?: React.ReactNode;\n\t\tgradients: TOriginType[];\n\t};\n"],"mappings":""}