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>
187 lines
5.9 KiB
JavaScript
187 lines
5.9 KiB
JavaScript
import { createElement } from "react";
|
|
/**
|
|
* External dependencies
|
|
*/
|
|
// eslint-disable-next-line no-restricted-imports
|
|
import * as Ariakit from '@ariakit/react';
|
|
import classnames from 'classnames';
|
|
/**
|
|
* WordPress dependencies
|
|
*/
|
|
import { forwardRef, useEffect, useLayoutEffect, useCallback } from '@wordpress/element';
|
|
import { useInstanceId, usePrevious } from '@wordpress/compose';
|
|
|
|
/**
|
|
* Internal dependencies
|
|
*/
|
|
|
|
import Button from '../button';
|
|
// Separate the actual tab name from the instance ID. This is
|
|
// necessary because Ariakit internally uses the element ID when
|
|
// a new tab is selected, but our implementation looks specifically
|
|
// for the tab name to be passed to the `onSelect` callback.
|
|
const extractTabName = id => {
|
|
if (typeof id === 'undefined' || id === null) {
|
|
return;
|
|
}
|
|
return id.match(/^tab-panel-[0-9]*-(.*)/)?.[1];
|
|
};
|
|
|
|
/**
|
|
* TabPanel is an ARIA-compliant tabpanel.
|
|
*
|
|
* TabPanels organize content across different screens, data sets, and interactions.
|
|
* It has two sections: a list of tabs, and the view to show when tabs are chosen.
|
|
*
|
|
* ```jsx
|
|
* import { TabPanel } from '@wordpress/components';
|
|
*
|
|
* const onSelect = ( tabName ) => {
|
|
* console.log( 'Selecting tab', tabName );
|
|
* };
|
|
*
|
|
* const MyTabPanel = () => (
|
|
* <TabPanel
|
|
* className="my-tab-panel"
|
|
* activeClass="active-tab"
|
|
* onSelect={ onSelect }
|
|
* tabs={ [
|
|
* {
|
|
* name: 'tab1',
|
|
* title: 'Tab 1',
|
|
* className: 'tab-one',
|
|
* },
|
|
* {
|
|
* name: 'tab2',
|
|
* title: 'Tab 2',
|
|
* className: 'tab-two',
|
|
* },
|
|
* ] }
|
|
* >
|
|
* { ( tab ) => <p>{ tab.title }</p> }
|
|
* </TabPanel>
|
|
* );
|
|
* ```
|
|
*/
|
|
const UnforwardedTabPanel = ({
|
|
className,
|
|
children,
|
|
tabs,
|
|
selectOnMove = true,
|
|
initialTabName,
|
|
orientation = 'horizontal',
|
|
activeClass = 'is-active',
|
|
onSelect
|
|
}, ref) => {
|
|
const instanceId = useInstanceId(TabPanel, 'tab-panel');
|
|
const prependInstanceId = useCallback(tabName => {
|
|
if (typeof tabName === 'undefined') {
|
|
return;
|
|
}
|
|
return `${instanceId}-${tabName}`;
|
|
}, [instanceId]);
|
|
const tabStore = Ariakit.useTabStore({
|
|
setSelectedId: newTabValue => {
|
|
if (typeof newTabValue === 'undefined' || newTabValue === null) {
|
|
return;
|
|
}
|
|
const newTab = tabs.find(t => prependInstanceId(t.name) === newTabValue);
|
|
if (newTab?.disabled || newTab === selectedTab) {
|
|
return;
|
|
}
|
|
const simplifiedTabName = extractTabName(newTabValue);
|
|
if (typeof simplifiedTabName === 'undefined') {
|
|
return;
|
|
}
|
|
onSelect?.(simplifiedTabName);
|
|
},
|
|
orientation,
|
|
selectOnMove,
|
|
defaultSelectedId: prependInstanceId(initialTabName)
|
|
});
|
|
const selectedTabName = extractTabName(tabStore.useState('selectedId'));
|
|
const setTabStoreSelectedId = useCallback(tabName => {
|
|
tabStore.setState('selectedId', prependInstanceId(tabName));
|
|
}, [prependInstanceId, tabStore]);
|
|
const selectedTab = tabs.find(({
|
|
name
|
|
}) => name === selectedTabName);
|
|
const previousSelectedTabName = usePrevious(selectedTabName);
|
|
|
|
// Ensure `onSelect` is called when the initial tab is selected.
|
|
useEffect(() => {
|
|
if (previousSelectedTabName !== selectedTabName && selectedTabName === initialTabName && !!selectedTabName) {
|
|
onSelect?.(selectedTabName);
|
|
}
|
|
}, [selectedTabName, initialTabName, onSelect, previousSelectedTabName]);
|
|
|
|
// Handle selecting the initial tab.
|
|
useLayoutEffect(() => {
|
|
// If there's a selected tab, don't override it.
|
|
if (selectedTab) {
|
|
return;
|
|
}
|
|
const initialTab = tabs.find(tab => tab.name === initialTabName);
|
|
// Wait for the denoted initial tab to be declared before making a
|
|
// selection. This ensures that if a tab is declared lazily it can
|
|
// still receive initial selection.
|
|
if (initialTabName && !initialTab) {
|
|
return;
|
|
}
|
|
if (initialTab && !initialTab.disabled) {
|
|
// Select the initial tab if it's not disabled.
|
|
setTabStoreSelectedId(initialTab.name);
|
|
} else {
|
|
// Fallback to the first enabled tab when the initial tab is
|
|
// disabled or it can't be found.
|
|
const firstEnabledTab = tabs.find(tab => !tab.disabled);
|
|
if (firstEnabledTab) {
|
|
setTabStoreSelectedId(firstEnabledTab.name);
|
|
}
|
|
}
|
|
}, [tabs, selectedTab, initialTabName, instanceId, setTabStoreSelectedId]);
|
|
|
|
// Handle the currently selected tab becoming disabled.
|
|
useEffect(() => {
|
|
// This effect only runs when the selected tab is defined and becomes disabled.
|
|
if (!selectedTab?.disabled) {
|
|
return;
|
|
}
|
|
const firstEnabledTab = tabs.find(tab => !tab.disabled);
|
|
// If the currently selected tab becomes disabled, select the first enabled tab.
|
|
// (if there is one).
|
|
if (firstEnabledTab) {
|
|
setTabStoreSelectedId(firstEnabledTab.name);
|
|
}
|
|
}, [tabs, selectedTab?.disabled, setTabStoreSelectedId, instanceId]);
|
|
return createElement("div", {
|
|
className: className,
|
|
ref: ref
|
|
}, createElement(Ariakit.TabList, {
|
|
store: tabStore,
|
|
className: "components-tab-panel__tabs"
|
|
}, tabs.map(tab => {
|
|
return createElement(Ariakit.Tab, {
|
|
key: tab.name,
|
|
id: prependInstanceId(tab.name),
|
|
className: classnames('components-tab-panel__tabs-item', tab.className, {
|
|
[activeClass]: tab.name === selectedTabName
|
|
}),
|
|
disabled: tab.disabled,
|
|
"aria-controls": `${prependInstanceId(tab.name)}-view`,
|
|
render: createElement(Button, {
|
|
icon: tab.icon,
|
|
label: tab.icon && tab.title,
|
|
showTooltip: !!tab.icon
|
|
})
|
|
}, !tab.icon && tab.title);
|
|
})), selectedTab && createElement(Ariakit.TabPanel, {
|
|
id: `${prependInstanceId(selectedTab.name)}-view`,
|
|
store: tabStore,
|
|
tabId: prependInstanceId(selectedTab.name),
|
|
className: 'components-tab-panel__tab-content'
|
|
}, children(selectedTab)));
|
|
};
|
|
export const TabPanel = forwardRef(UnforwardedTabPanel);
|
|
export default TabPanel;
|
|
//# sourceMappingURL=index.js.map
|