You need to sign in or sign up before continuing.

@toptal/picasso-tabs 1.0.1-alpha-fx-4861-find-missing-deep-imports-in-staff-portal-ca4ef823d.4082 → 1.0.1-alpha-fx-4861-find-missing-deep-imports-in-staff-portal-25389459e.4083

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.
@@ -0,0 +1,6 @@
1
+ import type { OmitInternalProps } from '@toptal/picasso-shared'
2
+
3
+ import type { Props } from './Tabs'
4
+
5
+ export { default as Tabs } from './Tabs'
6
+ export type TabsProps = OmitInternalProps<Props>
@@ -0,0 +1,33 @@
1
+ import React from 'react'
2
+ import { Container, Tabs } from '@toptal/picasso'
3
+ import { SPACING_4 } from '@toptal/picasso-utils'
4
+
5
+ const Example = () => {
6
+ const [value, setValue] = React.useState(0)
7
+
8
+ const handleChange = (_: React.ChangeEvent<{}>, newValue: number) => {
9
+ setValue(newValue)
10
+ }
11
+
12
+ return (
13
+ <div>
14
+ <Tabs value={value} onChange={handleChange}>
15
+ <Tabs.Tab label='Label' />
16
+ <Tabs.Tab label='Label' />
17
+ <Tabs.Tab label='Label' />
18
+ </Tabs>
19
+
20
+ {value === 0 && (
21
+ <Container top={SPACING_4}>Content of the first tab</Container>
22
+ )}
23
+ {value === 1 && (
24
+ <Container top={SPACING_4}>Content of the second tab</Container>
25
+ )}
26
+ {value === 2 && (
27
+ <Container top={SPACING_4}>Content of the third tab</Container>
28
+ )}
29
+ </div>
30
+ )
31
+ }
32
+
33
+ export default Example
@@ -0,0 +1,27 @@
1
+ /* eslint-disable react/no-array-index-key */
2
+ import React from 'react'
3
+ import { Container, Tabs } from '@toptal/picasso'
4
+ import { SPACING_4, palette } from '@toptal/picasso-utils'
5
+
6
+ const TAB_COUNT = 2
7
+
8
+ const Example = () => {
9
+ const [value, setValue] = React.useState(0)
10
+
11
+ const handleChange = (_: React.ChangeEvent<{}>, newValue: number) => {
12
+ setValue(newValue)
13
+ }
14
+
15
+ return (
16
+ <div style={{ width: '45rem', border: `1px solid ${palette.grey.light}` }}>
17
+ <Tabs value={value} onChange={handleChange} variant='fullWidth'>
18
+ {Array.from({ length: TAB_COUNT }).map((_, index) => (
19
+ <Tabs.Tab key={index} label='Label' />
20
+ ))}
21
+ </Tabs>
22
+ <Container padded={SPACING_4}>Content of tab #{value}</Container>
23
+ </div>
24
+ )
25
+ }
26
+
27
+ export default Example
@@ -0,0 +1,27 @@
1
+ /* eslint-disable react/no-array-index-key */
2
+ import React from 'react'
3
+ import { Container, Tabs } from '@toptal/picasso'
4
+ import { SPACING_4 } from '@toptal/picasso-utils'
5
+
6
+ const TAB_COUNT = 10
7
+
8
+ const Example = () => {
9
+ const [value, setValue] = React.useState(0)
10
+
11
+ const handleChange = (_: React.ChangeEvent<{}>, newValue: number) => {
12
+ setValue(newValue)
13
+ }
14
+
15
+ return (
16
+ <div style={{ width: '13rem' }}>
17
+ <Tabs value={value} onChange={handleChange}>
18
+ {Array.from({ length: TAB_COUNT }).map((_, index) => (
19
+ <Tabs.Tab key={index} label='Label' />
20
+ ))}
21
+ </Tabs>
22
+ <Container top={SPACING_4}>Content of tab #{value}</Container>
23
+ </div>
24
+ )
25
+ }
26
+
27
+ export default Example
@@ -0,0 +1,84 @@
1
+ import React from 'react'
2
+ import { Container, Tabs } from '@toptal/picasso'
3
+ import { SPACING_4, shadows, sizes, palette } from '@toptal/picasso-utils'
4
+
5
+ type TabPanelProps = {
6
+ children: React.ReactNode
7
+ value: number
8
+ index: number
9
+ }
10
+ const TabPanel = ({ children, value, index }: TabPanelProps) => (
11
+ <Container role='tabpanel' hidden={value !== index}>
12
+ {children}
13
+ </Container>
14
+ )
15
+
16
+ // This component is not from BASE, just an example how it can be used
17
+ const TabsContent = ({ children }: { children: React.ReactNode }) => {
18
+ return (
19
+ <Container
20
+ style={{
21
+ flex: '1 1 auto',
22
+ backgroundColor: palette.grey.lightest,
23
+ boxShadow: shadows[1],
24
+ borderRadius: sizes.borderRadius.medium,
25
+ }}
26
+ padded={SPACING_4}
27
+ >
28
+ {children}
29
+ </Container>
30
+ )
31
+ }
32
+
33
+ const Example = () => {
34
+ const [value, setValue] = React.useState(0)
35
+
36
+ const handleChange = (_: React.ChangeEvent<{}>, newValue: number) => {
37
+ setValue(newValue)
38
+ }
39
+
40
+ return (
41
+ <Container
42
+ style={{
43
+ backgroundColor: palette.grey.lighter,
44
+ }}
45
+ padded={SPACING_4}
46
+ flex
47
+ >
48
+ <Tabs onChange={handleChange} orientation='vertical' value={value}>
49
+ <Tabs.Tab
50
+ avatar='./jacqueline-with-flowers-1954-square.jpg'
51
+ description='UI specialist'
52
+ label='Jacqueline Roque'
53
+ />
54
+ <Tabs.Tab
55
+ avatar='./jacqueline-with-flowers-1954-square.jpg'
56
+ description='UI specialist'
57
+ label='Jacqueline Roque'
58
+ />
59
+ <Tabs.Tab
60
+ avatar=''
61
+ description='UI specialist'
62
+ label='Jacqueline Roque'
63
+ />
64
+ <Tabs.Tab avatar={null} description='UI specialist' label='John Doe' />
65
+ </Tabs>
66
+ <TabsContent>
67
+ <TabPanel value={value} index={0}>
68
+ Content of the first tab
69
+ </TabPanel>
70
+ <TabPanel value={value} index={1}>
71
+ Content of the second tab
72
+ </TabPanel>
73
+ <TabPanel value={value} index={2}>
74
+ Content of the third tab
75
+ </TabPanel>
76
+ <TabPanel value={value} index={3}>
77
+ Content of the third tab
78
+ </TabPanel>
79
+ </TabsContent>
80
+ </Container>
81
+ )
82
+ }
83
+
84
+ export default Example
@@ -0,0 +1,58 @@
1
+ import { Tabs } from '../Tabs'
2
+ import tabStory from '../../Tab/story'
3
+ import PicassoBook from '~/.storybook/components/PicassoBook'
4
+
5
+ const page = PicassoBook.section('Layout').createPage(
6
+ 'Tabs',
7
+ `
8
+ Tabs allow to switch between content sections
9
+
10
+ ${PicassoBook.createBaseDocsLink(
11
+ 'https://www.figma.com/file/5SCTOPrCDcHuk5We091GBn/Product-Library?node-id=246%3A11213'
12
+ )}
13
+
14
+ ${PicassoBook.createSourceLink(__filename)}
15
+ `
16
+ )
17
+
18
+ page
19
+ .createTabChapter('Props')
20
+ .addComponentDocs({ component: Tabs, name: 'Tabs' })
21
+ .addComponentDocs(tabStory.componentDocs)
22
+
23
+ page
24
+ .createChapter()
25
+ .addExample(
26
+ 'Tabs/story/Default.example.tsx',
27
+ {
28
+ title: 'Default',
29
+ takeScreenshot: false,
30
+ },
31
+ 'base/Tabs'
32
+ )
33
+ .addExample(
34
+ 'Tabs/story/Vertical.example.tsx',
35
+ {
36
+ title: 'Vertical',
37
+ takeScreenshot: false,
38
+ description: '⚠️ Not responsive',
39
+ },
40
+ 'base/Tabs'
41
+ )
42
+ .addExample(
43
+ 'Tabs/story/ScrollButtons.example.tsx',
44
+ {
45
+ title: 'Scroll buttons',
46
+ takeScreenshot: false,
47
+ },
48
+ 'base/Tabs'
49
+ )
50
+ .addExample(
51
+ 'Tabs/story/FullWidth.example.tsx',
52
+ {
53
+ title: 'Full Width',
54
+ screenshotBreakpoints: true,
55
+ },
56
+ 'base/Tabs'
57
+ )
58
+ page.connect(tabStory.chapter)
@@ -0,0 +1,45 @@
1
+ import type { Theme } from '@material-ui/core/styles'
2
+ import { createStyles } from '@material-ui/core/styles'
3
+ import { PicassoProvider } from '@toptal/picasso-provider'
4
+
5
+ PicassoProvider.override(({ palette }: Theme) => ({
6
+ MuiTabs: {
7
+ root: {
8
+ position: 'relative',
9
+ minHeight: 0,
10
+ },
11
+ vertical: {
12
+ width: 200,
13
+ margin: 0,
14
+ '& $scroller': {
15
+ // We need a bit of padding to allow active tab's shadow to be visible
16
+ paddingLeft: '0.5em',
17
+ },
18
+
19
+ '& $indicator': {
20
+ display: 'none',
21
+ },
22
+ },
23
+ indicator: {
24
+ backgroundColor: palette.blue.main,
25
+ zIndex: 1,
26
+ },
27
+ },
28
+ }))
29
+
30
+ export default ({ palette }: Theme) =>
31
+ createStyles({
32
+ horizontal: {
33
+ '&::after': {
34
+ position: 'absolute',
35
+ content: '""',
36
+ bottom: 0,
37
+ left: 0,
38
+ right: 0,
39
+ height: 1,
40
+ backgroundColor: palette.grey.main,
41
+ zIndex: 0,
42
+ },
43
+ },
44
+ vertical: {},
45
+ })
@@ -0,0 +1,165 @@
1
+ /* eslint-disable react/no-array-index-key */
2
+ import React from 'react'
3
+ import { render, fireEvent } from '@testing-library/react'
4
+ import type { OmitInternalProps } from '@toptal/picasso-shared'
5
+ import { TestingPicasso } from '@toptal/picasso-test-utils'
6
+
7
+ import type { TabProps } from '../Tab'
8
+ import type { Props } from './Tabs'
9
+ import { TabsCompound as Tabs } from '../TabsCompound'
10
+
11
+ const renderTabContent = (tab: TabProps, index: number, value: any) => {
12
+ const isTabActive = index + 1 === value || tab.value === value
13
+ const testId = `tab-${index + 1}-content`
14
+
15
+ if (isTabActive) {
16
+ return (
17
+ <div key={testId} data-testid={testId}>
18
+ Tab #{index + 1} content
19
+ </div>
20
+ )
21
+ }
22
+
23
+ return null
24
+ }
25
+
26
+ const renderTabs = (
27
+ tabs: TabProps[],
28
+ { value, onChange, variant }: OmitInternalProps<Props, 'children'>,
29
+ orientation: 'horizontal' | 'vertical' = 'horizontal'
30
+ ) => {
31
+ return render(
32
+ <TestingPicasso>
33
+ <Tabs
34
+ onChange={onChange}
35
+ value={value}
36
+ orientation={orientation}
37
+ variant={variant}
38
+ >
39
+ {tabs.map((tab, index) => (
40
+ <Tabs.Tab
41
+ key={index}
42
+ data-testid={`tab-${index + 1}`}
43
+ value={tab.value}
44
+ label={tab.label}
45
+ disabled={tab.disabled}
46
+ />
47
+ ))}
48
+ </Tabs>
49
+
50
+ {tabs.map((tab, index) => renderTabContent(tab, index, value))}
51
+ </TestingPicasso>
52
+ )
53
+ }
54
+
55
+ describe('Tabs', () => {
56
+ it('renders', () => {
57
+ const { container, queryByTestId } = renderTabs(
58
+ [{ label: 'Tab 1' }, { label: 'Tab 2' }],
59
+ {
60
+ value: false,
61
+ }
62
+ )
63
+
64
+ expect(queryByTestId('tab-1-content')).not.toBeInTheDocument()
65
+ expect(queryByTestId('tab-2-content')).not.toBeInTheDocument()
66
+
67
+ expect(container).toMatchSnapshot()
68
+ })
69
+
70
+ it('renders in vertical orientation', () => {
71
+ const { container } = renderTabs(
72
+ [{ label: 'Tab 1' }, { label: 'Tab 2' }],
73
+ { value: false },
74
+ 'vertical'
75
+ )
76
+
77
+ expect(container).toMatchSnapshot()
78
+ })
79
+
80
+ it('renders with a pre-selected option', () => {
81
+ const { container, queryByTestId } = renderTabs(
82
+ [{ label: 'Tab 1' }, { label: 'Tab 2' }],
83
+ {
84
+ value: 1,
85
+ }
86
+ )
87
+
88
+ expect(queryByTestId('tab-2-content')).not.toBeInTheDocument()
89
+ expect(queryByTestId('tab-1-content')).toBeInTheDocument()
90
+
91
+ expect(container).toMatchSnapshot()
92
+ })
93
+
94
+ it('renders with a pre-selected option using custom value', () => {
95
+ const { container, queryByTestId } = renderTabs(
96
+ [
97
+ { label: 'Tab 1', value: 'tab-1' },
98
+ { label: 'Tab 2', value: 'tab-2' },
99
+ ],
100
+ {
101
+ value: 'tab-1',
102
+ }
103
+ )
104
+
105
+ expect(queryByTestId('tab-2-content')).not.toBeInTheDocument()
106
+ expect(queryByTestId('tab-1-content')).toBeInTheDocument()
107
+
108
+ expect(container).toMatchSnapshot()
109
+ })
110
+
111
+ it('fires onChange when clicked', () => {
112
+ const onChange = jest.fn()
113
+ const { getByTestId } = renderTabs(
114
+ [{ label: 'Tab 1' }, { label: 'Tab 2' }],
115
+ {
116
+ value: 1,
117
+ onChange,
118
+ }
119
+ )
120
+
121
+ fireEvent.click(getByTestId('tab-2'))
122
+ expect(onChange).toHaveBeenCalledTimes(1)
123
+ })
124
+
125
+ it('fires onChange with custom value when clicked', () => {
126
+ const onChange = jest.fn()
127
+ const { getByTestId } = renderTabs(
128
+ [
129
+ { label: 'Tab 1', value: 'first' },
130
+ { label: 'Tab 2', value: 'second' },
131
+ ],
132
+ {
133
+ value: 'first',
134
+ onChange,
135
+ }
136
+ )
137
+
138
+ fireEvent.click(getByTestId('tab-2'))
139
+ expect(onChange).toHaveBeenCalledTimes(1)
140
+ expect(onChange).toHaveBeenCalledWith(expect.anything(), 'second')
141
+ })
142
+
143
+ it('doesnt fire onChange when disabled', () => {
144
+ const onChange = jest.fn()
145
+ const { getByTestId } = renderTabs(
146
+ [{ label: 'Tab 1' }, { label: 'Tab 2', disabled: true }],
147
+ {
148
+ value: 1,
149
+ onChange,
150
+ }
151
+ )
152
+
153
+ fireEvent.click(getByTestId('tab-2'))
154
+ expect(onChange).toHaveBeenCalledTimes(0)
155
+ })
156
+
157
+ it('renders in full width', () => {
158
+ const { container } = renderTabs([{ label: 'Tab 1' }, { label: 'Tab 2' }], {
159
+ value: false,
160
+ variant: 'fullWidth',
161
+ })
162
+
163
+ expect(container).toMatchSnapshot()
164
+ })
165
+ })
@@ -0,0 +1,27 @@
1
+ import type { Ref } from 'react'
2
+ import { useEffect, useRef } from 'react'
3
+ import type { TabsActions } from '@material-ui/core'
4
+
5
+ /*
6
+ * MuiTabs break when the size of a tab changes without rendering with React.
7
+ * This issue happens when the font is loaded after the initial render of the component.
8
+ * To solve this issue, we imperatively update the indicator and scroll buttons when it happens.
9
+ */
10
+ const useTabAction = (): Ref<TabsActions> => {
11
+ const ref = useRef<TabsActions>(null)
12
+
13
+ useEffect(() => {
14
+ const listener = () => {
15
+ ref.current?.updateIndicator()
16
+ ref.current?.updateScrollButtons()
17
+ }
18
+
19
+ window.addEventListener('load', listener)
20
+
21
+ return () => window.removeEventListener('load', listener)
22
+ }, [])
23
+
24
+ return ref
25
+ }
26
+
27
+ export default useTabAction
@@ -0,0 +1,6 @@
1
+ import { Tab } from '../Tab'
2
+ import { Tabs } from '../Tabs'
3
+
4
+ export const TabsCompound = Object.assign(Tabs, {
5
+ Tab,
6
+ })
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ export * from './TabScrollButton'
2
+ export * from './Tabs'
3
+ export * from './Tab'
4
+ export * from './TabDescription'
5
+ export * from './TabsCompound'
6
+ export * from './TabLabel'
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "extends": "../../../tsconfig.base.json",
3
+ "compilerOptions": { "outDir": "dist-package" },
4
+ "include": ["src"],
5
+ "references": [
6
+ { "path": "../../picasso-provider" },
7
+ { "path": "../../shared" },
8
+ { "path": "../Container" },
9
+ { "path": "../Icons" },
10
+ { "path": "../Typography" },
11
+ { "path": "../TypographyOverflow" },
12
+ { "path": "../UserBadge" },
13
+ { "path": "../Utils" }
14
+ ]
15
+ }