Skip to content
This repository was archived by the owner on Mar 25, 2025. It is now read-only.

Commit b0dbc73

Browse files
lekoafboilund
authored andcommitted
feat(tabs)!: add tabs component
Add a new Tabs and VerticalTabs (plural) component and removes the Tab and VerticalTab components. I does not make sense to give the user the ability to use Tabs individually, so instead we created a wrapper component which takes the tabs as options instead. This will also make our PRC => Fluent conversion easier because Fluent has a wrapper component that handles all the clicking and switching logic. BREAKING CHANGE: replaces Tab and VerticalTab components with Tabs and VerticalTabs components.
1 parent 1e92754 commit b0dbc73

File tree

4 files changed

+86
-63
lines changed

4 files changed

+86
-63
lines changed

packages/core/src/Tab/index.tsx

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -326,11 +326,19 @@ export interface TabProps<T> extends InternalTabBaseProps<T> {
326326
readonly markerOffset?: HorizontalTabMarkerOffset
327327
}
328328

329-
export function Tab<T>({
330-
markerOffset = 'bottom',
331-
...props
332-
}: TabProps<T>): JSX.Element {
333-
return <InternalTab<T> {...props} markerOffset={markerOffset} />
329+
export function Tabs<T>({
330+
tabs,
331+
}: {
332+
readonly tabs: ReadonlyArray<TabProps<T>>
333+
}): JSX.Element {
334+
return (
335+
<>
336+
{tabs.map((props, i) => {
337+
const markerOffset = props.markerOffset ?? 'bottom'
338+
return <InternalTab<T> key={i} {...props} markerOffset={markerOffset} />
339+
})}
340+
</>
341+
)
334342
}
335343

336344
/**
@@ -340,9 +348,17 @@ export interface VerticalTabProps<T> extends InternalTabBaseProps<T> {
340348
readonly markerOffset?: VerticalTabMarkerOffset
341349
}
342350

343-
export function VerticalTab<T>({
344-
markerOffset = 'right',
345-
...props
346-
}: VerticalTabProps<T>): JSX.Element {
347-
return <InternalTab<T> {...props} markerOffset={markerOffset} />
351+
export function VerticalTabs<T>({
352+
tabs,
353+
}: {
354+
readonly tabs: ReadonlyArray<VerticalTabProps<T>>
355+
}): JSX.Element {
356+
return (
357+
<>
358+
{tabs.map((props, i) => {
359+
const markerOffset = props.markerOffset ?? 'right'
360+
return <InternalTab<T> key={i} {...props} markerOffset={markerOffset} />
361+
})}
362+
</>
363+
)
348364
}

packages/docs/src/mdx/coreComponents/Tab.mdx

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
export const meta = {
2-
name: 'Tab',
3-
route: '/components/tab',
2+
name: 'Tabs',
3+
route: '/components/tabs',
44
menu: 'Components',
55
}
66

77
import styled from 'styled-components'
8-
import { useState } from 'react'
8+
import { useState, useMemo } from 'react'
99
import {
10-
Tab,
11-
VerticalTab,
12-
TabBase,
1310
Typography,
1411
Paper,
12+
Tabs,
13+
VerticalTabs,
1514
} from 'practical-react-components-core'
1615
import {
1716
HomeIcon,
@@ -98,21 +97,31 @@ export const TabPaper = styled(Paper)`
9897
export const DemoComponent = ({}) => {
9998
const [selectedHTab, setSelectedHTab] = useState('1')
10099
const [selectedVTab, setSelectedVTab] = useState('1')
100+
const hTabs = useMemo(() => {
101+
return HTABS.map(tab => ({
102+
id: tab.id,
103+
label: tab.label,
104+
icon: tab.icon,
105+
selected: tab.id === selectedHTab,
106+
onSelect: setSelectedHTab,
107+
className: 'my-tab',
108+
}))
109+
}, [selectedHTab, setSelectedHTab])
110+
const vTabs = useMemo(() => {
111+
return HTABS.map(tab => ({
112+
id: tab.id,
113+
label: tab.label,
114+
icon: tab.icon,
115+
selected: tab.id === selectedVTab,
116+
onSelect: setSelectedVTab,
117+
className: 'my-tab',
118+
}))
119+
}, [selectedVTab, setSelectedVTab])
101120
return (
102121
<>
103122
<ExamplePaper space={true}>
104123
<HorizontalTabContainer>
105-
{HTABS.map(tab => (
106-
<Tab
107-
key={tab.id}
108-
id={tab.id}
109-
label={tab.label}
110-
icon={tab.icon}
111-
selected={tab.id === selectedHTab}
112-
onSelect={setSelectedHTab}
113-
className="my-tab"
114-
/>
115-
))}
124+
<Tabs tabs={hTabs} />
116125
</HorizontalTabContainer>
117126
<Container show={selectedHTab === '1'}>
118127
<TabPaper space={true}>
@@ -131,17 +140,7 @@ export const DemoComponent = ({}) => {
131140
<ExamplePaper space={true}>
132141
<VContainer>
133142
<VerticalTabContainer>
134-
{VTABS.map(tab => (
135-
<VerticalTab
136-
key={tab.id}
137-
id={tab.id}
138-
label={tab.label}
139-
icon={tab.icon}
140-
selected={tab.id === selectedVTab}
141-
onSelect={setSelectedVTab}
142-
disabled={tab.disabled}
143-
/>
144-
))}
143+
<VerticalTabs tabs={vTabs} />
145144
</VerticalTabContainer>
146145
<Container show={selectedVTab === '1'}>
147146
<TabPaper space={true}>
@@ -166,12 +165,20 @@ export const DemoComponent = ({}) => {
166165
## Basic usage
167166

168167
```typescript type="live"
169-
<Tab
170-
id="id1"
171-
label="Home"
172-
icon={HomeIcon}
173-
selected={true}
174-
onSelect={() => {}}
168+
<Tabs
169+
tabs={[
170+
{
171+
id: '1',
172+
label: 'Home',
173+
icon: HomeIcon,
174+
},
175+
].map(tab => ({
176+
id: tab.id,
177+
label: tab.label,
178+
icon: tab.icon,
179+
selected: tab.id === '1',
180+
onSelect: () => {},
181+
}))}
175182
/>
176183
```
177184

@@ -181,4 +188,4 @@ Tab forwards all unknown props to the base native `<div>` component. See
181188
[`<div>` on MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div) for more
182189
details on which additional props that are available.
183190

184-
<Props of="Tab" />
191+
<Props of="Tabs" />

packages/ui-tests/src/coreComponents/Tab.cypress.tsx

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import React, { useState } from 'react'
1+
import React, { useMemo, useState } from 'react'
22
import styled from 'styled-components'
3-
import { DeviceIcon } from 'practical-react-components-icons'
4-
import { Tab } from 'practical-react-components-core'
3+
import { Tabs } from 'practical-react-components-core'
54

65
export const meta = {
7-
name: 'Tab',
8-
route: '/components/tab',
6+
name: 'Tabs',
7+
route: '/components/tabs',
98
menu: '',
109
}
1110

@@ -25,7 +24,6 @@ const HTABS = [
2524
{
2625
id: '1',
2726
label: 'Large device',
28-
icon: DeviceIcon,
2927
},
3028
{
3129
id: '2',
@@ -36,20 +34,22 @@ const HTABS = [
3634
const Test = () => {
3735
const [selectedTab, setSelectedTab] = useState('none')
3836

37+
const hTabs = useMemo(() => {
38+
return HTABS.map(tab => {
39+
return {
40+
id: tab.id,
41+
label: tab.label,
42+
selected: tab.id === selectedTab,
43+
onSelect: setSelectedTab,
44+
'data-cy': `my-tab-${tab.id}`,
45+
}
46+
})
47+
}, [selectedTab, setSelectedTab])
48+
3949
return (
4050
<>
4151
<HorizontalTabContainer>
42-
{HTABS.map(tab => (
43-
<Tab
44-
key={tab.id}
45-
id={tab.id}
46-
label={tab.label}
47-
icon={tab.icon}
48-
selected={tab.id === selectedTab}
49-
onSelect={setSelectedTab}
50-
data-cy={`my-tab-${tab.id}`}
51-
/>
52-
))}
52+
<Tabs tabs={hTabs} />
5353
</HorizontalTabContainer>
5454
<Container data-cy="container1" show={selectedTab === '1'}>
5555
<p>Content 1</p>

packages/ui-tests/src/coreComponents/Tab.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ context('Tab', () => {
55
const tab2El = '[data-cy*=my-tab-2]'
66

77
before(() => {
8-
cy.visit('http://localhost:9009/#/components/tab')
8+
cy.visit('http://localhost:9009/#/components/tabs')
99
})
1010

1111
it('no tab selected, containers should not be visible', () => {

0 commit comments

Comments
 (0)