Skip to content

Commit

Permalink
Alternate value-required approach
Browse files Browse the repository at this point in the history
  • Loading branch information
eps1lon committed May 6, 2020
1 parent f120754 commit 1858844
Show file tree
Hide file tree
Showing 26 changed files with 146 additions and 266 deletions.
2 changes: 1 addition & 1 deletion docs/pages/api-docs/tab-context.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ You can learn more about the difference by [reading this guide](/guides/minimizi
| Name | Type | Default | Description |
|:-----|:-----|:--------|:------------|
| <span class="prop-name">children</span> | <span class="prop-type">node</span> | | The content of the component. |
| <span class="prop-name required">value&nbsp;*</span> | <span class="prop-type">any</span> | | The value of the currently selected `Tab`. If you don't want any selected `Tab`, you can set this property to `false`. |
| <span class="prop-name required">value&nbsp;*</span> | <span class="prop-type">string</span> | | The value of the currently selected `Tab`. |

The component cannot hold a ref.

Expand Down
9 changes: 7 additions & 2 deletions docs/pages/api-docs/tab-list.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ You can learn more about the difference by [reading this guide](/guides/minimizi
|:-----|:-----|:--------|:------------|
| <span class="prop-name">children</span> | <span class="prop-type">Array&lt;element&gt;</span> | | |

The component cannot hold a ref.
The `ref` is forwarded to the root element.

Any other props supplied will be provided to the root element (native element).
Any other props supplied will be provided to the root element ([Tabs](/api/tabs/)).

## Inheritance

The props of the [Tabs](/api/tabs/) component are also available.
You can take advantage of this behavior to [target nested components](/guides/api/#spread).

5 changes: 2 additions & 3 deletions docs/pages/api-docs/tab-panel.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,9 @@ The `MuiTabPanel` name can be used for providing [default props](/customization/

| Name | Type | Default | Description |
|:-----|:-----|:--------|:------------|
| <span class="prop-name required">activeValue&nbsp;*</span> | <span class="prop-type">any</span> | | |
| <span class="prop-name">children</span> | <span class="prop-type">node</span> | | |
| <span class="prop-name">children</span> | <span class="prop-type">node</span> | | The content of the component. |
| <span class="prop-name">classes</span> | <span class="prop-type">object</span> | | Override or extend the styles applied to the component. See [CSS API](#css) below for more details. |
| <span class="prop-name required">value&nbsp;*</span> | <span class="prop-type">any</span> | | |
| <span class="prop-name required">value&nbsp;*</span> | <span class="prop-type">string</span> | | The `value` of the corresponding `Tab`. Must use the index of the `Tab` when no `value` was passed to `Tab`. |

The `ref` is forwarded to the root element.

Expand Down
15 changes: 0 additions & 15 deletions docs/pages/api-docs/tab-panels.js

This file was deleted.

34 changes: 0 additions & 34 deletions docs/pages/api-docs/tab-panels.md

This file was deleted.

17 changes: 7 additions & 10 deletions docs/src/pages/components/tabs/LabTabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import Tab from '@material-ui/core/Tab';
import TabContext from '@material-ui/lab/TabContext';
import TabList from '@material-ui/lab/TabList';
import TabPanel from '@material-ui/lab/TabPanel';
import TabPanels from '@material-ui/lab/TabPanels';

const useStyles = makeStyles((theme) => ({
root: {
Expand All @@ -16,7 +15,7 @@ const useStyles = makeStyles((theme) => ({

export default function LabTabs() {
const classes = useStyles();
const [value, setValue] = React.useState(0);
const [value, setValue] = React.useState('1');

const handleChange = (event, newValue) => {
setValue(newValue);
Expand All @@ -27,16 +26,14 @@ export default function LabTabs() {
<TabContext value={value}>
<AppBar position="static">
<TabList onChange={handleChange} aria-label="simple tabs example">
<Tab label="Item One" />
<Tab label="Item Two" />
<Tab label="Item Three" />
<Tab label="Item One" value="1" />
<Tab label="Item Two" value="2" />
<Tab label="Item Three" value="3" />
</TabList>
</AppBar>
<TabPanels>
<TabPanel>Item One</TabPanel>
<TabPanel>Item Two</TabPanel>
<TabPanel>Item Three</TabPanel>
</TabPanels>
<TabPanel value="1">Item One</TabPanel>
<TabPanel value="2">Item Two</TabPanel>
<TabPanel value="3">Item Three</TabPanel>
</TabContext>
</div>
);
Expand Down
19 changes: 8 additions & 11 deletions docs/src/pages/components/tabs/LabTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import Tab from '@material-ui/core/Tab';
import TabContext from '@material-ui/lab/TabContext';
import TabList from '@material-ui/lab/TabList';
import TabPanel from '@material-ui/lab/TabPanel';
import TabPanels from '@material-ui/lab/TabPanels';

const useStyles = makeStyles((theme: Theme) => ({
root: {
Expand All @@ -16,9 +15,9 @@ const useStyles = makeStyles((theme: Theme) => ({

export default function LabTabs() {
const classes = useStyles();
const [value, setValue] = React.useState(0);
const [value, setValue] = React.useState('1');

const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
const handleChange = (event: React.ChangeEvent<{}>, newValue: string) => {
setValue(newValue);
};

Expand All @@ -27,16 +26,14 @@ export default function LabTabs() {
<TabContext value={value}>
<AppBar position="static">
<TabList onChange={handleChange} aria-label="simple tabs example">
<Tab label="Item One" />
<Tab label="Item Two" />
<Tab label="Item Three" />
<Tab label="Item One" value="1" />
<Tab label="Item Two" value="2" />
<Tab label="Item Three" value="3" />
</TabList>
</AppBar>
<TabPanels>
<TabPanel>Item One</TabPanel>
<TabPanel>Item Two</TabPanel>
<TabPanel>Item Three</TabPanel>
</TabPanels>
<TabPanel value="1">Item One</TabPanel>
<TabPanel value="2">Item Two</TabPanel>
<TabPanel value="3">Item Three</TabPanel>
</TabContext>
</div>
);
Expand Down
10 changes: 5 additions & 5 deletions packages/material-ui-lab/src/TabContext/TabContext.d.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import * as React from 'react';

export interface TabContextValue {
panelPrefix: string;
tabPrefix: string;
value: unknown;
idPrefix: string;
value: string;
}

export interface TabContextProps {
children?: React.ReactNode;
/**
* The value of the currently selected `Tab`.
* If you don't want any selected `Tab`, you can set this property to `false`.
*/
value: unknown;
value: string;
}
/**
*
Expand All @@ -22,3 +20,5 @@ export interface TabContextProps {
*/
export default function TabContext(props: TabContextProps): JSX.Element;
export function useTabContext(): TabContextValue | null;
export function getPanelId(context: TabContextValue, tabValue: string): string;
export function getTabId(context: TabContextValue, tabValue: string): string;
34 changes: 27 additions & 7 deletions packages/material-ui-lab/src/TabContext/TabContext.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';

/**
* @type {React.Context<{ idPrefix: string; value: string } | null>}
*/
const Context = React.createContext(null);
if (process.env.NODE_ENV !== 'production') {
Context.displayName = 'TabContext';
Expand All @@ -9,19 +12,18 @@ if (process.env.NODE_ENV !== 'production') {
function useUniquePrefix() {
const [id, setId] = React.useState(null);
React.useEffect(() => {
setId(`mui-${Math.round(Math.random() * 1e5)}`);
setId(`mui-p-${Math.round(Math.random() * 1e5)}`);
}, []);
return id;
}

export default function TabContext(props) {
const { children, value } = props;
const panelPrefix = useUniquePrefix();
const tabPrefix = useUniquePrefix();
const idPrefix = useUniquePrefix();

const context = React.useMemo(() => {
return { tabPrefix, panelPrefix, value };
}, [panelPrefix, tabPrefix, value]);
return { idPrefix, value };
}, [idPrefix, value]);

return <Context.Provider value={context}>{children}</Context.Provider>;
}
Expand All @@ -37,11 +39,29 @@ TabContext.propTypes = {
children: PropTypes.node,
/**
* The value of the currently selected `Tab`.
* If you don't want any selected `Tab`, you can set this property to `false`.
*/
value: PropTypes.any.isRequired,
value: PropTypes.string.isRequired,
};

/**
* @returns {unknown}
*/
export function useTabContext() {
return React.useContext(Context);
}

export function getPanelId(context, value) {
const { idPrefix } = context;
if (idPrefix === null) {
return null;
}
return `${context.idPrefix}-P-${value}`;
}

export function getTabId(context, value) {
const { idPrefix } = context;
if (idPrefix === null) {
return null;
}
return `${context.idPrefix}-T-${value}`;
}
44 changes: 22 additions & 22 deletions packages/material-ui-lab/src/TabContext/TabContext.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as React from 'react';
import ReactDOMServer from 'react-dom/server';
import { expect } from 'chai';
import { createClientRender } from 'test/utils/createClientRender';
import TabContext, { useTabContext } from './TabContext';
import TabContext, { getPanelId, getTabId, useTabContext } from './TabContext';

describe('<TabContext />', () => {
const render = createClientRender();
Expand All @@ -19,21 +19,21 @@ describe('<TabContext />', () => {
expect(value).to.equal(null);
});

it('provides tab and panel prefixes for IDREFs and the active value', () => {
function Tabs() {
const { panelPrefix, tabPrefix, value } = useTabContext();
it('provides an id prefix for IDREFs and the active value', () => {
function Tabs({ value }) {
const context = useTabContext();
return (
<React.Fragment>
<div data-testid="active-value" data-value={value} />
<div role="tab" id={tabPrefix} />
<div role="tabpanel" id={panelPrefix} />
<div data-testid="active-value" data-value={context.value} />
<div role="tab" id={getTabId(context, value)} />
<div role="tabpanel" id={getPanelId(context, value)} />
</React.Fragment>
);
}

const { getByRole, getByTestId } = render(
<TabContext value={0}>
<Tabs />
<TabContext value="0">
<Tabs value="0" />
</TabContext>,
);

Expand All @@ -46,20 +46,20 @@ describe('<TabContext />', () => {
});

it('provides undefined tab and panel prefixes and the active value when ssr', () => {
function Tabs() {
const { panelPrefix, tabPrefix, value } = useTabContext();
function Tabs({ value }) {
const context = useTabContext();
return (
<React.Fragment>
<div data-testid="active-value" data-value={value} />
<div role="tab" id={tabPrefix} />
<div role="tabpanel" id={panelPrefix} />
<div data-testid="active-value" data-value={context.value} />
<div role="tab" id={getTabId(context, value)} />
<div role="tabpanel" id={getPanelId(context, value)} />
</React.Fragment>
);
}

const markup = ReactDOMServer.renderToStaticMarkup(
<TabContext value={0}>
<Tabs />
<TabContext value="0">
<Tabs value="0" />
</TabContext>,
);

Expand All @@ -69,18 +69,18 @@ describe('<TabContext />', () => {
});

it('hydrates tab and tabpanel prefixes', () => {
function Tabs() {
const { panelPrefix, tabPrefix } = useTabContext();
function Tabs({ value }) {
const context = useTabContext();
return (
<React.Fragment>
<div role="tab" id={tabPrefix} />
<div role="tabpanel" id={panelPrefix} />
<div role="tab" id={getTabId(context, value)} />
<div role="tabpanel" id={getPanelId(context, value)} />
</React.Fragment>
);
}
const reactElement = (
<TabContext value={0}>
<Tabs />
<TabContext value="0">
<Tabs value="0" />
</TabContext>
);
const markup = ReactDOMServer.renderToString(reactElement);
Expand Down
3 changes: 2 additions & 1 deletion packages/material-ui-lab/src/TabContext/index.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default, useTabContext } from './TabContext';
export { default } from './TabContext';
export * from './TabContext';
3 changes: 2 additions & 1 deletion packages/material-ui-lab/src/TabContext/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default, useTabContext } from './TabContext';
export { default } from './TabContext';
export * from './TabContext';
1 change: 1 addition & 0 deletions packages/material-ui-lab/src/TabList/TabList.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface TabListTypeMap<
* API:
*
* - [TabList API](https://material-ui.com/api/tab-list/)
* - inherits [Tabs API](https://material-ui.com/api/tabs/)
*/
declare const TabList: OverridableComponent<TabListTypeMap>;

Expand Down

0 comments on commit 1858844

Please sign in to comment.