Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tabs2 ➡️ Tabs #1900

Merged
merged 7 commits into from
Dec 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions packages/core/src/common/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,6 @@ export const SLIDER_ZERO_STEP = ns + ` <Slider> stepSize must be greater than ze
export const SLIDER_ZERO_LABEL_STEP = ns + ` <Slider> labelStepSize must be greater than zero.`;
export const RANGESLIDER_NULL_VALUE = ns + ` <RangeSlider> value prop must be an array of two non-null numbers.`;

export const TABS_FIRST_CHILD = ns + ` First child of <Tabs> component must be a <TabList>`;
export const TABS_MISMATCH = ns + ` Number of <Tab> components must equal number of <TabPanel> components`;
export const TABS_WARN_DEPRECATED =
deprec +
` <Tabs> is deprecated since v1.11.0; consider upgrading to <Tabs2>.` +
" https://blueprintjs.com/#components.tabs.js";

export const TOASTER_WARN_INLINE = ns + ` Toaster.create() ignores inline prop as it always creates a new element.`;
export const TOASTER_WARN_LEFT_RIGHT = ns + ` Toaster does not support LEFT or RIGHT positions.`;

Expand Down
1 change: 0 additions & 1 deletion packages/core/src/components/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
@page sliders
@page table
@page tabs
@page tabs2
@page tag
@page tag-input
@page text
Expand Down
4 changes: 0 additions & 4 deletions packages/core/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,6 @@ export * from "./spinner/spinner";
export * from "./spinner/svgSpinner";
export * from "./tabs/tab";
export * from "./tabs/tabs";
export * from "./tabs/tabList";
export * from "./tabs/tabPanel";
export * from "./tabs2/tab2";
export * from "./tabs2/tabs2";
export * from "./tag/tag";
export * from "./tag-input/tagInput";
export * from "./toast/toast";
Expand Down
48 changes: 22 additions & 26 deletions packages/core/src/components/tabs/tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,54 +10,50 @@ import * as React from "react";
import * as Classes from "../../common/classes";
import { IProps } from "../../common/props";

export type TabId = string | number;

export interface ITabProps extends IProps {
/**
* Element ID.
* @internal
* Whether the tab is disabled.
* @default false
*/
id?: string;
disabled?: boolean;

/**
* Whether the tab is disabled.
* @default false
* Unique identifier used to control which tab is selected
* and to generate ARIA attributes for accessibility.
*/
isDisabled?: boolean;
id: TabId;

/**
* Whether the tab is currently selected.
* @internal
* Panel content, rendered by the parent `Tabs` when this tab is active.
* If omitted, no panel will be rendered for this tab.
*/
isSelected?: boolean;
panel?: JSX.Element;

/**
* The ID of the tab panel which this tab corresponds to.
* @internal
* Content of tab title element, rendered in a list above the active panel.
* Can also be set via React `children`.
*/
panelId?: string;
title?: string | JSX.Element;
}

export class Tab extends React.PureComponent<ITabProps, {}> {
public static defaultProps: ITabProps = {
isDisabled: false,
isSelected: false,
disabled: false,
id: undefined,
};

public static displayName = "Blueprint.Tab";

// this component is never rendered directly; see Tabs#renderTabPanel()
/* istanbul ignore next */
public render() {
const { className, panel } = this.props;
return (
<li
aria-controls={this.props.panelId}
aria-disabled={this.props.isDisabled}
aria-expanded={this.props.isSelected}
aria-selected={this.props.isSelected}
className={classNames(Classes.TAB, this.props.className)}
id={this.props.id}
role="tab"
tabIndex={this.props.isDisabled ? null : 0}
>
{this.props.children}
</li>
<div className={classNames(Classes.TAB_PANEL, className)} role="tablist">
{panel}
</div>
);
}
}
Expand Down
57 changes: 0 additions & 57 deletions packages/core/src/components/tabs/tabList.tsx

This file was deleted.

43 changes: 0 additions & 43 deletions packages/core/src/components/tabs/tabPanel.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import * as classNames from "classnames";
import * as React from "react";

import * as Classes from "../../common/classes";
import { ITab2Props, TabId } from "./tab2";
import { ITabProps, TabId } from "./tab";

export interface ITabTitleProps extends ITab2Props {
export interface ITabTitleProps extends ITabProps {
/** Handler invoked when this tab is clicked. */
onClick: (id: TabId, event: React.MouseEvent<HTMLElement>) => void;

Expand Down
125 changes: 34 additions & 91 deletions packages/core/src/components/tabs/tabs.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
@# Tabs

<div class="pt-callout pt-intent-danger pt-icon-error">
<h5>The `Tabs` JavaScript API is deprecated since v1.11.0</h5>
The following `Tabs` React components been deprecated in v1.11.0 favor of the [simpler and more flexible
`Tabs2` API](#core/components/tabs2). `Tabs2` will replace `Tabs` in version 2.0. The CSS API has not been changed.
</div>

@## CSS API

In addition to the [JavaScript API](#core/components/tabs2.javascript-api), Blueprint also offers tab styles with the
In addition to the [JavaScript API](#core/components/tabs.javascript-api), Blueprint also offers tab styles with the
class `pt-tabs`. You should add the proper accessibility attributes (`role`, `aria-selected`, and
`aria-hidden`) if you choose to implement tabs with CSS.

Expand All @@ -18,106 +12,55 @@ JavaScript component does this by default).

@css pt-tabs

@## Deprecated JavaScript API

<div class="pt-callout pt-intent-danger pt-icon-error">
These components are deprecated since v1.11.0. Please use the [`Tabs2` API](#core/components/tabs2) instead.
</div>
@## JavaScript API

The `Tabs`, `TabList`, `Tab`, and `TabPanel` components are available in the __@blueprintjs/core__
The `Tabs` and `Tab` components are available in the __@blueprintjs/core__
package. Make sure to review the [general usage docs for JS components](#blueprint.usage).

Four components are necessary to render tabs: `Tabs`, `TabList`, `Tab`, and `TabPanel`.

For performance reasons, only the currently active `TabPanel` is rendered into the DOM. When the
user switches tabs, data stored in the DOM is lost. This is not an issue in React applications
because of how the library manages the virtual DOM for you.
Tab selection is managed by `id`, much like the HTML `<select>` element respects `<option value>`. This is more reliable than using a numeric index (it's also deterministic), and
does not require translating between numbers and tab names. It does, however, require that
every `Tab` have a locally unique `id` prop.

@### Sample usage
Arbitrary elements are supported in the tab list, and order is respected. Yes, you can even
insert things _between_ `Tab`s.

```tsx
<Tabs>
<TabList>
<Tab>First tab</Tab>
<Tab>Second tab</Tab>
<Tab>Third tab</Tab>
<Tab isDisabled={true}>Fourth tab</Tab>
</TabList>
<TabPanel>
First panel
</TabPanel>
<TabPanel>
Second panel
</TabPanel>
<TabPanel>
Third panel
</TabPanel>
<TabPanel>
Fourth panel
</TabPanel>
import { Tab, Tabs } from "@blueprintjs/core";

<Tabs id="TabsExample" onChange={this.handleTabChange} selectedTabId="rx">
<Tab id="ng" title="Angular" panel={<AngularPanel />} />
<Tab id="mb" title="Ember" panel={<EmberPanel />} />
<Tab id="rx" title="React" panel={<ReactPanel />} />
<Tab id="bb" disabled title="Backbone" panel={<BackbonePanel />} />
<Tabs.Expander />
<input className="pt-input" type="text" placeholder="Search..." />
</Tabs>
```

Every component accepts a `className` prop that can be used to set additional classes on the
component's root element. You can get larger tabs by using the `pt-large` class on `TabList`.

You can use the `Tabs` API in controlled or uncontrolled mode. The props you supply will differ
between these approaches.

@reactExample TabsExample

@### Tabs props
@### Tabs

<div class="pt-callout pt-intent-danger pt-icon-error">
This component is deprecated since v1.11.0. Please use the [`Tabs2` API](#core/components/tabs2) instead.
</div>
`Tabs` is the top-level component responsible for rendering the tab list and coordinating selection.
It can be used in controlled mode by providing `selectedTabId` and `onChange` props, or in
uncontrolled mode by optionally providing `defaultSelectedTabId` and `onChange`.

@interface ITabsProps
Children of the `Tabs` are rendered in order in the tab list, which is a flex container.
`Tab` children are managed by the component; clicking one will change selection. Arbitrary other
children are simply rendered in order; interactions are your responsibility.

@### Tab props
Insert a `<Tabs.Expander />` between any two children to right-align all subsequent children (or bottom-align when `vertical`).

<div class="pt-callout pt-intent-danger pt-icon-error">
This component is deprecated since v1.11.0. Please use the [`Tabs2` API](#core/components/tabs2) instead.
</div>
@interface ITabsProps

@interface ITabProps
@### Tab

@### Usage with React Router
`Tab` is a minimal wrapper with no functionality of its own&mdash;it is managed entirely by its
parent `Tabs` wrapper. Tab title text can be set either via `title` prop or via React children
(for more complex content).

Often, you'll want to link tab navigation to overall app navigation, including updating the URL.
[react-router](https://github.com/reactjs/react-router) is a commonly-used library for React
applications. Here's how you might configure tabs to work with it:
The associated tab `panel` will be visible when the `Tab` is active. Omitting `panel` is perfectly
safe and allows you to control exactly where the panel appears in the DOM (by rendering it yourself
as needed).

```tsx
import { render } from "react-dom";
import { Router, Route } from "react-router";
import { Tabs, TabList, Tab, TabPanel } from "@blueprintjs/core";

const App = () => { ... };

// keys are necessary in JSX.Element lists to keep React happy
const contents = [
<TabList key={0}>
<Tab>Home</Tab>
<Tab>Projects</Tab>
</TabList>,
<TabPanel key={1}>
home things
</TabPanel>,
<TabPanel key={2}>
projects things
</TabPanel>,
];

// using SFCs from TS 1.8, but easy to do without them
export const Home = () => <Tabs selectedTabIndex={0}>{contents}</Tabs>;
export const Projects = () => <Tabs selectedTabIndex={1}>{contents}</Tabs>;

render(
<Router path="/" component={App}>
<Route path="home" component={Home}/>
<Route path="projects" component={Projects}/>
</Router>,
document.querySelector("#app")
);
```
@interface ITabProps
Loading