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,123 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.SearchControl = void 0;
var _react = require("react");
var _classnames = _interopRequireDefault(require("classnames"));
var _compose = require("@wordpress/compose");
var _i18n = require("@wordpress/i18n");
var _icons = require("@wordpress/icons");
var _element = require("@wordpress/element");
var _button = _interopRequireDefault(require("../button"));
var _baseControl = _interopRequireDefault(require("../base-control"));
/**
* External dependencies
*/
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
function UnforwardedSearchControl({
__nextHasNoMarginBottom,
__next40pxDefaultSize = false,
className,
onChange,
onKeyDown,
value,
label,
placeholder = (0, _i18n.__)('Search'),
hideLabelFromVision = true,
help,
onClose,
size = 'default',
...restProps
}, forwardedRef) {
const searchRef = (0, _element.useRef)();
const instanceId = (0, _compose.useInstanceId)(SearchControl);
const id = `components-search-control-${instanceId}`;
const renderRightButton = () => {
if (onClose) {
return (0, _react.createElement)(_button.default, {
__next40pxDefaultSize: __next40pxDefaultSize,
icon: _icons.closeSmall,
label: (0, _i18n.__)('Close search'),
onClick: onClose,
size: size
});
}
if (!!value) {
return (0, _react.createElement)(_button.default, {
__next40pxDefaultSize: __next40pxDefaultSize,
icon: _icons.closeSmall,
label: (0, _i18n.__)('Reset search'),
onClick: () => {
onChange('');
searchRef.current?.focus();
},
size: size
});
}
return (0, _react.createElement)(_icons.Icon, {
icon: _icons.search
});
};
return (0, _react.createElement)(_baseControl.default, {
__nextHasNoMarginBottom: __nextHasNoMarginBottom,
label: label,
id: id,
hideLabelFromVision: hideLabelFromVision,
help: help,
className: (0, _classnames.default)(className, 'components-search-control', {
'is-next-40px-default-size': __next40pxDefaultSize,
'is-size-compact': size === 'compact'
})
}, (0, _react.createElement)("div", {
className: "components-search-control__input-wrapper"
}, (0, _react.createElement)("input", {
...restProps,
ref: (0, _compose.useMergeRefs)([searchRef, forwardedRef]),
className: "components-search-control__input",
id: id,
type: "search",
placeholder: placeholder,
onChange: event => onChange(event.target.value),
onKeyDown: onKeyDown,
autoComplete: "off",
value: value || ''
}), (0, _react.createElement)("div", {
className: "components-search-control__icon"
}, renderRightButton())));
}
/**
* SearchControl components let users display a search control.
*
* ```jsx
* import { SearchControl } from '@wordpress/components';
* import { useState } from '@wordpress/element';
*
* function MySearchControl( { className, setState } ) {
* const [ searchInput, setSearchInput ] = useState( '' );
*
* return (
* <SearchControl
* value={ searchInput }
* onChange={ setSearchInput }
* />
* );
* }
* ```
*/
const SearchControl = (0, _element.forwardRef)(UnforwardedSearchControl);
exports.SearchControl = SearchControl;
var _default = SearchControl;
exports.default = _default;
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,206 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = require("react");
var _reactNative = require("react-native");
var _element = require("@wordpress/element");
var _i18n = require("@wordpress/i18n");
var _components = require("@wordpress/components");
var _icons = require("@wordpress/icons");
var _style = _interopRequireDefault(require("./style.scss"));
var _platformStyle = _interopRequireDefault(require("./platform-style.scss"));
/**
* External dependencies
*/
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
// Merge platform specific styles with the default styles.
const baseStyles = {
..._style.default
};
for (const selector in _platformStyle.default) {
baseStyles[selector] = {
...baseStyles[selector],
..._platformStyle.default[selector]
};
}
function selectModifiedStyles(styles, modifier) {
const modifierMatcher = new RegExp(`--${modifier}$`);
const modifierSelectors = Object.keys(styles).filter(selector => selector.match(modifierMatcher));
return modifierSelectors.reduce((modifiedStyles, modifierSelector) => {
const blockElementSelector = modifierSelector.split('--')[0];
modifiedStyles[blockElementSelector] = styles[modifierSelector];
return modifiedStyles;
}, {});
}
function mergeStyles(styles, updateStyles, selectors) {
selectors.forEach(selector => {
styles[selector] = {
...styles[selector],
...updateStyles[selector]
};
});
return styles;
}
function SearchControl({
value,
onChange,
placeholder = (0, _i18n.__)('Search blocks')
}) {
const [isActive, setIsActive] = (0, _element.useState)(false);
const [currentStyles, setCurrentStyles] = (0, _element.useState)(baseStyles);
const isDark = (0, _reactNative.useColorScheme)() === 'dark';
const inputRef = (0, _element.useRef)();
const onCancelTimer = (0, _element.useRef)();
const isIOS = _reactNative.Platform.OS === 'ios';
const darkStyles = (0, _element.useMemo)(() => {
return selectModifiedStyles(baseStyles, 'dark');
}, []);
const activeStyles = (0, _element.useMemo)(() => {
return selectModifiedStyles(baseStyles, 'active');
}, []);
const activeDarkStyles = (0, _element.useMemo)(() => {
return selectModifiedStyles(baseStyles, 'active-dark');
}, []);
(0, _element.useEffect)(() => {
let futureStyles = {
...baseStyles
};
function mergeFutureStyles(modifiedStyles, shouldUseConditions) {
const shouldUseModified = shouldUseConditions.every(should => should);
const updatedStyles = shouldUseModified ? modifiedStyles : futureStyles;
const selectors = Object.keys(modifiedStyles);
futureStyles = mergeStyles(futureStyles, updatedStyles, selectors);
}
mergeFutureStyles(activeStyles, [isActive]);
mergeFutureStyles(darkStyles, [isDark]);
mergeFutureStyles(activeDarkStyles, [isActive, isDark]);
setCurrentStyles(futureStyles);
// Disable reason: deferring this refactor to the native team.
// see https://github.com/WordPress/gutenberg/pull/41166
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isActive, isDark]);
const clearInput = (0, _element.useCallback)(() => {
onChange('');
}, [onChange]);
const onPress = (0, _element.useCallback)(() => {
setIsActive(true);
inputRef.current?.focus();
}, []);
const onFocus = (0, _element.useCallback)(() => {
setIsActive(true);
}, []);
const onCancel = (0, _element.useCallback)(() => {
clearTimeout(onCancelTimer.current);
onCancelTimer.current = setTimeout(() => {
inputRef.current?.blur();
clearInput();
setIsActive(false);
}, 0);
}, [clearInput]);
const onKeyboardDidHide = (0, _element.useCallback)(() => {
if (!isIOS) {
onCancel();
}
}, [isIOS, onCancel]);
(0, _element.useEffect)(() => {
const keyboardHideSubscription = _reactNative.Keyboard.addListener('keyboardDidHide', onKeyboardDidHide);
return () => {
clearTimeout(onCancelTimer.current);
keyboardHideSubscription.remove();
};
}, [onKeyboardDidHide]);
const {
'search-control__container': containerStyle,
'search-control__inner-container': innerContainerStyle,
'search-control__input-container': inputContainerStyle,
'search-control__form-input': formInputStyle,
'search-control__form-input-placeholder': placeholderStyle,
'search-control__input-button': inputButtonStyle,
'search-control__input-button-left': inputButtonLeftStyle,
'search-control__input-button-right': inputButtonRightStyle,
'search-control__cancel-button': cancelButtonStyle,
'search-control__cancel-button-text': cancelButtonTextStyle,
'search-control__icon': iconStyle,
'search-control__right-icon': rightIconStyle
} = currentStyles;
function renderLeftButton() {
const button = !isIOS && isActive ? (0, _react.createElement)(_components.Button, {
label: (0, _i18n.__)('Cancel search'),
icon: _icons.arrowLeft,
onClick: onCancel,
style: iconStyle
}) : (0, _react.createElement)(_icons.Icon, {
icon: _components.Gridicons.search,
fill: iconStyle?.color
});
return (0, _react.createElement)(_reactNative.View, {
style: [inputButtonStyle, inputButtonLeftStyle]
}, button);
}
function renderRightButton() {
let button;
// Add a View element to properly center the input placeholder via flexbox.
if (isIOS && !isActive) {
button = (0, _react.createElement)(_reactNative.View, null);
}
if (!!value) {
button = (0, _react.createElement)(_components.Button, {
label: (0, _i18n.__)('Clear search'),
icon: isIOS ? _icons.cancelCircleFilled : _icons.close,
onClick: clearInput,
style: [iconStyle, rightIconStyle]
});
}
return (0, _react.createElement)(_reactNative.View, {
style: [inputButtonStyle, inputButtonRightStyle]
}, button);
}
function renderCancel() {
if (!isIOS) {
return null;
}
return (0, _react.createElement)(_reactNative.View, {
style: cancelButtonStyle
}, (0, _react.createElement)(_reactNative.Text, {
onPress: onCancel,
style: cancelButtonTextStyle,
accessible: true,
accessibilityRole: 'button',
accessibilityLabel: (0, _i18n.__)('Cancel search'),
accessibilityHint: (0, _i18n.__)('Cancel search')
}, (0, _i18n.__)('Cancel')));
}
return (0, _react.createElement)(_reactNative.TouchableOpacity, {
style: containerStyle,
onPress: onPress,
activeOpacity: 1
}, (0, _react.createElement)(_reactNative.View, {
style: innerContainerStyle
}, (0, _react.createElement)(_reactNative.View, {
style: inputContainerStyle
}, renderLeftButton(), (0, _react.createElement)(_reactNative.TextInput, {
ref: inputRef,
style: formInputStyle,
placeholderTextColor: placeholderStyle?.color,
onChangeText: onChange,
onFocus: onFocus,
value: value,
placeholder: placeholder
}), renderRightButton()), isActive && renderCancel()));
}
var _default = SearchControl;
exports.default = _default;
//# sourceMappingURL=index.native.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
//# sourceMappingURL=types.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":[],"sources":["@wordpress/components/src/search-control/types.ts"],"sourcesContent":["/**\n * External dependencies\n */\nimport type { HTMLAttributes } from 'react';\n\n/**\n * Internal dependencies\n */\nimport type { BaseControlProps } from '../base-control/types';\n\nexport type SearchControlProps = Pick<\n\tBaseControlProps,\n\t'__nextHasNoMarginBottom' | 'help' | 'label'\n> & {\n\t/**\n\t * If true, the label will only be visible to screen readers.\n\t *\n\t * @default true\n\t */\n\thideLabelFromVision?: boolean;\n\t/**\n\t * A function that receives the value of the input when the value is changed.\n\t */\n\tonChange: ( value: string ) => void;\n\t/**\n\t * When an `onClose` callback is provided, the search control will render a close button\n\t * that will trigger the given callback.\n\t *\n\t * Use this if you want the button to trigger your own logic to close the search field entirely,\n\t * rather than just clearing the input value.\n\t */\n\tonClose?: () => void;\n\t/**\n\t * A placeholder for the input.\n\t *\n\t * @default 'Search'\n\t */\n\tplaceholder?: HTMLAttributes< HTMLInputElement >[ 'placeholder' ];\n\t/**\n\t * The current value of the input.\n\t */\n\tvalue?: string;\n\t/**\n\t * The size of the component\n\t *\n\t * @default 'default'\n\t */\n\tsize?: 'default' | 'compact';\n\t/**\n\t * Start opting into the larger default height that will become the default size in a future version.\n\t *\n\t * @default false\n\t */\n\t__next40pxDefaultSize?: boolean;\n};\n"],"mappings":""}