File tree 6 files changed +210
-0
lines changed
6 files changed +210
-0
lines changed Original file line number Diff line number Diff line change
1
+ import React , { FC , useState } from 'react' ;
2
+ import { Box , BoxProps } from 'rebass' ;
3
+ import * as S from './styles' ;
4
+ import Tab , { Props as EmbeddedTabItem } from './Tab' ;
5
+
6
+ export interface Props extends Omit < BoxProps , 'css' > {
7
+ tabs : EmbeddedTabItem [ ] ;
8
+ initialTab ?: number ;
9
+ onTabChange ?: ( tabIndex : number ) => void ;
10
+ }
11
+
12
+ const EmbeddedTabs : FC < Props > = ( {
13
+ tabs,
14
+ onTabChange,
15
+ initialTab = 0 ,
16
+ sx = { } ,
17
+ ...boxProps
18
+ } : Props ) => {
19
+ const [ activeIndex , setActiveIndex ] = useState ( initialTab ) ;
20
+
21
+ const handleTabClick = ( newIndex : number ) => {
22
+ setActiveIndex ( newIndex ) ;
23
+
24
+ if ( onTabChange ) {
25
+ onTabChange ( newIndex ) ;
26
+ }
27
+ } ;
28
+
29
+ return (
30
+ < Box sx = { { ...S . tabsList , ...sx } } { ...boxProps } >
31
+ { tabs . map ( ( { title, onClick : onTabClick , ...tabProps } , index ) => (
32
+ < Tab
33
+ key = { title }
34
+ title = { title }
35
+ active = { index === activeIndex }
36
+ onClick = { ( ) => {
37
+ if ( onTabClick ) {
38
+ onTabClick ( ) ;
39
+ }
40
+
41
+ handleTabClick ( index ) ;
42
+ } }
43
+ { ...tabProps }
44
+ />
45
+ ) ) }
46
+ { /* This box is needed to draw the horizontal line up to the full width, it's a stylistic decision */ }
47
+ < Box tabIndex = { - 1 } sx = { S . tabsLineEnding } />
48
+ </ Box >
49
+ ) ;
50
+ } ;
51
+
52
+ export default EmbeddedTabs ;
Original file line number Diff line number Diff line change
1
+ import * as R from 'ramda' ;
2
+ import React , { FC } from 'react' ;
3
+ import { Box , SxStyleProp } from 'rebass' ;
4
+ import Label from '../label' ;
5
+ import * as S from './styles' ;
6
+
7
+ export interface Props {
8
+ title : string ;
9
+ active ?: boolean ;
10
+ onClick ?: ( ) => any ;
11
+ disabled ?: boolean ;
12
+ }
13
+
14
+ const getStyles = ( { active, disabled } : Props ) =>
15
+ ( {
16
+ ...S . tab ,
17
+ ...( active ? S . activeTab : { } ) ,
18
+ ...( disabled ? S . disabledTab : { } ) ,
19
+ } as SxStyleProp ) ;
20
+
21
+ const Tab : FC < Props > = ( props ) => {
22
+ const propagatedProps = R . pick ( [ 'disabled' , 'onClick' ] , props ) ;
23
+
24
+ return (
25
+ < Box sx = { getStyles ( props ) } { ...propagatedProps } >
26
+ < Label pb = "1px" > { props . title } </ Label >
27
+ </ Box >
28
+ ) ;
29
+ } ;
30
+
31
+ export default Tab ;
Original file line number Diff line number Diff line change
1
+ import { Meta , Story } from '@storybook/react/types-6-0' ;
2
+ import React , { useState } from 'react' ;
3
+ import { Box } from 'rebass' ;
4
+ import Labeling from '../typography/labeling' ;
5
+ import EmbeddedTabs , { Props } from './EmbeddedTabs' ;
6
+
7
+ export default {
8
+ title : 'Quartz/EmbeddedTabs' ,
9
+ component : EmbeddedTabs ,
10
+ } as Meta ;
11
+
12
+ const argTypes = {
13
+ tabs : {
14
+ required : true ,
15
+ description : 'A list of tab items.' ,
16
+ } ,
17
+ initialTab : {
18
+ required : false ,
19
+ description : 'The initial tab to be selected.' ,
20
+ default : 0 ,
21
+ } ,
22
+ onTabChange : {
23
+ description : 'Callback to be called when a tab is selected.' ,
24
+ required : false
25
+ } ,
26
+ } ;
27
+
28
+ const tabs = [
29
+ {
30
+ title : 'Validation Reports' ,
31
+ } ,
32
+ {
33
+ title : 'Results' ,
34
+ } ,
35
+ {
36
+ title : 'Statistics' ,
37
+ } ,
38
+ {
39
+ title : 'And a disabled tab' ,
40
+ disabled : true ,
41
+ } ,
42
+ ] ;
43
+
44
+ const Template : Story < Props > = ( props ) => {
45
+ const [ activeTab , setActiveTab ] = useState ( props . initialTab ?? 0 ) ;
46
+
47
+ return (
48
+ < Box width = "700px" >
49
+ < EmbeddedTabs { ...props } onTabChange = { setActiveTab } />
50
+ < Box mt = { 3 } >
51
+ < Labeling bold > Active tab: { tabs [ activeTab ] . title } </ Labeling >
52
+ </ Box >
53
+ </ Box >
54
+ ) ;
55
+ } ;
56
+
57
+ export const Default = Template . bind ( { } ) ;
58
+
59
+ Default . args = {
60
+ tabs,
61
+ } ;
62
+
63
+ Default . argTypes = argTypes ;
Original file line number Diff line number Diff line change
1
+ export { default } from './EmbeddedTabs' ;
2
+ export type { Props as EmbeddedTabsProps } from './EmbeddedTabs' ;
3
+ export type { Props as EmbeddedTabsItem } from './Tab' ;
Original file line number Diff line number Diff line change
1
+ import { SxStyleProp } from 'rebass' ;
2
+ import * as R from 'ramda' ;
3
+
4
+ export const tabsList = {
5
+ /* It is `inline-table` to have the ability to collapse borders */
6
+ display : 'inline-table' ,
7
+ verticalAlign : 'middle' ,
8
+ borderCollapse : 'collapse' ,
9
+
10
+ '> div:not(:last-child)' : {
11
+ marginRight : '20px'
12
+ }
13
+ } as SxStyleProp ;
14
+
15
+ /* this one is needed to have the line that spans across the rest of the width. Couldn't find any other solution. */
16
+ export const tabsLineEnding = {
17
+ display : 'table-cell' ,
18
+ width : '100%' ,
19
+ borderBottom : '1px solid' ,
20
+ borderBottomColor : 'gray' ,
21
+ pointerEvents : 'none' ,
22
+ } ;
23
+
24
+ export const activeTab = {
25
+ backgroundColor : 'white' ,
26
+ borderBottomColor : 'grayShade3' ,
27
+ } ;
28
+
29
+ export const disabledTab = {
30
+ backgroundColor : 'grayShade1' ,
31
+ pointerEvents : 'none' ,
32
+ } ;
33
+
34
+ export const tab = {
35
+ display : 'table-cell' ,
36
+
37
+ p : 10 ,
38
+
39
+ backgroundColor : 'grayShade3' ,
40
+ border : '1px solid' ,
41
+ borderColor : ' gray' ,
42
+
43
+ whiteSpace : 'nowrap' ,
44
+ userSelect : 'none' ,
45
+ cursor : 'pointer' ,
46
+ '*' : {
47
+ cursor : 'pointer' ,
48
+ } ,
49
+
50
+ transition : ( { transitions } ) => transitions . button ,
51
+
52
+ ':hover' : {
53
+ ...R . dissoc ( 'borderBottomColor' , activeTab ) ,
54
+ } ,
55
+ } as SxStyleProp ;
Original file line number Diff line number Diff line change @@ -252,6 +252,8 @@ export {
252
252
constants ,
253
253
} ;
254
254
255
+ export { default as EmbeddedTabs } from './components/embedded-tabs' ;
256
+
255
257
export type { ITheme , IThemeColors , IThemeIconSizes } from './theme/types' ;
256
258
export type TooltipProps = import ( './components/tooltip' ) . TooltipProps ;
257
259
export type { BadgeProps , BlinkProps } from './components/badges' ;
@@ -289,6 +291,10 @@ export type {
289
291
RadioGroupProps ,
290
292
RadioGroupOption ,
291
293
} from './components/radio/radio-group' ;
294
+ export type {
295
+ EmbeddedTabsItem ,
296
+ EmbeddedTabsProps ,
297
+ } from './components/embedded-tabs' ;
292
298
293
299
// Rebass components
294
300
export { Flex , Box } from 'rebass' ;
You can’t perform that action at this time.
0 commit comments