Files
formipay/node_modules/@wordpress/components/build/modal/index.js
dwindown e8fbfb14c1 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>
2026-04-18 17:02:14 +07:00

302 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.Modal = void 0;
var _react = require("react");
var _classnames = _interopRequireDefault(require("classnames"));
var _element = require("@wordpress/element");
var _compose = require("@wordpress/compose");
var _i18n = require("@wordpress/i18n");
var _icons = require("@wordpress/icons");
var _dom = require("@wordpress/dom");
var ariaHelper = _interopRequireWildcard(require("./aria-helper"));
var _button = _interopRequireDefault(require("../button"));
var _styleProvider = _interopRequireDefault(require("../style-provider"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
/**
* External dependencies
*/
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
// Used to track and dismiss the prior modal when another opens unless nested.
const ModalContext = (0, _element.createContext)([]);
// Used to track body class names applied while modals are open.
const bodyOpenClasses = new Map();
function UnforwardedModal(props, forwardedRef) {
const {
bodyOpenClassName = 'modal-open',
role = 'dialog',
title = null,
focusOnMount = true,
shouldCloseOnEsc = true,
shouldCloseOnClickOutside = true,
isDismissible = true,
/* Accessibility. */
aria = {
labelledby: undefined,
describedby: undefined
},
onRequestClose,
icon,
closeButtonLabel,
children,
style,
overlayClassName,
className,
contentLabel,
onKeyDown,
isFullScreen = false,
size,
headerActions = null,
__experimentalHideHeader = false
} = props;
const ref = (0, _element.useRef)();
const instanceId = (0, _compose.useInstanceId)(Modal);
const headingId = title ? `components-modal-header-${instanceId}` : aria.labelledby;
// The focus hook does not support 'firstContentElement' but this is a valid
// value for the Modal's focusOnMount prop. The following code ensures the focus
// hook will focus the first focusable node within the element to which it is applied.
// When `firstContentElement` is passed as the value of the focusOnMount prop,
// the focus hook is applied to the Modal's content element.
// Otherwise, the focus hook is applied to the Modal's ref. This ensures that the
// focus hook will focus the first element in the Modal's **content** when
// `firstContentElement` is passed.
const focusOnMountRef = (0, _compose.useFocusOnMount)(focusOnMount === 'firstContentElement' ? 'firstElement' : focusOnMount);
const constrainedTabbingRef = (0, _compose.useConstrainedTabbing)();
const focusReturnRef = (0, _compose.useFocusReturn)();
const contentRef = (0, _element.useRef)(null);
const childrenContainerRef = (0, _element.useRef)(null);
const [hasScrolledContent, setHasScrolledContent] = (0, _element.useState)(false);
const [hasScrollableContent, setHasScrollableContent] = (0, _element.useState)(false);
let sizeClass;
if (isFullScreen || size === 'fill') {
sizeClass = 'is-full-screen';
} else if (size) {
sizeClass = `has-size-${size}`;
}
// Determines whether the Modal content is scrollable and updates the state.
const isContentScrollable = (0, _element.useCallback)(() => {
if (!contentRef.current) {
return;
}
const closestScrollContainer = (0, _dom.getScrollContainer)(contentRef.current);
if (contentRef.current === closestScrollContainer) {
setHasScrollableContent(true);
} else {
setHasScrollableContent(false);
}
}, [contentRef]);
// Accessibly isolates/unisolates the modal.
(0, _element.useEffect)(() => {
ariaHelper.modalize(ref.current);
return () => ariaHelper.unmodalize();
}, []);
// Keeps a fresh ref for the subsequent effect.
const refOnRequestClose = (0, _element.useRef)();
(0, _element.useEffect)(() => {
refOnRequestClose.current = onRequestClose;
}, [onRequestClose]);
// The list of `onRequestClose` callbacks of open (non-nested) Modals. Only
// one should remain open at a time and the list enables closing prior ones.
const dismissers = (0, _element.useContext)(ModalContext);
// Used for the tracking and dismissing any nested modals.
const nestedDismissers = (0, _element.useRef)([]);
// Updates the stack tracking open modals at this level and calls
// onRequestClose for any prior and/or nested modals as applicable.
(0, _element.useEffect)(() => {
dismissers.push(refOnRequestClose);
const [first, second] = dismissers;
if (second) first?.current?.();
const nested = nestedDismissers.current;
return () => {
nested[0]?.current?.();
dismissers.shift();
};
}, [dismissers]);
// Adds/removes the value of bodyOpenClassName to body element.
(0, _element.useEffect)(() => {
var _bodyOpenClasses$get;
const theClass = bodyOpenClassName;
const oneMore = 1 + ((_bodyOpenClasses$get = bodyOpenClasses.get(theClass)) !== null && _bodyOpenClasses$get !== void 0 ? _bodyOpenClasses$get : 0);
bodyOpenClasses.set(theClass, oneMore);
document.body.classList.add(bodyOpenClassName);
return () => {
const oneLess = bodyOpenClasses.get(theClass) - 1;
if (oneLess === 0) {
document.body.classList.remove(theClass);
bodyOpenClasses.delete(theClass);
} else {
bodyOpenClasses.set(theClass, oneLess);
}
};
}, [bodyOpenClassName]);
// Calls the isContentScrollable callback when the Modal children container resizes.
(0, _element.useLayoutEffect)(() => {
if (!window.ResizeObserver || !childrenContainerRef.current) {
return;
}
const resizeObserver = new ResizeObserver(isContentScrollable);
resizeObserver.observe(childrenContainerRef.current);
isContentScrollable();
return () => {
resizeObserver.disconnect();
};
}, [isContentScrollable, childrenContainerRef]);
function handleEscapeKeyDown(event) {
if (
// Ignore keydowns from IMEs
event.nativeEvent.isComposing ||
// Workaround for Mac Safari where the final Enter/Backspace of an IME composition
// is `isComposing=false`, even though it's technically still part of the composition.
// These can only be detected by keyCode.
event.keyCode === 229) {
return;
}
if (shouldCloseOnEsc && (event.code === 'Escape' || event.key === 'Escape') && !event.defaultPrevented) {
event.preventDefault();
if (onRequestClose) {
onRequestClose(event);
}
}
}
const onContentContainerScroll = (0, _element.useCallback)(e => {
var _e$currentTarget$scro;
const scrollY = (_e$currentTarget$scro = e?.currentTarget?.scrollTop) !== null && _e$currentTarget$scro !== void 0 ? _e$currentTarget$scro : -1;
if (!hasScrolledContent && scrollY > 0) {
setHasScrolledContent(true);
} else if (hasScrolledContent && scrollY <= 0) {
setHasScrolledContent(false);
}
}, [hasScrolledContent]);
let pressTarget = null;
const overlayPressHandlers = {
onPointerDown: event => {
if (event.target === event.currentTarget) {
pressTarget = event.target;
// Avoids focus changing so that focus return works as expected.
event.preventDefault();
}
},
// Closes the modal with two exceptions. 1. Opening the context menu on
// the overlay. 2. Pressing on the overlay then dragging the pointer
// over the modal and releasing. Due to the modal being a child of the
// overlay, such a gesture is a `click` on the overlay and cannot be
// excepted by a `click` handler. Thus the tactic of handling
// `pointerup` and comparing its target to that of the `pointerdown`.
onPointerUp: ({
target,
button
}) => {
const isSameTarget = target === pressTarget;
pressTarget = null;
if (button === 0 && isSameTarget) onRequestClose();
}
};
const modal =
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
(0, _react.createElement)("div", {
ref: (0, _compose.useMergeRefs)([ref, forwardedRef]),
className: (0, _classnames.default)('components-modal__screen-overlay', overlayClassName),
onKeyDown: handleEscapeKeyDown,
...(shouldCloseOnClickOutside ? overlayPressHandlers : {})
}, (0, _react.createElement)(_styleProvider.default, {
document: document
}, (0, _react.createElement)("div", {
className: (0, _classnames.default)('components-modal__frame', sizeClass, className),
style: style,
ref: (0, _compose.useMergeRefs)([constrainedTabbingRef, focusReturnRef, focusOnMount !== 'firstContentElement' ? focusOnMountRef : null]),
role: role,
"aria-label": contentLabel,
"aria-labelledby": contentLabel ? undefined : headingId,
"aria-describedby": aria.describedby,
tabIndex: -1,
onKeyDown: onKeyDown
}, (0, _react.createElement)("div", {
className: (0, _classnames.default)('components-modal__content', {
'hide-header': __experimentalHideHeader,
'is-scrollable': hasScrollableContent,
'has-scrolled-content': hasScrolledContent
}),
role: "document",
onScroll: onContentContainerScroll,
ref: contentRef,
"aria-label": hasScrollableContent ? (0, _i18n.__)('Scrollable section') : undefined,
tabIndex: hasScrollableContent ? 0 : undefined
}, !__experimentalHideHeader && (0, _react.createElement)("div", {
className: "components-modal__header"
}, (0, _react.createElement)("div", {
className: "components-modal__header-heading-container"
}, icon && (0, _react.createElement)("span", {
className: "components-modal__icon-container",
"aria-hidden": true
}, icon), title && (0, _react.createElement)("h1", {
id: headingId,
className: "components-modal__header-heading"
}, title)), headerActions, isDismissible && (0, _react.createElement)(_button.default, {
onClick: onRequestClose,
icon: _icons.close,
label: closeButtonLabel || (0, _i18n.__)('Close')
})), (0, _react.createElement)("div", {
ref: (0, _compose.useMergeRefs)([childrenContainerRef, focusOnMount === 'firstContentElement' ? focusOnMountRef : null])
}, children)))));
return (0, _element.createPortal)((0, _react.createElement)(ModalContext.Provider, {
value: nestedDismissers.current
}, modal), document.body);
}
/**
* Modals give users information and choices related to a task theyre trying to
* accomplish. They can contain critical information, require decisions, or
* involve multiple tasks.
*
* ```jsx
* import { Button, Modal } from '@wordpress/components';
* import { useState } from '@wordpress/element';
*
* const MyModal = () => {
* const [ isOpen, setOpen ] = useState( false );
* const openModal = () => setOpen( true );
* const closeModal = () => setOpen( false );
*
* return (
* <>
* <Button variant="secondary" onClick={ openModal }>
* Open Modal
* </Button>
* { isOpen && (
* <Modal title="This is my modal" onRequestClose={ closeModal }>
* <Button variant="secondary" onClick={ closeModal }>
* My custom close button
* </Button>
* </Modal>
* ) }
* </>
* );
* };
* ```
*/
const Modal = (0, _element.forwardRef)(UnforwardedModal);
exports.Modal = Modal;
var _default = Modal;
exports.default = _default;
//# sourceMappingURL=index.js.map