@toptal/picasso-tabs 5.0.15-alpha-ff-7-tabs-2a3da7cea.16 → 5.0.15-alpha-bill-root-ref-context-42c3d2541.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-package/src/Tab/Tab.d.ts +10 -7
- package/dist-package/src/Tab/Tab.d.ts.map +1 -1
- package/dist-package/src/Tab/Tab.js +26 -73
- package/dist-package/src/Tab/Tab.js.map +1 -1
- package/dist-package/src/Tab/index.d.ts +4 -1
- package/dist-package/src/Tab/index.d.ts.map +1 -1
- package/dist-package/src/Tab/index.js.map +1 -1
- package/dist-package/src/Tab/styles.d.ts +4 -0
- package/dist-package/src/Tab/styles.d.ts.map +1 -0
- package/dist-package/src/Tab/styles.js +95 -0
- package/dist-package/src/Tab/styles.js.map +1 -0
- package/dist-package/src/TabScrollButton/TabScrollButton.d.ts +12 -0
- package/dist-package/src/TabScrollButton/TabScrollButton.d.ts.map +1 -0
- package/dist-package/src/TabScrollButton/TabScrollButton.js +30 -0
- package/dist-package/src/TabScrollButton/TabScrollButton.js.map +1 -0
- package/dist-package/src/TabScrollButton/index.d.ts +5 -0
- package/dist-package/src/TabScrollButton/index.d.ts.map +1 -0
- package/dist-package/src/TabScrollButton/index.js +2 -0
- package/dist-package/src/TabScrollButton/index.js.map +1 -0
- package/dist-package/src/Tabs/Tabs.d.ts +12 -15
- package/dist-package/src/Tabs/Tabs.d.ts.map +1 -1
- package/dist-package/src/Tabs/Tabs.js +17 -71
- package/dist-package/src/Tabs/Tabs.js.map +1 -1
- package/dist-package/src/Tabs/index.d.ts +5 -1
- package/dist-package/src/Tabs/index.d.ts.map +1 -1
- package/dist-package/src/Tabs/index.js.map +1 -1
- package/dist-package/src/Tabs/styles.d.ts +4 -0
- package/dist-package/src/Tabs/styles.d.ts.map +1 -0
- package/dist-package/src/Tabs/styles.js +41 -0
- package/dist-package/src/Tabs/styles.js.map +1 -0
- package/dist-package/src/Tabs/use-tab-action.d.ts +5 -0
- package/dist-package/src/Tabs/use-tab-action.d.ts.map +1 -0
- package/dist-package/src/Tabs/use-tab-action.js +21 -0
- package/dist-package/src/Tabs/use-tab-action.js.map +1 -0
- package/dist-package/src/TabsCompound/index.d.ts +4 -6
- package/dist-package/src/TabsCompound/index.d.ts.map +1 -1
- package/dist-package/src/index.d.ts +1 -0
- package/dist-package/src/index.d.ts.map +1 -1
- package/dist-package/src/index.js +1 -0
- package/dist-package/src/index.js.map +1 -1
- package/package.json +13 -13
- package/src/Tab/Tab.tsx +79 -149
- package/src/Tab/__snapshots__/test.tsx.snap +45 -29
- package/src/Tab/index.ts +6 -1
- package/src/Tab/story/CustomValue.example.tsx +2 -2
- package/src/Tab/story/IconOrBadge.example.tsx +3 -3
- package/src/Tab/styles.ts +107 -0
- package/src/TabScrollButton/TabScrollButton.tsx +59 -0
- package/src/TabScrollButton/index.ts +6 -0
- package/src/Tabs/Tabs.tsx +60 -145
- package/src/Tabs/__snapshots__/test.tsx.snap +76 -45
- package/src/Tabs/index.ts +7 -1
- package/src/Tabs/story/Default.example.tsx +6 -7
- package/src/Tabs/styles.ts +45 -0
- package/src/Tabs/test.tsx +14 -16
- package/src/Tabs/use-tab-action.ts +27 -0
- package/src/index.ts +1 -0
- package/dist-package/src/Tabs/TabsContext.d.ts +0 -11
- package/dist-package/src/Tabs/TabsContext.d.ts.map +0 -1
- package/dist-package/src/Tabs/TabsContext.js +0 -16
- package/dist-package/src/Tabs/TabsContext.js.map +0 -1
- package/src/Tabs/TabsContext.tsx +0 -27
@@ -0,0 +1,107 @@
|
|
1
|
+
import type { Theme } from '@material-ui/core/styles'
|
2
|
+
import { createStyles } from '@material-ui/core/styles'
|
3
|
+
import { rem } from '@toptal/picasso-shared'
|
4
|
+
import { PicassoProvider } from '@toptal/picasso-provider'
|
5
|
+
|
6
|
+
PicassoProvider.override(({ breakpoints, palette }: Theme) => ({
|
7
|
+
MuiTab: {
|
8
|
+
root: {
|
9
|
+
minHeight: 0,
|
10
|
+
minWidth: 0,
|
11
|
+
lineHeight: 1,
|
12
|
+
textTransform: 'none',
|
13
|
+
padding: `${rem('9px')} 0 ${rem('7px')}`,
|
14
|
+
overflow: 'initial',
|
15
|
+
|
16
|
+
[breakpoints.up('md')]: {
|
17
|
+
padding: undefined,
|
18
|
+
},
|
19
|
+
|
20
|
+
color: palette.grey.dark,
|
21
|
+
|
22
|
+
[breakpoints.up('md')]: {
|
23
|
+
minWidth: 'auto',
|
24
|
+
fontSize: '1rem',
|
25
|
+
},
|
26
|
+
},
|
27
|
+
labelIcon: {
|
28
|
+
minHeight: 0,
|
29
|
+
paddingRight: '1.5rem',
|
30
|
+
paddingTop: rem('9px'),
|
31
|
+
'& $wrapper > *:first-child': {
|
32
|
+
position: 'absolute',
|
33
|
+
right: 0,
|
34
|
+
marginBottom: 0,
|
35
|
+
},
|
36
|
+
},
|
37
|
+
selected: {
|
38
|
+
color: palette.common.black,
|
39
|
+
},
|
40
|
+
textColorInherit: {
|
41
|
+
'&$disabled': {
|
42
|
+
color: palette.grey.main,
|
43
|
+
},
|
44
|
+
},
|
45
|
+
disabled: {},
|
46
|
+
},
|
47
|
+
}))
|
48
|
+
|
49
|
+
export default ({ sizes, palette, shadows, transitions }: Theme) =>
|
50
|
+
createStyles({
|
51
|
+
horizontal: {
|
52
|
+
paddingTop: 0,
|
53
|
+
'&:not(:last-child)': {
|
54
|
+
marginRight: '2em',
|
55
|
+
},
|
56
|
+
},
|
57
|
+
vertical: {
|
58
|
+
width: '100%',
|
59
|
+
borderRadius: `${sizes.borderRadius.small} 0 0 ${sizes.borderRadius.small}`,
|
60
|
+
margin: '0.25rem 0',
|
61
|
+
overflow: 'hidden',
|
62
|
+
padding: '0.5rem 1rem',
|
63
|
+
transition: `all ${transitions.duration.short}ms ${transitions.easing.easeInOut}`,
|
64
|
+
textAlign: 'left',
|
65
|
+
backgroundColor: palette.grey.lighter,
|
66
|
+
opacity: 1,
|
67
|
+
color: palette.grey.dark,
|
68
|
+
|
69
|
+
'&:first-child': {
|
70
|
+
marginTop: '1rem',
|
71
|
+
},
|
72
|
+
|
73
|
+
'&:last-child': {
|
74
|
+
marginBottom: '1rem',
|
75
|
+
},
|
76
|
+
|
77
|
+
'&:hover': {
|
78
|
+
color: palette.common.black,
|
79
|
+
},
|
80
|
+
|
81
|
+
'&:hover:not($selected)': {
|
82
|
+
backgroundColor: palette.grey.lighter2,
|
83
|
+
},
|
84
|
+
|
85
|
+
'& $wrapper': {
|
86
|
+
display: 'block',
|
87
|
+
},
|
88
|
+
},
|
89
|
+
selected: {
|
90
|
+
'&$vertical': {
|
91
|
+
color: palette.common.black,
|
92
|
+
boxShadow: shadows[1],
|
93
|
+
backgroundColor: palette.grey.lightest,
|
94
|
+
|
95
|
+
'&::before': {
|
96
|
+
content: '""',
|
97
|
+
background: palette.blue.main,
|
98
|
+
position: 'absolute',
|
99
|
+
left: 0,
|
100
|
+
top: 0,
|
101
|
+
bottom: 0,
|
102
|
+
width: '3px',
|
103
|
+
},
|
104
|
+
},
|
105
|
+
},
|
106
|
+
wrapper: {},
|
107
|
+
})
|
@@ -0,0 +1,59 @@
|
|
1
|
+
import React, { forwardRef } from 'react'
|
2
|
+
import { ButtonBase } from '@material-ui/core'
|
3
|
+
import type { BaseProps } from '@toptal/picasso-shared'
|
4
|
+
import { BackMinor16, ChevronMinor16 } from '@toptal/picasso-icons'
|
5
|
+
import { Container } from '@toptal/picasso-container'
|
6
|
+
import { twMerge } from '@toptal/picasso-tailwind-merge'
|
7
|
+
|
8
|
+
type DirectionType = 'left' | 'right'
|
9
|
+
|
10
|
+
export interface Props extends BaseProps {
|
11
|
+
/** The direction the button should indicate. */
|
12
|
+
direction: DirectionType
|
13
|
+
/** If `true`, the component is disabled. */
|
14
|
+
disabled?: boolean
|
15
|
+
}
|
16
|
+
|
17
|
+
export const TabScrollButton = forwardRef<HTMLDivElement, Props>(
|
18
|
+
function TabScrollButton(props, ref) {
|
19
|
+
const { className, style, direction, disabled, ...rest } = props
|
20
|
+
|
21
|
+
if (disabled) {
|
22
|
+
return null
|
23
|
+
}
|
24
|
+
|
25
|
+
return (
|
26
|
+
<Container
|
27
|
+
{...rest}
|
28
|
+
ref={ref}
|
29
|
+
className={twMerge('relative', className)}
|
30
|
+
style={style}
|
31
|
+
>
|
32
|
+
<Container
|
33
|
+
className={twMerge(
|
34
|
+
'absolute w-10 h-full z-10',
|
35
|
+
direction === 'left'
|
36
|
+
? 'bg-gradient-to-r from-white via-white to-transparent'
|
37
|
+
: 'bg-gradient-to-l from-white via-white to-transparent',
|
38
|
+
direction === 'left' ? 'left-0' : 'right-0'
|
39
|
+
)}
|
40
|
+
>
|
41
|
+
<ButtonBase
|
42
|
+
className={twMerge(
|
43
|
+
'absolute w-4 h-full',
|
44
|
+
direction === 'left' ? 'left-0' : 'right-0'
|
45
|
+
)}
|
46
|
+
aria-label={`${direction} button`}
|
47
|
+
data-testid={`tab-scroll-button-${direction}`}
|
48
|
+
>
|
49
|
+
{direction === 'left' ? <BackMinor16 /> : <ChevronMinor16 />}
|
50
|
+
</ButtonBase>
|
51
|
+
</Container>
|
52
|
+
</Container>
|
53
|
+
)
|
54
|
+
}
|
55
|
+
)
|
56
|
+
|
57
|
+
TabScrollButton.displayName = 'TabScrollButton'
|
58
|
+
|
59
|
+
export default TabScrollButton
|
package/src/Tabs/Tabs.tsx
CHANGED
@@ -1,164 +1,79 @@
|
|
1
|
-
import type {
|
2
|
-
import React, { forwardRef
|
1
|
+
import type { ForwardedRef, ReactNode } from 'react'
|
2
|
+
import React, { forwardRef } from 'react'
|
3
|
+
import type { Theme } from '@material-ui/core/styles'
|
4
|
+
import { makeStyles } from '@material-ui/core/styles'
|
5
|
+
import { Tabs as MUITabs } from '@material-ui/core'
|
3
6
|
import type { BaseProps } from '@toptal/picasso-shared'
|
4
|
-
import { twJoin, twMerge } from '@toptal/picasso-tailwind-merge'
|
5
7
|
|
6
|
-
import {
|
7
|
-
import
|
8
|
-
import
|
8
|
+
import { TabScrollButton } from '../TabScrollButton'
|
9
|
+
import styles from './styles'
|
10
|
+
import useTabAction from './use-tab-action'
|
9
11
|
|
10
|
-
export
|
12
|
+
export type TabsValueType = string | number | false
|
13
|
+
|
14
|
+
export interface Props<V extends TabsValueType> extends BaseProps {
|
11
15
|
/** Tabs content containing Tab components */
|
12
16
|
children: ReactNode
|
13
17
|
|
14
18
|
/** Callback fired when the value changes. */
|
15
|
-
onChange?: (event: ChangeEvent<{}
|
19
|
+
onChange?: (event: React.ChangeEvent<{}> | null, value: V) => void
|
16
20
|
|
17
|
-
/**
|
18
|
-
|
19
|
-
* If you don't want any selected Tab, you can set this property to null.
|
20
|
-
*/
|
21
|
-
value: T
|
21
|
+
/** The value of the currently selected Tab. If you don't want any selected Tab, you can set this property to false. */
|
22
|
+
value: V
|
22
23
|
|
23
24
|
/** The tabs orientation (layout flow direction). */
|
24
25
|
orientation?: 'horizontal' | 'vertical'
|
25
26
|
|
26
27
|
/** Determines additional display behavior of the tabs */
|
27
28
|
variant?: 'scrollable' | 'fullWidth'
|
28
|
-
|
29
|
-
/** The default value. Use when the component is not controlled. */
|
30
|
-
defaultValue?: T
|
31
|
-
|
32
|
-
/** The direction of the text. */
|
33
|
-
direction?: 'ltr' | 'rtl'
|
34
29
|
}
|
35
30
|
|
36
|
-
const
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
'
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
}
|
57
|
-
|
58
|
-
const
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
}
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
onChange,
|
75
|
-
value: valueProp,
|
76
|
-
defaultValue,
|
77
|
-
variant = 'scrollable',
|
78
|
-
direction = 'ltr',
|
79
|
-
className,
|
80
|
-
...rest
|
81
|
-
} = props
|
82
|
-
|
83
|
-
const [value, setValue] = React.useState<T>(defaultValue as T)
|
84
|
-
const isControlled = valueProp !== undefined
|
85
|
-
const currentValue = isControlled ? valueProp : value
|
86
|
-
|
87
|
-
const handleChange = useCallback(
|
88
|
-
(event: ChangeEvent<{}>, newValue: T) => {
|
89
|
-
if (!isControlled) {
|
90
|
-
setValue(newValue)
|
91
|
-
}
|
92
|
-
onChange?.(event, newValue)
|
93
|
-
},
|
94
|
-
[isControlled, onChange]
|
95
|
-
)
|
96
|
-
|
97
|
-
const contextValue = useMemo(
|
98
|
-
() => ({
|
99
|
-
value: currentValue,
|
100
|
-
onChange: handleChange,
|
101
|
-
orientation,
|
102
|
-
variant,
|
103
|
-
direction,
|
104
|
-
}),
|
105
|
-
[currentValue, handleChange, orientation, variant, direction]
|
106
|
-
)
|
107
|
-
|
108
|
-
const isVertical = orientation === 'vertical'
|
109
|
-
|
110
|
-
const childrenWithIndex = React.Children.map(children, (child, idx) => {
|
111
|
-
if (
|
112
|
-
React.isValidElement(child) &&
|
113
|
-
child.type === Tab &&
|
114
|
-
child.props.value === undefined
|
115
|
-
) {
|
116
|
-
return React.cloneElement(child as React.ReactElement<TabProps<number>>, {
|
117
|
-
value: idx,
|
118
|
-
})
|
119
|
-
}
|
120
|
-
|
121
|
-
return child
|
122
|
-
})
|
123
|
-
|
124
|
-
return (
|
125
|
-
<TabsContext.Provider value={contextValue}>
|
126
|
-
<div
|
127
|
-
{...rest}
|
128
|
-
ref={ref}
|
129
|
-
data-component-type='tabs'
|
130
|
-
className={twMerge(
|
131
|
-
'relative min-h-0 flex overflow-hidden',
|
132
|
-
classesByOrientation[orientation].root,
|
133
|
-
classesByVariant[variant].root,
|
134
|
-
className
|
135
|
-
)}
|
136
|
-
aria-orientation={orientation}
|
137
|
-
>
|
138
|
-
<div
|
139
|
-
className={twJoin(
|
140
|
-
classesByVariant[variant].scroller,
|
141
|
-
classesByOrientation[orientation].scroller,
|
142
|
-
'flex-auto inline-block relative whitespace-nowrap'
|
143
|
-
)}
|
31
|
+
const useStyles = makeStyles<Theme>(styles, {
|
32
|
+
name: 'Tabs',
|
33
|
+
})
|
34
|
+
|
35
|
+
export const TabsOrientationContext = React.createContext<
|
36
|
+
'horizontal' | 'vertical'
|
37
|
+
>('horizontal')
|
38
|
+
|
39
|
+
export const Tabs = forwardRef(
|
40
|
+
<V extends TabsValueType = TabsValueType>(
|
41
|
+
props: Props<V>,
|
42
|
+
ref: ForwardedRef<HTMLButtonElement>
|
43
|
+
) => {
|
44
|
+
const {
|
45
|
+
children,
|
46
|
+
orientation = 'horizontal',
|
47
|
+
onChange,
|
48
|
+
value,
|
49
|
+
variant = 'scrollable',
|
50
|
+
...rest
|
51
|
+
} = props
|
52
|
+
const classes = useStyles(props)
|
53
|
+
const action = useTabAction()
|
54
|
+
|
55
|
+
return (
|
56
|
+
<TabsOrientationContext.Provider value={orientation}>
|
57
|
+
<MUITabs
|
58
|
+
{...rest}
|
59
|
+
classes={{ root: classes[orientation] }}
|
60
|
+
ref={ref}
|
61
|
+
onChange={onChange}
|
62
|
+
value={value}
|
63
|
+
action={action}
|
64
|
+
scrollButtons='auto'
|
65
|
+
ScrollButtonComponent={TabScrollButton}
|
66
|
+
orientation={orientation}
|
67
|
+
variant={variant}
|
68
|
+
data-component-type='tabs'
|
144
69
|
>
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
</div>
|
154
|
-
</TabsContext.Provider>
|
155
|
-
)
|
156
|
-
}
|
157
|
-
|
158
|
-
TabsInner.displayName = 'Tabs'
|
159
|
-
|
160
|
-
export const Tabs = forwardRef(TabsInner) as <T = number>(
|
161
|
-
props: TabsProps<T> & { ref?: Ref<HTMLDivElement> }
|
162
|
-
) => ReactElement | null
|
70
|
+
{children}
|
71
|
+
</MUITabs>
|
72
|
+
</TabsOrientationContext.Provider>
|
73
|
+
)
|
74
|
+
}
|
75
|
+
) as <V extends TabsValueType = TabsValueType>(
|
76
|
+
props: Props<V> & { ref?: ForwardedRef<HTMLDivElement> }
|
77
|
+
) => ReturnType<typeof MUITabs>
|
163
78
|
|
164
79
|
export default Tabs
|