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>
391 lines
14 KiB
JavaScript
391 lines
14 KiB
JavaScript
"use strict";
|
|
|
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.default = exports.SLOT_NAME = exports.Popover = void 0;
|
|
var _react = require("react");
|
|
var _classnames = _interopRequireDefault(require("classnames"));
|
|
var _reactDom = require("@floating-ui/react-dom");
|
|
var _framerMotion = require("framer-motion");
|
|
var _element = require("@wordpress/element");
|
|
var _compose = require("@wordpress/compose");
|
|
var _icons = require("@wordpress/icons");
|
|
var _deprecated = _interopRequireDefault(require("@wordpress/deprecated"));
|
|
var _primitives = require("@wordpress/primitives");
|
|
var _button = _interopRequireDefault(require("../button"));
|
|
var _scrollLock = _interopRequireDefault(require("../scroll-lock"));
|
|
var _slotFill = require("../slot-fill");
|
|
var _utils = require("./utils");
|
|
var _context = require("../context");
|
|
var _overlayMiddlewares = require("./overlay-middlewares");
|
|
var _styleProvider = require("../style-provider");
|
|
/**
|
|
* External dependencies
|
|
*/
|
|
|
|
// eslint-disable-next-line no-restricted-imports
|
|
|
|
/**
|
|
* WordPress dependencies
|
|
*/
|
|
|
|
/**
|
|
* Internal dependencies
|
|
*/
|
|
|
|
/**
|
|
* Name of slot in which popover should fill.
|
|
*
|
|
* @type {string}
|
|
*/
|
|
const SLOT_NAME = 'Popover';
|
|
|
|
// An SVG displaying a triangle facing down, filled with a solid
|
|
// color and bordered in such a way to create an arrow-like effect.
|
|
// Keeping the SVG's viewbox squared simplify the arrow positioning
|
|
// calculations.
|
|
exports.SLOT_NAME = SLOT_NAME;
|
|
const ArrowTriangle = () => (0, _react.createElement)(_primitives.SVG, {
|
|
xmlns: "http://www.w3.org/2000/svg",
|
|
viewBox: `0 0 100 100`,
|
|
className: "components-popover__triangle",
|
|
role: "presentation"
|
|
}, (0, _react.createElement)(_primitives.Path, {
|
|
className: "components-popover__triangle-bg",
|
|
d: "M 0 0 L 50 50 L 100 0"
|
|
}), (0, _react.createElement)(_primitives.Path, {
|
|
className: "components-popover__triangle-border",
|
|
d: "M 0 0 L 50 50 L 100 0",
|
|
vectorEffect: "non-scaling-stroke"
|
|
}));
|
|
const slotNameContext = (0, _element.createContext)(undefined);
|
|
const fallbackContainerClassname = 'components-popover__fallback-container';
|
|
const getPopoverFallbackContainer = () => {
|
|
let container = document.body.querySelector('.' + fallbackContainerClassname);
|
|
if (!container) {
|
|
container = document.createElement('div');
|
|
container.className = fallbackContainerClassname;
|
|
document.body.append(container);
|
|
}
|
|
return container;
|
|
};
|
|
const UnconnectedPopover = (props, forwardedRef) => {
|
|
const {
|
|
animate = true,
|
|
headerTitle,
|
|
onClose,
|
|
children,
|
|
className,
|
|
noArrow = true,
|
|
position,
|
|
placement: placementProp = 'bottom-start',
|
|
offset: offsetProp = 0,
|
|
focusOnMount = 'firstElement',
|
|
anchor,
|
|
expandOnMobile,
|
|
onFocusOutside,
|
|
__unstableSlotName = SLOT_NAME,
|
|
flip = true,
|
|
resize = true,
|
|
shift = false,
|
|
inline = false,
|
|
variant,
|
|
// Deprecated props
|
|
__unstableForcePosition,
|
|
anchorRef,
|
|
anchorRect,
|
|
getAnchorRect,
|
|
isAlternate,
|
|
// Rest
|
|
...contentProps
|
|
} = (0, _context.useContextSystem)(props, 'Popover');
|
|
let computedFlipProp = flip;
|
|
let computedResizeProp = resize;
|
|
if (__unstableForcePosition !== undefined) {
|
|
(0, _deprecated.default)('`__unstableForcePosition` prop in wp.components.Popover', {
|
|
since: '6.1',
|
|
version: '6.3',
|
|
alternative: '`flip={ false }` and `resize={ false }`'
|
|
});
|
|
|
|
// Back-compat, set the `flip` and `resize` props
|
|
// to `false` to replicate `__unstableForcePosition`.
|
|
computedFlipProp = !__unstableForcePosition;
|
|
computedResizeProp = !__unstableForcePosition;
|
|
}
|
|
if (anchorRef !== undefined) {
|
|
(0, _deprecated.default)('`anchorRef` prop in wp.components.Popover', {
|
|
since: '6.1',
|
|
alternative: '`anchor` prop'
|
|
});
|
|
}
|
|
if (anchorRect !== undefined) {
|
|
(0, _deprecated.default)('`anchorRect` prop in wp.components.Popover', {
|
|
since: '6.1',
|
|
alternative: '`anchor` prop'
|
|
});
|
|
}
|
|
if (getAnchorRect !== undefined) {
|
|
(0, _deprecated.default)('`getAnchorRect` prop in wp.components.Popover', {
|
|
since: '6.1',
|
|
alternative: '`anchor` prop'
|
|
});
|
|
}
|
|
const computedVariant = isAlternate ? 'toolbar' : variant;
|
|
if (isAlternate !== undefined) {
|
|
(0, _deprecated.default)('`isAlternate` prop in wp.components.Popover', {
|
|
since: '6.2',
|
|
alternative: "`variant` prop with the `'toolbar'` value"
|
|
});
|
|
}
|
|
const arrowRef = (0, _element.useRef)(null);
|
|
const [fallbackReferenceElement, setFallbackReferenceElement] = (0, _element.useState)(null);
|
|
const anchorRefFallback = (0, _element.useCallback)(node => {
|
|
setFallbackReferenceElement(node);
|
|
}, []);
|
|
const isMobileViewport = (0, _compose.useViewportMatch)('medium', '<');
|
|
const isExpanded = expandOnMobile && isMobileViewport;
|
|
const hasArrow = !isExpanded && !noArrow;
|
|
const normalizedPlacementFromProps = position ? (0, _utils.positionToPlacement)(position) : placementProp;
|
|
const middleware = [...(placementProp === 'overlay' ? (0, _overlayMiddlewares.overlayMiddlewares)() : []), (0, _reactDom.offset)(offsetProp), computedFlipProp && (0, _reactDom.flip)(), computedResizeProp && (0, _reactDom.size)({
|
|
apply(sizeProps) {
|
|
var _refs$floating$curren;
|
|
const {
|
|
firstElementChild
|
|
} = (_refs$floating$curren = refs.floating.current) !== null && _refs$floating$curren !== void 0 ? _refs$floating$curren : {};
|
|
|
|
// Only HTMLElement instances have the `style` property.
|
|
if (!(firstElementChild instanceof HTMLElement)) return;
|
|
|
|
// Reduce the height of the popover to the available space.
|
|
Object.assign(firstElementChild.style, {
|
|
maxHeight: `${sizeProps.availableHeight}px`,
|
|
overflow: 'auto'
|
|
});
|
|
}
|
|
}), shift && (0, _reactDom.shift)({
|
|
crossAxis: true,
|
|
limiter: (0, _reactDom.limitShift)(),
|
|
padding: 1 // Necessary to avoid flickering at the edge of the viewport.
|
|
}), (0, _reactDom.arrow)({
|
|
element: arrowRef
|
|
})];
|
|
const slotName = (0, _element.useContext)(slotNameContext) || __unstableSlotName;
|
|
const slot = (0, _slotFill.useSlot)(slotName);
|
|
let onDialogClose;
|
|
if (onClose || onFocusOutside) {
|
|
onDialogClose = (type, event) => {
|
|
// Ideally the popover should have just a single onClose prop and
|
|
// not three props that potentially do the same thing.
|
|
if (type === 'focus-outside' && onFocusOutside) {
|
|
onFocusOutside(event);
|
|
} else if (onClose) {
|
|
onClose();
|
|
}
|
|
};
|
|
}
|
|
const [dialogRef, dialogProps] = (0, _compose.__experimentalUseDialog)({
|
|
focusOnMount,
|
|
__unstableOnClose: onDialogClose,
|
|
// @ts-expect-error The __unstableOnClose property needs to be deprecated first (see https://github.com/WordPress/gutenberg/pull/27675)
|
|
onClose: onDialogClose
|
|
});
|
|
const {
|
|
// Positioning coordinates
|
|
x,
|
|
y,
|
|
// Object with "regular" refs to both "reference" and "floating"
|
|
refs,
|
|
// Type of CSS position property to use (absolute or fixed)
|
|
strategy,
|
|
update,
|
|
placement: computedPlacement,
|
|
middlewareData: {
|
|
arrow: arrowData
|
|
}
|
|
} = (0, _reactDom.useFloating)({
|
|
placement: normalizedPlacementFromProps === 'overlay' ? undefined : normalizedPlacementFromProps,
|
|
middleware,
|
|
whileElementsMounted: (referenceParam, floatingParam, updateParam) => (0, _reactDom.autoUpdate)(referenceParam, floatingParam, updateParam, {
|
|
layoutShift: false,
|
|
animationFrame: true
|
|
})
|
|
});
|
|
const arrowCallbackRef = (0, _element.useCallback)(node => {
|
|
arrowRef.current = node;
|
|
update();
|
|
}, [update]);
|
|
|
|
// When any of the possible anchor "sources" change,
|
|
// recompute the reference element (real or virtual) and its owner document.
|
|
|
|
const anchorRefTop = anchorRef?.top;
|
|
const anchorRefBottom = anchorRef?.bottom;
|
|
const anchorRefStartContainer = anchorRef?.startContainer;
|
|
const anchorRefCurrent = anchorRef?.current;
|
|
(0, _element.useLayoutEffect)(() => {
|
|
const resultingReferenceElement = (0, _utils.getReferenceElement)({
|
|
anchor,
|
|
anchorRef,
|
|
anchorRect,
|
|
getAnchorRect,
|
|
fallbackReferenceElement
|
|
});
|
|
refs.setReference(resultingReferenceElement);
|
|
}, [anchor, anchorRef, anchorRefTop, anchorRefBottom, anchorRefStartContainer, anchorRefCurrent, anchorRect, getAnchorRect, fallbackReferenceElement, refs]);
|
|
const mergedFloatingRef = (0, _compose.useMergeRefs)([refs.setFloating, dialogRef, forwardedRef]);
|
|
const style = isExpanded ? undefined : {
|
|
position: strategy,
|
|
top: 0,
|
|
left: 0,
|
|
// `x` and `y` are framer-motion specific props and are shorthands
|
|
// for `translateX` and `translateY`. Currently it is not possible
|
|
// to use `translateX` and `translateY` because those values would
|
|
// be overridden by the return value of the
|
|
// `placementToMotionAnimationProps` function.
|
|
x: (0, _utils.computePopoverPosition)(x),
|
|
y: (0, _utils.computePopoverPosition)(y)
|
|
};
|
|
const shouldReduceMotion = (0, _framerMotion.useReducedMotion)();
|
|
const shouldAnimate = animate && !isExpanded && !shouldReduceMotion;
|
|
const [animationFinished, setAnimationFinished] = (0, _element.useState)(false);
|
|
const {
|
|
style: motionInlineStyles,
|
|
...otherMotionProps
|
|
} = (0, _element.useMemo)(() => (0, _utils.placementToMotionAnimationProps)(computedPlacement), [computedPlacement]);
|
|
const animationProps = shouldAnimate ? {
|
|
style: {
|
|
...motionInlineStyles,
|
|
...style
|
|
},
|
|
onAnimationComplete: () => setAnimationFinished(true),
|
|
...otherMotionProps
|
|
} : {
|
|
animate: false,
|
|
style
|
|
};
|
|
|
|
// When Floating UI has finished positioning and Framer Motion has finished animating
|
|
// the popover, add the `is-positioned` class to signal that all transitions have finished.
|
|
const isPositioned = (!shouldAnimate || animationFinished) && x !== null && y !== null;
|
|
|
|
// In case a `ColorPicker` component is rendered as a child of `Popover`,
|
|
// the `Popover` component can be notified of when the user is dragging
|
|
// parts of the `ColorPicker` UI (this is possible because the `ColorPicker`
|
|
// component exposes the `onPickerDragStart` and `onPickerDragEnd` props
|
|
// via internal context).
|
|
// While the user is performing a pointer drag, the `Popover` will render
|
|
// a transparent backdrop element that will serve as a "pointer events trap",
|
|
// making sure that no pointer events reach any potential `iframe` element
|
|
// underneath (like, for example, the editor canvas in the WordPress editor).
|
|
const [showBackdrop, setShowBackdrop] = (0, _element.useState)(false);
|
|
const contextValue = (0, _element.useMemo)(() => ({
|
|
ColorPicker: {
|
|
onPickerDragStart() {
|
|
setShowBackdrop(true);
|
|
},
|
|
onPickerDragEnd() {
|
|
setShowBackdrop(false);
|
|
}
|
|
}
|
|
}), []);
|
|
let content = (0, _react.createElement)(_react.Fragment, null, showBackdrop && (0, _react.createElement)("div", {
|
|
className: "components-popover-pointer-events-trap",
|
|
"aria-hidden": "true",
|
|
onClick: () => setShowBackdrop(false)
|
|
}), (0, _react.createElement)(_framerMotion.motion.div, {
|
|
className: (0, _classnames.default)('components-popover', className, {
|
|
'is-expanded': isExpanded,
|
|
'is-positioned': isPositioned,
|
|
// Use the 'alternate' classname for 'toolbar' variant for back compat.
|
|
[`is-${computedVariant === 'toolbar' ? 'alternate' : computedVariant}`]: computedVariant
|
|
}),
|
|
...animationProps,
|
|
...contentProps,
|
|
ref: mergedFloatingRef,
|
|
...dialogProps,
|
|
tabIndex: -1
|
|
}, isExpanded && (0, _react.createElement)(_scrollLock.default, null), isExpanded && (0, _react.createElement)("div", {
|
|
className: "components-popover__header"
|
|
}, (0, _react.createElement)("span", {
|
|
className: "components-popover__header-title"
|
|
}, headerTitle), (0, _react.createElement)(_button.default, {
|
|
className: "components-popover__close",
|
|
icon: _icons.close,
|
|
onClick: onClose
|
|
})), (0, _react.createElement)("div", {
|
|
className: "components-popover__content"
|
|
}, (0, _react.createElement)(_context.ContextSystemProvider, {
|
|
value: contextValue
|
|
}, children)), hasArrow && (0, _react.createElement)("div", {
|
|
ref: arrowCallbackRef,
|
|
className: ['components-popover__arrow', `is-${computedPlacement.split('-')[0]}`].join(' '),
|
|
style: {
|
|
left: typeof arrowData?.x !== 'undefined' && Number.isFinite(arrowData.x) ? `${arrowData.x}px` : '',
|
|
top: typeof arrowData?.y !== 'undefined' && Number.isFinite(arrowData.y) ? `${arrowData.y}px` : ''
|
|
}
|
|
}, (0, _react.createElement)(ArrowTriangle, null))));
|
|
const shouldRenderWithinSlot = slot.ref && !inline;
|
|
const hasAnchor = anchorRef || anchorRect || anchor;
|
|
if (shouldRenderWithinSlot) {
|
|
content = (0, _react.createElement)(_slotFill.Fill, {
|
|
name: slotName
|
|
}, content);
|
|
} else if (!inline) {
|
|
content = (0, _element.createPortal)((0, _react.createElement)(_styleProvider.StyleProvider, {
|
|
document: document
|
|
}, content), getPopoverFallbackContainer());
|
|
}
|
|
if (hasAnchor) {
|
|
return content;
|
|
}
|
|
return (0, _react.createElement)(_react.Fragment, null, (0, _react.createElement)("span", {
|
|
ref: anchorRefFallback
|
|
}), content);
|
|
};
|
|
|
|
/**
|
|
* `Popover` renders its content in a floating modal. If no explicit anchor is passed via props, it anchors to its parent element by default.
|
|
*
|
|
* ```jsx
|
|
* import { Button, Popover } from '@wordpress/components';
|
|
* import { useState } from '@wordpress/element';
|
|
*
|
|
* const MyPopover = () => {
|
|
* const [ isVisible, setIsVisible ] = useState( false );
|
|
* const toggleVisible = () => {
|
|
* setIsVisible( ( state ) => ! state );
|
|
* };
|
|
*
|
|
* return (
|
|
* <Button variant="secondary" onClick={ toggleVisible }>
|
|
* Toggle Popover!
|
|
* { isVisible && <Popover>Popover is toggled!</Popover> }
|
|
* </Button>
|
|
* );
|
|
* };
|
|
* ```
|
|
*
|
|
*/
|
|
const Popover = (0, _context.contextConnect)(UnconnectedPopover, 'Popover');
|
|
exports.Popover = Popover;
|
|
function PopoverSlot({
|
|
name = SLOT_NAME
|
|
}, ref) {
|
|
return (0, _react.createElement)(_slotFill.Slot, {
|
|
bubblesVirtually: true,
|
|
name: name,
|
|
className: "popover-slot",
|
|
ref: ref
|
|
});
|
|
}
|
|
|
|
// @ts-expect-error For Legacy Reasons
|
|
Popover.Slot = (0, _element.forwardRef)(PopoverSlot);
|
|
// @ts-expect-error For Legacy Reasons
|
|
Popover.__unstableSlotNameProvider = slotNameContext.Provider;
|
|
var _default = Popover;
|
|
exports.default = _default;
|
|
//# sourceMappingURL=index.js.map
|