Skip to content

Commit

Permalink
[lab][TabPanel] Add keepMounted prop to match joy-ui (#41651)
Browse files Browse the repository at this point in the history
  • Loading branch information
ppaskaris-plooto authored Apr 3, 2024
1 parent 4fe9e2a commit 49fb397
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 9 deletions.
7 changes: 7 additions & 0 deletions docs/pages/material-ui/api/tab-panel.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"value": { "type": { "name": "string" }, "required": true },
"children": { "type": { "name": "node" } },
"classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } },
"keepMounted": { "type": { "name": "bool" }, "default": "false" },
"sx": {
"type": {
"name": "union",
Expand All @@ -14,6 +15,12 @@
"name": "TabPanel",
"imports": ["import TabPanel from '@mui/lab/TabPanel';", "import { TabPanel } from '@mui/lab';"],
"classes": [
{
"key": "hidden",
"className": "MuiTabPanel-hidden",
"description": "State class applied to the root `div` element if `hidden={true}`.",
"isGlobal": false
},
{
"key": "root",
"className": "MuiTabPanel-root",
Expand Down
10 changes: 9 additions & 1 deletion docs/translations/api-docs/tab-panel/tab-panel.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,20 @@
"propDescriptions": {
"children": { "description": "The content of the component." },
"classes": { "description": "Override or extend the styles applied to the component." },
"keepMounted": { "description": "Always keep the children in the DOM." },
"sx": {
"description": "The system prop that allows defining system overrides as well as additional CSS styles."
},
"value": {
"description": "The <code>value</code> of the corresponding <code>Tab</code>. Must use the index of the <code>Tab</code> when no <code>value</code> was passed to <code>Tab</code>."
}
},
"classDescriptions": { "root": { "description": "Styles applied to the root element." } }
"classDescriptions": {
"hidden": {
"description": "State class applied to {{nodeName}} if {{conditions}}.",
"nodeName": "the root <code>div</code> element",
"conditions": "<code>hidden={true}</code>"
},
"root": { "description": "Styles applied to the root element." }
}
}
5 changes: 5 additions & 0 deletions packages/mui-lab/src/TabPanel/TabPanel.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ export interface TabPanelProps extends StandardProps<React.HTMLAttributes<HTMLDi
* no `value` was passed to `Tab`.
*/
value: string;
/**
* Always keep the children in the DOM.
* @default false
*/
keepMounted?: boolean;
}

/**
Expand Down
13 changes: 9 additions & 4 deletions packages/mui-lab/src/TabPanel/TabPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import { getTabPanelUtilityClass } from './tabPanelClasses';
import { getPanelId, getTabId, useTabContext } from '../TabContext';

const useUtilityClasses = (ownerState) => {
const { classes } = ownerState;
const { classes, hidden } = ownerState;

const slots = {
root: ['root'],
root: ['root', hidden && 'hidden'],
};

return composeClasses(slots, getTabPanelUtilityClass, classes);
Expand All @@ -28,7 +28,7 @@ const TabPanelRoot = styled('div', {
const TabPanel = React.forwardRef(function TabPanel(inProps, ref) {
const props = useThemeProps({ props: inProps, name: 'MuiTabPanel' });

const { children, className, value, ...other } = props;
const { children, className, value, keepMounted = false, ...other } = props;

const ownerState = {
...props,
Expand All @@ -54,7 +54,7 @@ const TabPanel = React.forwardRef(function TabPanel(inProps, ref) {
ownerState={ownerState}
{...other}
>
{value === context.value && children}
{(keepMounted || value === context.value) && children}
</TabPanelRoot>
);
});
Expand All @@ -76,6 +76,11 @@ TabPanel.propTypes /* remove-proptypes */ = {
* @ignore
*/
className: PropTypes.string,
/**
* Always keep the children in the DOM.
* @default false
*/
keepMounted: PropTypes.bool,
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
Expand Down
22 changes: 19 additions & 3 deletions packages/mui-lab/src/TabPanel/TabPanel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,17 @@ describe('<TabPanel />', () => {
],
}));

it('renders a [role="tabpanel"]', () => {
const { getByTestId } = render(
it('renders a [role="tabpanel"] and mounts children', () => {
const { getByTestId, queryByTestId } = render(
<TabContext value="0">
<TabPanel data-testid="tabpanel" value="0" />
<TabPanel data-testid="tabpanel" value="0">
<div data-testid="child" />
</TabPanel>
</TabContext>,
);

expect(getByTestId('tabpanel')).to.have.attribute('role', 'tabpanel');
expect(queryByTestId('child')).to.not.equal(null);
});

it('is [hidden] when TabPanel#value !== TabContext#value and does not mount children', () => {
Expand All @@ -47,6 +50,19 @@ describe('<TabPanel />', () => {
expect(queryByTestId('child')).to.equal(null);
});

it('is [hidden] when TabPanel#value !== TabContext#value but does mount children when keepMounted', () => {
const { getByTestId, queryByTestId } = render(
<TabContext value="1">
<TabPanel data-testid="tabpanel" value="0" keepMounted>
<div data-testid="child" />
</TabPanel>
</TabContext>,
);

expect(getByTestId('tabpanel')).to.have.property('hidden', true);
expect(queryByTestId('child')).to.not.equal(null);
});

it('is accessible when TabPanel#value === TabContext#value', () => {
const { getByTestId } = render(
<TabContext value="0">
Expand Down
4 changes: 3 additions & 1 deletion packages/mui-lab/src/TabPanel/tabPanelClasses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import generateUtilityClasses from '@mui/utils/generateUtilityClasses';
export interface TabPanelClasses {
/** Styles applied to the root element. */
root: string;
/** State class applied to the root `div` element if `hidden={true}`. */
hidden: string;
}

export type TabPanelClassKey = keyof TabPanelClasses;
Expand All @@ -12,6 +14,6 @@ export function getTabPanelUtilityClass(slot: string): string {
return generateUtilityClass('MuiTabPanel', slot);
}

const tabPanelClasses: TabPanelClasses = generateUtilityClasses('MuiTabPanel', ['root']);
const tabPanelClasses: TabPanelClasses = generateUtilityClasses('MuiTabPanel', ['root', 'hidden']);

export default tabPanelClasses;

0 comments on commit 49fb397

Please sign in to comment.