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

129
node_modules/reakit/src/Clickable/Clickable.ts generated vendored Normal file
View File

@@ -0,0 +1,129 @@
import * as React from "react";
import { createComponent } from "reakit-system/createComponent";
import { createHook } from "reakit-system/createHook";
import { isButton } from "reakit-utils/isButton";
import { useLiveRef } from "reakit-utils/useLiveRef";
import { isSelfTarget } from "reakit-utils/isSelfTarget";
import {
TabbableOptions,
TabbableHTMLProps,
useTabbable,
} from "../Tabbable/Tabbable";
import { CLICKABLE_KEYS } from "./__keys";
export type ClickableOptions = TabbableOptions & {
/**
* Whether or not trigger click on pressing <kbd>Enter</kbd>.
* @private
*/
unstable_clickOnEnter?: boolean;
/**
* Whether or not trigger click on pressing <kbd>Space</kbd>.
* @private
*/
unstable_clickOnSpace?: boolean;
};
export type ClickableHTMLProps = TabbableHTMLProps;
export type ClickableProps = ClickableOptions & ClickableHTMLProps;
function isNativeClick(event: React.KeyboardEvent) {
const element = event.currentTarget;
if (!event.isTrusted) return false;
// istanbul ignore next: can't test trusted events yet
return (
isButton(element) ||
element.tagName === "INPUT" ||
element.tagName === "TEXTAREA" ||
element.tagName === "A" ||
element.tagName === "SELECT"
);
}
export const useClickable = createHook<ClickableOptions, ClickableHTMLProps>({
name: "Clickable",
compose: useTabbable,
keys: CLICKABLE_KEYS,
useOptions({
unstable_clickOnEnter = true,
unstable_clickOnSpace = true,
...options
}) {
return {
unstable_clickOnEnter,
unstable_clickOnSpace,
...options,
};
},
useProps(
options,
{ onKeyDown: htmlOnKeyDown, onKeyUp: htmlOnKeyUp, ...htmlProps }
) {
const [active, setActive] = React.useState(false);
const onKeyDownRef = useLiveRef(htmlOnKeyDown);
const onKeyUpRef = useLiveRef(htmlOnKeyUp);
const onKeyDown = React.useCallback(
(event: React.KeyboardEvent<HTMLElement>) => {
onKeyDownRef.current?.(event);
if (event.defaultPrevented) return;
if (options.disabled) return;
if (event.metaKey) return;
if (!isSelfTarget(event)) return;
const isEnter = options.unstable_clickOnEnter && event.key === "Enter";
const isSpace = options.unstable_clickOnSpace && event.key === " ";
if (isEnter || isSpace) {
if (isNativeClick(event)) return;
event.preventDefault();
if (isEnter) {
event.currentTarget.click();
} else if (isSpace) {
setActive(true);
}
}
},
[
options.disabled,
options.unstable_clickOnEnter,
options.unstable_clickOnSpace,
]
);
const onKeyUp = React.useCallback(
(event: React.KeyboardEvent<HTMLElement>) => {
onKeyUpRef.current?.(event);
if (event.defaultPrevented) return;
if (options.disabled) return;
if (event.metaKey) return;
const isSpace = options.unstable_clickOnSpace && event.key === " ";
if (active && isSpace) {
setActive(false);
event.currentTarget.click();
}
},
[options.disabled, options.unstable_clickOnSpace, active]
);
return {
"data-active": active || undefined,
onKeyDown,
onKeyUp,
...htmlProps,
};
},
});
export const Clickable = createComponent({
as: "button",
memo: true,
useHook: useClickable,
});

73
node_modules/reakit/src/Clickable/README.md generated vendored Normal file
View File

@@ -0,0 +1,73 @@
---
path: /docs/clickable/
---
# Clickable
`Clickable` is an abstract component that implements all the interactions an interactive element needs to be fully accessible when it's not rendered as its respective native element.
<carbon-ad></carbon-ad>
## Installation
```sh
npm install reakit
```
Learn more in [Get started](/docs/get-started/).
## Usage
<!-- eslint-disable no-alert -->
```jsx
import { Clickable } from "reakit/Clickable";
function Example() {
const onClick = () => alert("clicked");
return (
<>
<Clickable as="div" onClick={onClick}>
Clickable
</Clickable>
<Clickable as="div" onClick={onClick} disabled>
Disabled
</Clickable>
<Clickable as="div" onClick={onClick} disabled focusable>
Focusable
</Clickable>
</>
);
}
```
## Accessibility
- Pressing <kbd>Enter</kbd> or <kbd>Space</kbd> triggers a click event on `Clickable` regardless of its rendered element.
- `Clickable` extends the accessibility features of [Tabbable](/docs/tabbable/#accessibility).
Learn more in [Accessibility](/docs/accessibility/).
## Composition
- `Clickable` uses [Tabbable](/docs/tabbable/), and is used by [Button](/docs/button/), [Checkbox](/docs/checkbox/), and [CompositeItem](/docs/composite/).
Learn more in [Composition](/docs/composition/#props-hooks).
## Props
<!-- Automatically generated -->
### `Clickable`
- **`disabled`**
<code>boolean | undefined</code>
Same as the HTML attribute.
- **`focusable`**
<code>boolean | undefined</code>
When an element is `disabled`, it may still be `focusable`. It works
similarly to `readOnly` on form elements. In this case, only
`aria-disabled` will be set.

5
node_modules/reakit/src/Clickable/__keys.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
// Automatically generated
export const CLICKABLE_KEYS = [
"unstable_clickOnEnter",
"unstable_clickOnSpace",
] as const;

View File

@@ -0,0 +1,252 @@
import * as React from "react";
import { render, click, focus, press } from "reakit-test-utils";
import { Clickable, ClickableProps } from "../Clickable";
test("render", () => {
const { getByText } = render(<Clickable>clickable</Clickable>);
expect(getByText("clickable")).toMatchInlineSnapshot(`
<button>
clickable
</button>
`);
});
test("render disabled", () => {
const { getByText } = render(<Clickable disabled>clickable</Clickable>);
expect(getByText("clickable")).toMatchInlineSnapshot(`
<button
aria-disabled="true"
disabled=""
style="pointer-events: none;"
>
clickable
</button>
`);
});
test("render disabled focusable", () => {
const { getByText } = render(
<Clickable disabled focusable>
clickable
</Clickable>
);
expect(getByText("clickable")).toMatchInlineSnapshot(`
<button
aria-disabled="true"
style="pointer-events: none;"
>
clickable
</button>
`);
});
test("click", () => {
const fn = jest.fn();
const { getByText } = render(<Clickable onClick={fn}>clickable</Clickable>);
const clickable = getByText("clickable");
expect(fn).toHaveBeenCalledTimes(0);
click(clickable);
expect(fn).toHaveBeenCalledTimes(1);
});
test("click disabled", () => {
const fn = jest.fn();
const { getByText } = render(
<Clickable onClick={fn} disabled>
clickable
</Clickable>
);
const clickable = getByText("clickable");
click(clickable);
expect(fn).toHaveBeenCalledTimes(0);
});
test("click enabled after disabled", () => {
const fn = jest.fn();
const { getByText, rerender } = render(
<Clickable onClick={fn} disabled>
clickable
</Clickable>
);
const clickable = getByText("clickable");
rerender(<Clickable onClick={fn}>clickable</Clickable>);
click(clickable);
expect(fn).toHaveBeenCalledTimes(1);
});
test("click disabled focusable", () => {
const fn = jest.fn();
const { getByText } = render(
<Clickable onClick={fn} disabled focusable>
clickable
</Clickable>
);
const clickable = getByText("clickable");
click(clickable);
expect(fn).toHaveBeenCalledTimes(0);
});
test("focus", () => {
const { getByText } = render(<Clickable>clickable</Clickable>);
const clickable = getByText("clickable");
expect(clickable).not.toHaveFocus();
focus(clickable);
expect(clickable).toHaveFocus();
});
test("focus disabled", () => {
const { getByText } = render(<Clickable disabled>clickable</Clickable>);
const clickable = getByText("clickable");
expect(clickable).not.toHaveFocus();
focus(clickable);
expect(clickable).not.toHaveFocus();
});
test("focus disabled focusable", () => {
const { getByText } = render(
<Clickable disabled focusable>
clickable
</Clickable>
);
const clickable = getByText("clickable");
expect(clickable).not.toHaveFocus();
focus(clickable);
expect(clickable).toHaveFocus();
});
test("non-native button click", () => {
const fn = jest.fn();
const { getByText } = render(
<Clickable as="div" onClick={fn}>
clickable
</Clickable>
);
const clickable = getByText("clickable");
expect(fn).toHaveBeenCalledTimes(0);
click(clickable);
expect(fn).toHaveBeenCalledTimes(1);
});
test("non-native button click disabled", () => {
const fn = jest.fn();
const { getByText } = render(
<Clickable as="div" onClick={fn} disabled>
clickable
</Clickable>
);
const clickable = getByText("clickable");
click(clickable);
expect(fn).toHaveBeenCalledTimes(0);
});
test("non-native button click disabled focusable", () => {
const fn = jest.fn();
const { getByText } = render(
<Clickable as="div" onClick={fn} disabled focusable>
clickable
</Clickable>
);
const clickable = getByText("clickable");
click(clickable);
expect(fn).toHaveBeenCalledTimes(0);
});
test("non-native button focus", () => {
const { getByText } = render(<Clickable as="div">clickable</Clickable>);
const clickable = getByText("clickable");
expect(clickable).not.toHaveFocus();
focus(clickable);
expect(clickable).toHaveFocus();
});
test("non-native button focus disabled", () => {
const { getByText } = render(
<Clickable as="div" disabled>
clickable
</Clickable>
);
const clickable = getByText("clickable");
expect(clickable).not.toHaveFocus();
focus(clickable);
expect(clickable).not.toHaveFocus();
});
test("non-native button focus disabled focusable", () => {
const { getByText } = render(
<Clickable as="div" disabled focusable>
clickable
</Clickable>
);
const clickable = getByText("clickable");
expect(clickable).not.toHaveFocus();
focus(clickable);
expect(clickable).toHaveFocus();
});
test("non-native button space/enter", () => {
const fn = jest.fn();
const { getByText } = render(
<Clickable as="div" onClick={fn}>
clickable
</Clickable>
);
const clickable = getByText("clickable");
press.Enter(clickable);
expect(fn).toHaveBeenCalledTimes(1);
press.Space(clickable);
expect(fn).toHaveBeenCalledTimes(2);
});
test("non-native button space/enter disabled", () => {
const fn = jest.fn();
const { getByText } = render(
<Clickable as="div" disabled onClick={fn}>
clickable
</Clickable>
);
const clickable = getByText("clickable");
press.Enter(clickable);
press.Space(clickable);
expect(fn).toHaveBeenCalledTimes(0);
});
test("non-native button space/enter metaKey", () => {
const fn = jest.fn();
const { getByText } = render(
<Clickable as="div" onClick={fn}>
clickable
</Clickable>
);
const clickable = getByText("clickable");
press.Enter(clickable, { metaKey: true });
press.Space(clickable, { metaKey: true });
expect(fn).toHaveBeenCalledTimes(0);
});
test("non-native button space/enter disabled focusable", () => {
const fn = jest.fn();
const { getByText } = render(
<Clickable as="div" disabled focusable onClick={fn}>
clickable
</Clickable>
);
const clickable = getByText("clickable");
press.Enter(clickable);
press.Space(clickable);
expect(fn).toHaveBeenCalledTimes(0);
});
test("press enter on Clickable as another non-native Clickable", () => {
const onClick = jest.fn();
const NonNativeClickable = React.forwardRef<HTMLDivElement, ClickableProps>(
(props, ref) => <Clickable as="div" ref={ref} {...props} />
);
const { getByText } = render(
<Clickable as={NonNativeClickable} onClick={onClick}>
clickable
</Clickable>
);
const clickable = getByText("clickable");
press.Enter(clickable);
expect(onClick).toHaveBeenCalledTimes(1);
});

1
node_modules/reakit/src/Clickable/index.ts generated vendored Normal file
View File

@@ -0,0 +1 @@
export * from "./Clickable";