@wordpress/components
Version:
UI components for WordPress.
202 lines (194 loc) • 7.52 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.TabPanel = void 0;
var Ariakit = _interopRequireWildcard(require("@ariakit/react"));
var _clsx = _interopRequireDefault(require("clsx"));
var _element = require("@wordpress/element");
var _compose = require("@wordpress/compose");
var _i18n = require("@wordpress/i18n");
var _button = _interopRequireDefault(require("../button"));
var _jsxRuntime = require("react/jsx-runtime");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
/**
* External dependencies
*/
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
// 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 = (0, _compose.useInstanceId)(TabPanel, 'tab-panel');
const prependInstanceId = (0, _element.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),
rtl: (0, _i18n.isRTL)()
});
const selectedTabName = extractTabName(Ariakit.useStoreState(tabStore, 'selectedId'));
const setTabStoreSelectedId = (0, _element.useCallback)(tabName => {
tabStore.setState('selectedId', prependInstanceId(tabName));
}, [prependInstanceId, tabStore]);
const selectedTab = tabs.find(({
name
}) => name === selectedTabName);
const previousSelectedTabName = (0, _compose.usePrevious)(selectedTabName);
// Ensure `onSelect` is called when the initial tab is selected.
(0, _element.useEffect)(() => {
if (previousSelectedTabName !== selectedTabName && selectedTabName === initialTabName && !!selectedTabName) {
onSelect?.(selectedTabName);
}
}, [selectedTabName, initialTabName, onSelect, previousSelectedTabName]);
// Handle selecting the initial tab.
(0, _element.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.
(0, _element.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 /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
className: className,
ref: ref,
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(Ariakit.TabList, {
store: tabStore,
className: "components-tab-panel__tabs",
children: tabs.map(tab => {
return /*#__PURE__*/(0, _jsxRuntime.jsx)(Ariakit.Tab, {
id: prependInstanceId(tab.name),
className: (0, _clsx.default)('components-tab-panel__tabs-item', tab.className, {
[activeClass]: tab.name === selectedTabName
}),
disabled: tab.disabled,
"aria-controls": `${prependInstanceId(tab.name)}-view`,
render: /*#__PURE__*/(0, _jsxRuntime.jsx)(_button.default, {
__next40pxDefaultSize: true,
icon: tab.icon,
label: tab.icon && tab.title,
showTooltip: !!tab.icon
}),
children: !tab.icon && tab.title
}, tab.name);
})
}), selectedTab && /*#__PURE__*/(0, _jsxRuntime.jsx)(Ariakit.TabPanel, {
id: `${prependInstanceId(selectedTab.name)}-view`,
store: tabStore,
tabId: prependInstanceId(selectedTab.name),
className: "components-tab-panel__tab-content",
children: children(selectedTab)
})]
});
};
const TabPanel = exports.TabPanel = (0, _element.forwardRef)(UnforwardedTabPanel);
var _default = exports.default = TabPanel;
//# sourceMappingURL=index.js.map