@toptal/picasso-tabs 5.0.15-alpha-ff-7-tabs-19babbfd6.8 → 5.0.15-alpha-ff-7-tabs-2a3da7cea.16

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.
Files changed (32) hide show
  1. package/dist-package/src/Tab/Tab.d.ts +7 -10
  2. package/dist-package/src/Tab/Tab.d.ts.map +1 -1
  3. package/dist-package/src/Tab/Tab.js +32 -33
  4. package/dist-package/src/Tab/Tab.js.map +1 -1
  5. package/dist-package/src/Tab/index.d.ts +1 -4
  6. package/dist-package/src/Tab/index.d.ts.map +1 -1
  7. package/dist-package/src/Tab/index.js.map +1 -1
  8. package/dist-package/src/Tabs/Tabs.d.ts +11 -11
  9. package/dist-package/src/Tabs/Tabs.d.ts.map +1 -1
  10. package/dist-package/src/Tabs/Tabs.js +34 -17
  11. package/dist-package/src/Tabs/Tabs.js.map +1 -1
  12. package/dist-package/src/Tabs/TabsContext.d.ts +11 -0
  13. package/dist-package/src/Tabs/TabsContext.d.ts.map +1 -0
  14. package/dist-package/src/Tabs/TabsContext.js +16 -0
  15. package/dist-package/src/Tabs/TabsContext.js.map +1 -0
  16. package/dist-package/src/Tabs/index.d.ts +1 -5
  17. package/dist-package/src/Tabs/index.d.ts.map +1 -1
  18. package/dist-package/src/Tabs/index.js.map +1 -1
  19. package/dist-package/src/TabsCompound/index.d.ts +6 -2
  20. package/dist-package/src/TabsCompound/index.d.ts.map +1 -1
  21. package/package.json +12 -13
  22. package/src/Tab/Tab.tsx +103 -111
  23. package/src/Tab/__snapshots__/test.tsx.snap +29 -45
  24. package/src/Tab/index.ts +1 -6
  25. package/src/Tab/story/CustomValue.example.tsx +2 -2
  26. package/src/Tab/story/IconOrBadge.example.tsx +3 -3
  27. package/src/Tabs/Tabs.tsx +103 -69
  28. package/src/Tabs/TabsContext.tsx +27 -0
  29. package/src/Tabs/__snapshots__/test.tsx.snap +33 -49
  30. package/src/Tabs/index.ts +1 -7
  31. package/src/Tabs/story/Default.example.tsx +7 -6
  32. package/src/Tabs/test.tsx +12 -10
package/src/Tab/Tab.tsx CHANGED
@@ -1,17 +1,15 @@
1
- import type { ReactNode, HTMLAttributes, ReactElement } from 'react'
2
- import React, { forwardRef, useContext } from 'react'
3
- import type { TabProps } from '@mui/base/Tab'
4
- import { Tab as MUITab } from '@mui/base/Tab'
1
+ import type { ReactNode, HTMLAttributes, ReactElement, Ref } from 'react'
2
+ import React, { forwardRef } from 'react'
5
3
  import type { BaseProps, TextLabelProps } from '@toptal/picasso-shared'
6
4
  import { useTitleCase } from '@toptal/picasso-shared'
7
5
  import { UserBadge } from '@toptal/picasso-user-badge'
8
6
  import { twJoin, twMerge } from '@toptal/picasso-tailwind-merge'
9
7
 
10
- import { TabsContext } from '../Tabs/Tabs'
8
+ import { useTabsContext } from '../Tabs/TabsContext'
11
9
  import { TabLabel } from '../TabLabel'
12
10
  import { TabDescription } from '../TabDescription'
13
11
 
14
- export interface Props
12
+ export interface TabProps<T = number>
15
13
  extends BaseProps,
16
14
  TextLabelProps,
17
15
  Omit<HTMLAttributes<HTMLButtonElement>, 'onChange'> {
@@ -21,8 +19,8 @@ export interface Props
21
19
  */
22
20
  disabled?: boolean
23
21
 
24
- /** You can provide your own value. Otherwise, we fallback to the child position index */
25
- value?: TabProps['value']
22
+ /** The value of the tab */
23
+ value?: T
26
24
 
27
25
  /** The label element */
28
26
  label?: ReactNode
@@ -35,12 +33,6 @@ export interface Props
35
33
 
36
34
  /** Description */
37
35
  description?: string
38
-
39
- // Properties below are managed by Tabs component
40
-
41
- selected?: boolean
42
- onChange?: TabProps['onChange']
43
- onClick?: TabProps['onClick']
44
36
  }
45
37
 
46
38
  const getOpacityClass = (
@@ -51,7 +43,6 @@ const getOpacityClass = (
51
43
  if (disabled) {
52
44
  return 'opacity-50'
53
45
  }
54
-
55
46
  if (selected || orientation === 'vertical') {
56
47
  return 'opacity-100 '
57
48
  }
@@ -60,13 +51,13 @@ const getOpacityClass = (
60
51
  }
61
52
 
62
53
  const wrapperClassesByOrientation = {
63
- horizontal: 'inline-flex items-center flex-col justify-center',
54
+ horizontal: 'inline-flex flex-row items-center justify-center',
64
55
  vertical: 'block',
65
56
  }
66
57
 
67
58
  const rootClassesByOrientation = (selected: boolean) => ({
68
59
  horizontal: [
69
- 'm-0 [&:not(:last-child)]:mr-8 pt-[0.5625rem] pb-[0.4375rem] px-0',
60
+ 'm-0 [&:not(:last-child)]:mr-8 pt-0 pb-[0.4375rem] px-0',
70
61
  'text-center bg-transparent transition-shadow z-10 rounded-none',
71
62
  'text-black',
72
63
  selected && 'shadow-blue-500 shadow-[inset_0_-2px_0]',
@@ -96,96 +87,6 @@ const classesByVariant = {
96
87
  fullWidth: 'shrink flex-grow basis-0',
97
88
  }
98
89
 
99
- export const Tab = forwardRef<HTMLButtonElement, Props>(function Tab(
100
- props,
101
- ref
102
- ) {
103
- const {
104
- disabled,
105
- value,
106
- label,
107
- icon,
108
- onChange,
109
- onClick,
110
- titleCase: propsTitleCase,
111
- description,
112
- avatar,
113
- className,
114
- ...rest
115
- } = props
116
- const titleCase = useTitleCase(propsTitleCase)
117
- const { orientation, variant } = useContext(TabsContext)
118
- const isHorizontal = orientation === 'horizontal'
119
-
120
- const renderLabel = getLabelComponent({
121
- avatar,
122
- description,
123
- disabled,
124
- label,
125
- orientation,
126
- titleCase,
127
- })
128
-
129
- return (
130
- <MUITab
131
- className=''
132
- {...rest}
133
- ref={ref}
134
- tabIndex={0}
135
- disabled={disabled}
136
- value={value}
137
- onChange={onChange}
138
- onClick={onClick}
139
- slotProps={{
140
- root: ownerState => {
141
- return {
142
- className: twMerge(
143
- getOpacityClass(
144
- ownerState.selected,
145
- ownerState.disabled,
146
- orientation
147
- ),
148
- rootClassesByOrientation(ownerState.selected)[orientation],
149
- classesByVariant[variant],
150
- ownerState.disabled
151
- ? 'cursor-default text-gray-500'
152
- : 'cursor-pointer',
153
- ownerState.disabled && 'pointer-events-none',
154
- icon && isHorizontal && 'min-h-0 pt-[0.5625rem] pr-6',
155
- 'min-w-0 sm:min-w-[160px] md:min-w-[auto]',
156
- 'border-0 cursor-pointer inline-flex outline-none',
157
- 'items-center select-none align-middle appearance-none',
158
- 'justify-center no-underline [-webkit-tap-highlight-color:transparent]',
159
- 'normal-case whitespace-normal leading-4',
160
- 'relative ',
161
- className
162
- ),
163
- }
164
- },
165
- }}
166
- >
167
- <span
168
- className={twJoin('w-full', wrapperClassesByOrientation[orientation])}
169
- >
170
- {renderLabel}
171
- {icon && <span className='absolute right-0 mb-0 h-4'>{icon}</span>}
172
- </span>
173
- </MUITab>
174
- )
175
- })
176
-
177
- Tab.defaultProps = {}
178
-
179
- Tab.displayName = 'Tab'
180
-
181
- type GetLabelComponentProps = {
182
- avatar?: string | null
183
- description?: string
184
- disabled?: boolean
185
- label?: React.ReactNode
186
- orientation: 'horizontal' | 'vertical'
187
- titleCase?: boolean
188
- }
189
90
  const getLabelComponent = ({
190
91
  avatar,
191
92
  description,
@@ -193,14 +94,19 @@ const getLabelComponent = ({
193
94
  label,
194
95
  orientation,
195
96
  titleCase,
196
- }: GetLabelComponentProps): React.ReactNode => {
97
+ }: {
98
+ avatar?: string | null
99
+ description?: string
100
+ disabled?: boolean
101
+ label?: React.ReactNode
102
+ orientation: 'horizontal' | 'vertical'
103
+ titleCase?: boolean
104
+ }): React.ReactNode => {
197
105
  if (!label) {
198
106
  return null
199
107
  }
200
-
201
108
  const isHorizontal = orientation === 'horizontal'
202
109
  const isCustomLabel = typeof label !== 'string'
203
-
204
110
  const Label = () => (
205
111
  <TabLabel titleCase={titleCase} label={label} orientation={orientation} />
206
112
  )
@@ -208,7 +114,6 @@ const getLabelComponent = ({
208
114
  if (isHorizontal || isCustomLabel) {
209
115
  return <Label />
210
116
  }
211
-
212
117
  if (typeof avatar === 'undefined') {
213
118
  return (
214
119
  <>
@@ -229,4 +134,91 @@ const getLabelComponent = ({
229
134
  )
230
135
  }
231
136
 
137
+ // eslint-disable-next-line func-style
138
+ function TabInner<T = number>(props: TabProps<T>, ref: Ref<HTMLButtonElement>) {
139
+ const {
140
+ disabled,
141
+ value,
142
+ label,
143
+ icon,
144
+ titleCase: propsTitleCase,
145
+ description,
146
+ avatar,
147
+ className,
148
+ onClick,
149
+ ...rest
150
+ } = props
151
+ const titleCase = useTitleCase(propsTitleCase)
152
+ const {
153
+ value: selectedValue,
154
+ onChange,
155
+ orientation,
156
+ variant,
157
+ } = useTabsContext()
158
+ const isHorizontal = orientation === 'horizontal'
159
+ const selected = value === selectedValue
160
+
161
+ const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
162
+ if (!disabled && onChange) {
163
+ onChange(event, value as T)
164
+ }
165
+ onClick?.(event)
166
+ }
167
+
168
+ const renderLabel = getLabelComponent({
169
+ avatar,
170
+ description,
171
+ disabled,
172
+ label,
173
+ orientation,
174
+ titleCase,
175
+ })
176
+
177
+ return (
178
+ <button
179
+ className={twMerge(
180
+ getOpacityClass(selected, !!disabled, orientation),
181
+ rootClassesByOrientation(selected)[orientation],
182
+ classesByVariant[variant],
183
+ disabled ? 'cursor-default text-gray-500' : 'cursor-pointer',
184
+ disabled && 'pointer-events-none',
185
+ icon && isHorizontal && 'min-h-0 pt-0 pr-6',
186
+ 'min-w-0 sm:min-w-[160px] md:min-w-[auto]',
187
+ 'border-0 cursor-pointer inline-flex outline-none',
188
+ 'items-center select-none align-middle appearance-none',
189
+ 'justify-center no-underline [-webkit-tap-highlight-color:transparent]',
190
+ 'normal-case whitespace-normal leading-4',
191
+ 'relative ',
192
+ className
193
+ )}
194
+ ref={ref}
195
+ tabIndex={disabled ? -1 : 0}
196
+ disabled={disabled}
197
+ onClick={handleClick}
198
+ role='tab'
199
+ aria-selected={selected}
200
+ aria-disabled={disabled}
201
+ type='button'
202
+ {...rest}
203
+ >
204
+ <span
205
+ className={twJoin('w-full', wrapperClassesByOrientation[orientation])}
206
+ >
207
+ {renderLabel}
208
+ {icon && (
209
+ <span className='absolute top-0 right-0 mb-0 flex items-center'>
210
+ {icon}
211
+ </span>
212
+ )}
213
+ </span>
214
+ </button>
215
+ )
216
+ }
217
+
218
+ TabInner.displayName = 'Tab'
219
+
220
+ export const Tab = forwardRef(TabInner) as <T = number>(
221
+ props: TabProps<T> & { ref?: Ref<HTMLButtonElement> }
222
+ ) => ReactElement | null
223
+
232
224
  export default Tab
@@ -6,31 +6,29 @@ exports[`Tab Tab disabled tab 1`] = `
6
6
  class="Picasso-root"
7
7
  >
8
8
  <div
9
- class="MuiTabs-root Tabs-horizontal"
9
+ aria-orientation="horizontal"
10
+ class="relative min-h flex overflow-hidden overflow-x"
10
11
  data-component-type="tabs"
11
12
  >
12
13
  <div
13
- class="MuiTabs-scrollable"
14
- style="width: 99px; height: 99px; position: absolute; top: -9999px; overflow: scroll;"
15
- />
16
- <div
17
- class="MuiTabs-scroller MuiTabs-scrollable"
18
- style="margin-bottom: 0px;"
14
+ class="after:absolute after:content-[""] after:bottom-0 after:left-0 after:right-0 after:h-[1px] after:bg-gray after:z-0 flex-auto inline-block relative whitespace-nowrap"
19
15
  >
20
16
  <div
21
- class="MuiTabs-flexContainer"
17
+ class="flex"
22
18
  role="tablist"
19
+ tabindex="-1"
23
20
  >
24
21
  <button
22
+ aria-disabled="true"
25
23
  aria-selected="false"
26
- class="MuiButtonBase-root MuiTab-root PicassoTab-horizontal MuiTab-textColorInherit Mui-disabled Mui-disabled"
24
+ class="opacity-50 m-0 [&:not(:last-child)]:mr-8 pt-0 pb-[0.4375rem] px-0 text-center bg-transparent transition-shadow z-10 rounded-none shrink-0 max-w text-gray pointer-events min-w sm:min-w md:min-w border-0 cursor-pointer inline-flex outline-none items-center select-none align-middle appearance-none justify-center no-underline [-webkit-tap-highlight normal-case whitespace-normal leading-4 relative"
27
25
  disabled=""
28
26
  role="tab"
29
27
  tabindex="-1"
30
28
  type="button"
31
29
  >
32
30
  <span
33
- class="MuiTab-wrapper PicassoTab-wrapper"
31
+ class="w-full inline-flex flex-row items-center justify-center"
34
32
  >
35
33
  <div
36
34
  class="m-0 text-sm text-inherit font-semibold leading-[1.1rem]"
@@ -40,10 +38,6 @@ exports[`Tab Tab disabled tab 1`] = `
40
38
  </span>
41
39
  </button>
42
40
  </div>
43
- <span
44
- class="PrivateTabIndicator-root PrivateTabIndicator-colorSecondary MuiTabs-indicator"
45
- style="left: 0px; width: 0px;"
46
- />
47
41
  </div>
48
42
  </div>
49
43
  </div>
@@ -56,30 +50,27 @@ exports[`Tab Tab renders 1`] = `
56
50
  class="Picasso-root"
57
51
  >
58
52
  <div
59
- class="MuiTabs-root Tabs-horizontal"
53
+ aria-orientation="horizontal"
54
+ class="relative min-h flex overflow-hidden overflow-x"
60
55
  data-component-type="tabs"
61
56
  >
62
57
  <div
63
- class="MuiTabs-scrollable"
64
- style="width: 99px; height: 99px; position: absolute; top: -9999px; overflow: scroll;"
65
- />
66
- <div
67
- class="MuiTabs-scroller MuiTabs-scrollable"
68
- style="margin-bottom: 0px;"
58
+ class="after:absolute after:content-[""] after:bottom-0 after:left-0 after:right-0 after:h-[1px] after:bg-gray after:z-0 flex-auto inline-block relative whitespace-nowrap"
69
59
  >
70
60
  <div
71
- class="MuiTabs-flexContainer"
61
+ class="flex"
72
62
  role="tablist"
63
+ tabindex="-1"
73
64
  >
74
65
  <button
75
66
  aria-selected="false"
76
- class="MuiButtonBase-root MuiTab-root PicassoTab-horizontal MuiTab-textColorInherit"
67
+ class="opacity-70 m-0 [&:not(:last-child)]:mr-8 pt-0 pb-[0.4375rem] px-0 text-center bg-transparent transition-shadow z-10 rounded-none text-black shrink-0 max-w min-w sm:min-w md:min-w border-0 cursor-pointer inline-flex outline-none items-center select-none align-middle appearance-none justify-center no-underline [-webkit-tap-highlight normal-case whitespace-normal leading-4 relative"
77
68
  role="tab"
78
69
  tabindex="0"
79
70
  type="button"
80
71
  >
81
72
  <span
82
- class="MuiTab-wrapper PicassoTab-wrapper"
73
+ class="w-full inline-flex flex-row items-center justify-center"
83
74
  >
84
75
  <div
85
76
  class="m-0 text-sm text-inherit font-semibold leading-[1.1rem]"
@@ -89,10 +80,6 @@ exports[`Tab Tab renders 1`] = `
89
80
  </span>
90
81
  </button>
91
82
  </div>
92
- <span
93
- class="PrivateTabIndicator-root PrivateTabIndicator-colorSecondary MuiTabs-indicator"
94
- style="left: 0px; width: 0px;"
95
- />
96
83
  </div>
97
84
  </div>
98
85
  </div>
@@ -105,46 +92,43 @@ exports[`Tab Tab tab with icon 1`] = `
105
92
  class="Picasso-root"
106
93
  >
107
94
  <div
108
- class="MuiTabs-root Tabs-horizontal"
95
+ aria-orientation="horizontal"
96
+ class="relative min-h flex overflow-hidden overflow-x"
109
97
  data-component-type="tabs"
110
98
  >
111
99
  <div
112
- class="MuiTabs-scrollable"
113
- style="width: 99px; height: 99px; position: absolute; top: -9999px; overflow: scroll;"
114
- />
115
- <div
116
- class="MuiTabs-scroller MuiTabs-scrollable"
117
- style="margin-bottom: 0px;"
100
+ class="after:absolute after:content-[""] after:bottom-0 after:left-0 after:right-0 after:h-[1px] after:bg-gray after:z-0 flex-auto inline-block relative whitespace-nowrap"
118
101
  >
119
102
  <div
120
- class="MuiTabs-flexContainer"
103
+ class="flex"
121
104
  role="tablist"
105
+ tabindex="-1"
122
106
  >
123
107
  <button
124
108
  aria-selected="false"
125
- class="MuiButtonBase-root MuiTab-root PicassoTab-horizontal MuiTab-textColorInherit MuiTab-labelIcon"
109
+ class="opacity-70 m-0 [&:not(:last-child)]:mr-8 pb-[0.4375rem] px-0 text-center bg-transparent transition-shadow z-10 rounded-none text-black shrink-0 max-w min-h pt-0 pr-6 min-w sm:min-w md:min-w border-0 cursor-pointer inline-flex outline-none items-center select-none align-middle appearance-none justify-center no-underline [-webkit-tap-highlight normal-case whitespace-normal leading-4 relative"
126
110
  role="tab"
127
111
  tabindex="0"
128
112
  type="button"
129
113
  >
130
114
  <span
131
- class="MuiTab-wrapper PicassoTab-wrapper"
115
+ class="w-full inline-flex flex-row items-center justify-center"
132
116
  >
133
- <div
134
- id="Icon"
135
- />
136
117
  <div
137
118
  class="m-0 text-sm text-inherit font-semibold leading-[1.1rem]"
138
119
  >
139
120
  Tab Label
140
121
  </div>
122
+ <span
123
+ class="absolute top-0 right-0 mb-0 flex items-center"
124
+ >
125
+ <div
126
+ id="Icon"
127
+ />
128
+ </span>
141
129
  </span>
142
130
  </button>
143
131
  </div>
144
- <span
145
- class="PrivateTabIndicator-root PrivateTabIndicator-colorSecondary MuiTabs-indicator"
146
- style="left: 0px; width: 0px;"
147
- />
148
132
  </div>
149
133
  </div>
150
134
  </div>
package/src/Tab/index.ts CHANGED
@@ -1,6 +1 @@
1
- import type { OmitInternalProps } from '@toptal/picasso-shared'
2
-
3
- import type { Props } from './Tab'
4
-
5
- export { default as Tab } from './Tab'
6
- export type TabProps = OmitInternalProps<Props>
1
+ export { default as Tab, type TabProps } from './Tab'
@@ -2,10 +2,10 @@ import React from 'react'
2
2
  import { Container, Tabs } from '@toptal/picasso'
3
3
  import { SPACING_4 } from '@toptal/picasso-utils'
4
4
 
5
- type Value = number | string | null
5
+ type Value = 'jobs' | 'engagements' | 'interviews'
6
6
 
7
7
  const Example = () => {
8
- const [value, setValue] = React.useState<Value>(0)
8
+ const [value, setValue] = React.useState<Value>('engagements')
9
9
 
10
10
  const handleChange = (_: React.ChangeEvent<{}>, newValue: Value) => {
11
11
  setValue(newValue)
@@ -4,7 +4,7 @@ import { SPACING_4 } from '@toptal/picasso-utils'
4
4
  import { Exclamation16 } from '@toptal/picasso-icons'
5
5
 
6
6
  const Example = () => {
7
- const [value, setValue] = React.useState(0)
7
+ const [value, setValue] = React.useState<number>(0)
8
8
 
9
9
  const handleChange = (_: React.ChangeEvent<{}>, newValue: number) => {
10
10
  setValue(newValue)
@@ -17,9 +17,9 @@ const Example = () => {
17
17
  label='Label'
18
18
  icon={
19
19
  <Tooltip content='Some content...' placement='top'>
20
- <span>
20
+ <div>
21
21
  <Exclamation16 color='red' />
22
- </span>
22
+ </div>
23
23
  </Tooltip>
24
24
  }
25
25
  />