-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
feat: export TabPanel #6896
feat: export TabPanel #6896
Changes from all commits
73a0519
4ac5b19
6d456b5
316f4a5
7d1be88
83116ef
0a007a1
45d761a
bcdb95b
c6b3717
087ac23
c2aed65
9adf944
5472c30
1f2d078
fdf8652
5b91852
b773ae3
75a6efc
241696b
150687f
f8794af
110923a
955d4f1
aabcc6b
dc3f729
7881c58
8f202ae
fc9d945
2254a18
3fbc070
9f9c0b6
6b820bd
0bd052b
72bfa73
12a665b
01cb908
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* | ||
* Copyright 2024 Palantir Technologies, Inc. All rights reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
import classNames from "classnames"; | ||
import * as React from "react"; | ||
|
||
import { AbstractPureComponent, Classes, Utils } from "../../common"; | ||
|
||
import { type TabId, type TabProps } from "./tab"; | ||
import type { TabsProps } from "./tabs"; | ||
import { generateTabIds, type TabTitleProps } from "./tabTitle"; | ||
|
||
export interface TabPanelProps | ||
extends Pick<TabProps, "className" | "id" | "panel">, | ||
Pick<TabsProps, "renderActiveTabPanelOnly" | "selectedTabId">, | ||
Pick<TabTitleProps, "parentId"> { | ||
/** | ||
* Used for setting visibility. This `TabPanel` will be visibile when `selectedTabId === id`, with proper accessibility attributes set. | ||
*/ | ||
selectedTabId: TabId | undefined; | ||
} | ||
|
||
/** | ||
* Wraps the passed `panel`. | ||
*/ | ||
export class TabPanel extends AbstractPureComponent<TabPanelProps> { | ||
public render() { | ||
const { className, id, parentId, selectedTabId, panel, renderActiveTabPanelOnly } = this.props; | ||
|
||
const isSelected = id === selectedTabId; | ||
|
||
if (panel === undefined || (renderActiveTabPanelOnly && !isSelected)) { | ||
return undefined; | ||
} | ||
|
||
const { tabTitleId, tabPanelId } = generateTabIds(parentId, id); | ||
|
||
return ( | ||
<div | ||
aria-labelledby={tabTitleId} | ||
aria-hidden={!isSelected} | ||
className={classNames(Classes.TAB_PANEL, className)} | ||
id={tabPanelId} | ||
role="tabpanel" | ||
> | ||
{Utils.isFunction(panel) ? panel({ tabTitleId, tabPanelId }) : panel} | ||
</div> | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ import { | |
Switch, | ||
Tab, | ||
type TabId, | ||
TabPanel, | ||
evansjohnson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Tabs, | ||
TabsExpander, | ||
} from "@blueprintjs/core"; | ||
|
@@ -105,39 +106,11 @@ export class TabsExample extends React.PureComponent<ExampleProps, TabsExampleSt | |
</> | ||
); | ||
|
||
const NAVBAR_PARENT_ID = "navbar"; | ||
|
||
return ( | ||
<Example className="docs-tabs-example" options={options} {...this.props}> | ||
<H4>Tabs without panels, controlled mode</H4> | ||
<Switch checked={this.state.fill} label="Fill height" onChange={this.toggleFill} /> | ||
<Navbar> | ||
<Navbar.Group> | ||
<Navbar.Heading> | ||
Page: <strong>{this.state.navbarTabId}</strong> | ||
</Navbar.Heading> | ||
</Navbar.Group> | ||
<Navbar.Group align={Alignment.RIGHT}> | ||
<Tabs | ||
animate={this.state.animate} | ||
fill={this.state.fill} | ||
id="navbar" | ||
large={this.state.large} | ||
onChange={this.handleNavbarTabChange} | ||
selectedTabId={this.state.navbarTabId} | ||
> | ||
<Tab id="Home" title="Home" icon={this.state.showIcon ? "home" : undefined} /> | ||
<Tab id="Files" title="Files" icon={this.state.showIcon ? "folder-open" : undefined} /> | ||
<Tab | ||
id="Builds" | ||
title="Builds" | ||
icon={this.state.showIcon ? "build" : undefined} | ||
tagContent={this.state.showTags ? 4 : undefined} | ||
tagProps={{ round: this.state.useRoundTags }} | ||
/> | ||
</Tabs> | ||
</Navbar.Group> | ||
</Navbar> | ||
<Divider style={{ margin: "20px 0", width: "100%" }} /> | ||
<H4>Tabs with panels, uncontrolled mode</H4> | ||
<H4>Tabs with passed panels, uncontrolled mode</H4> | ||
<Switch checked={this.state.vertical} label="Use vertical tabs" onChange={this.toggleVertical} /> | ||
<Tabs | ||
animate={this.state.animate} | ||
|
@@ -160,6 +133,49 @@ export class TabsExample extends React.PureComponent<ExampleProps, TabsExampleSt | |
<TabsExpander /> | ||
<InputGroup fill={true} type="text" placeholder="Search..." /> | ||
</Tabs> | ||
<Divider style={{ margin: "20px 0", width: "100%" }} /> | ||
<H4>Tabs with separately rendered panels, controlled mode</H4> | ||
<Switch checked={this.state.fill} label="Fill height" onChange={this.toggleFill} /> | ||
<div className={Classes.SECTION}> | ||
<Navbar> | ||
<Navbar.Group> | ||
<Navbar.Heading> | ||
Page: <strong>{this.state.navbarTabId}</strong> | ||
</Navbar.Heading> | ||
</Navbar.Group> | ||
<Navbar.Group align={Alignment.RIGHT}> | ||
<Tabs | ||
animate={this.state.animate} | ||
fill={this.state.fill} | ||
id={NAVBAR_PARENT_ID} | ||
large={this.state.large} | ||
onChange={this.handleNavbarTabChange} | ||
selectedTabId={this.state.navbarTabId} | ||
> | ||
<Tab id="Home" title="Home" icon={this.state.showIcon ? "home" : undefined} /> | ||
<Tab id="Files" title="Files" icon={this.state.showIcon ? "folder-open" : undefined} /> | ||
<Tab | ||
id="Builds" | ||
title="Builds" | ||
icon={this.state.showIcon ? "build" : undefined} | ||
tagContent={this.state.showTags ? 4 : undefined} | ||
tagProps={{ round: this.state.useRoundTags }} | ||
/> | ||
</Tabs> | ||
</Navbar.Group> | ||
</Navbar> | ||
<TabPanel | ||
id={this.state.navbarTabId} | ||
selectedTabId={this.state.navbarTabId} | ||
Comment on lines
+168
to
+169
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. lol I guess I didn't see this coming where that's fine I can't think of an easy way to prevent this and maybe it is okay. if we ever actually see an accessibility issue with changing the id dynamically we can update the docs at that time but no need to go searching for if this would be an issue |
||
parentId={NAVBAR_PARENT_ID} | ||
panel={ | ||
<> | ||
<H4>Example panel: {this.state.navbarTabId}</H4> | ||
<p>The current panel is: "{this.state.navbarTabId}"</p> | ||
</> | ||
} | ||
/> | ||
</div> | ||
</Example> | ||
); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bingo, exactly!