@toptal/picasso-tabs 5.0.15-alpha-ff-7-tabs-19babbfd6.8 → 5.0.15-alpha-ff-7-tabs-17eb872bb.13
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 +3 -6
- package/dist-package/src/Tab/Tab.d.ts.map +1 -1
- package/dist-package/src/Tab/Tab.js +15 -18
- package/dist-package/src/Tab/Tab.js.map +1 -1
- package/dist-package/src/Tabs/Tabs.d.ts +7 -7
- package/dist-package/src/Tabs/Tabs.d.ts.map +1 -1
- package/dist-package/src/Tabs/Tabs.js +29 -14
- package/dist-package/src/Tabs/Tabs.js.map +1 -1
- package/dist-package/src/Tabs/TabsContext.d.ts +11 -0
- package/dist-package/src/Tabs/TabsContext.d.ts.map +1 -0
- package/dist-package/src/Tabs/TabsContext.js +15 -0
- package/dist-package/src/Tabs/TabsContext.js.map +1 -0
- package/dist-package/src/Tabs/index.d.ts +3 -2
- package/dist-package/src/Tabs/index.d.ts.map +1 -1
- package/dist-package/src/Tabs/index.js.map +1 -1
- package/package.json +12 -13
- package/src/Tab/Tab.tsx +57 -65
- package/src/Tab/__snapshots__/test.tsx.snap +29 -45
- package/src/Tab/story/IconOrBadge.example.tsx +8 -3
- package/src/Tabs/Tabs.tsx +65 -33
- package/src/Tabs/TabsContext.tsx +27 -0
- package/src/Tabs/__snapshots__/test.tsx.snap +33 -49
- package/src/Tabs/index.ts +3 -2
- package/src/Tabs/story/Default.example.tsx +4 -2
@@ -1,15 +1,15 @@
|
|
1
1
|
import type { ReactNode, HTMLAttributes, ReactElement } from 'react';
|
2
2
|
import React from 'react';
|
3
|
-
import type { TabProps } from '@mui/base/Tab';
|
4
3
|
import type { BaseProps, TextLabelProps } from '@toptal/picasso-shared';
|
4
|
+
import { type TabsValueType } from '../Tabs/TabsContext';
|
5
5
|
export interface Props extends BaseProps, TextLabelProps, Omit<HTMLAttributes<HTMLButtonElement>, 'onChange'> {
|
6
6
|
/**
|
7
7
|
* If true, the tab will be disabled
|
8
8
|
* @default false
|
9
9
|
*/
|
10
10
|
disabled?: boolean;
|
11
|
-
/**
|
12
|
-
value?:
|
11
|
+
/** The value of the tab */
|
12
|
+
value?: TabsValueType;
|
13
13
|
/** The label element */
|
14
14
|
label?: ReactNode;
|
15
15
|
/** The Icon element */
|
@@ -18,9 +18,6 @@ export interface Props extends BaseProps, TextLabelProps, Omit<HTMLAttributes<HT
|
|
18
18
|
avatar?: string | null;
|
19
19
|
/** Description */
|
20
20
|
description?: string;
|
21
|
-
selected?: boolean;
|
22
|
-
onChange?: TabProps['onChange'];
|
23
|
-
onClick?: TabProps['onClick'];
|
24
21
|
}
|
25
22
|
export declare const Tab: React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLButtonElement>>;
|
26
23
|
export default Tab;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"Tab.d.ts","sourceRoot":"","sources":["../../../src/Tab/Tab.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,OAAO,CAAA;AACpE,OAAO,
|
1
|
+
{"version":3,"file":"Tab.d.ts","sourceRoot":"","sources":["../../../src/Tab/Tab.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,OAAO,CAAA;AACpE,OAAO,KAAqB,MAAM,OAAO,CAAA;AACzC,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAKvE,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAIxE,MAAM,WAAW,KACf,SAAQ,SAAS,EACf,cAAc,EACd,IAAI,CAAC,cAAc,CAAC,iBAAiB,CAAC,EAAE,UAAU,CAAC;IACrD;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAElB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,aAAa,CAAA;IAErB,wBAAwB;IACxB,KAAK,CAAC,EAAE,SAAS,CAAA;IAEjB,uBAAuB;IACvB,IAAI,CAAC,EAAE,YAAY,CAAA;IAEnB,gBAAgB;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAEtB,kBAAkB;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;CAOrB;AAsDD,eAAO,MAAM,GAAG,iFA6Ed,CAAA;AAmDF,eAAe,GAAG,CAAA"}
|
@@ -9,12 +9,11 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
9
9
|
}
|
10
10
|
return t;
|
11
11
|
};
|
12
|
-
import React, { forwardRef
|
13
|
-
import { Tab as MUITab } from '@mui/base/Tab';
|
12
|
+
import React, { forwardRef } from 'react';
|
14
13
|
import { useTitleCase } from '@toptal/picasso-shared';
|
15
14
|
import { UserBadge } from '@toptal/picasso-user-badge';
|
16
15
|
import { twJoin, twMerge } from '@toptal/picasso-tailwind-merge';
|
17
|
-
import {
|
16
|
+
import { useTabsContext } from '../Tabs/TabsContext';
|
18
17
|
import { TabLabel } from '../TabLabel';
|
19
18
|
import { TabDescription } from '../TabDescription';
|
20
19
|
const getOpacityClass = (selected, disabled, orientation) => {
|
@@ -27,12 +26,12 @@ const getOpacityClass = (selected, disabled, orientation) => {
|
|
27
26
|
return 'opacity-70';
|
28
27
|
};
|
29
28
|
const wrapperClassesByOrientation = {
|
30
|
-
horizontal: 'inline-flex items-center
|
29
|
+
horizontal: 'inline-flex flex-row items-center justify-center',
|
31
30
|
vertical: 'block',
|
32
31
|
};
|
33
32
|
const rootClassesByOrientation = (selected) => ({
|
34
33
|
horizontal: [
|
35
|
-
'm-0 [&:not(:last-child)]:mr-8 pt-
|
34
|
+
'm-0 [&:not(:last-child)]:mr-8 pt-0 pb-[0.4375rem] px-0',
|
36
35
|
'text-center bg-transparent transition-shadow z-10 rounded-none',
|
37
36
|
'text-black',
|
38
37
|
selected && 'shadow-blue-500 shadow-[inset_0_-2px_0]',
|
@@ -61,10 +60,17 @@ const classesByVariant = {
|
|
61
60
|
fullWidth: 'shrink flex-grow basis-0',
|
62
61
|
};
|
63
62
|
export const Tab = forwardRef(function Tab(props, ref) {
|
64
|
-
const { disabled, value, label, icon,
|
63
|
+
const { disabled, value, label, icon, titleCase: propsTitleCase, description, avatar, className, onClick } = props, rest = __rest(props, ["disabled", "value", "label", "icon", "titleCase", "description", "avatar", "className", "onClick"]);
|
65
64
|
const titleCase = useTitleCase(propsTitleCase);
|
66
|
-
const { orientation, variant } =
|
65
|
+
const { value: selectedValue, onChange, orientation, variant, } = useTabsContext();
|
67
66
|
const isHorizontal = orientation === 'horizontal';
|
67
|
+
const selected = value === selectedValue;
|
68
|
+
const handleClick = (event) => {
|
69
|
+
if (!disabled && onChange) {
|
70
|
+
onChange(event, value);
|
71
|
+
}
|
72
|
+
onClick === null || onClick === void 0 ? void 0 : onClick(event);
|
73
|
+
};
|
68
74
|
const renderLabel = getLabelComponent({
|
69
75
|
avatar,
|
70
76
|
description,
|
@@ -73,20 +79,11 @@ export const Tab = forwardRef(function Tab(props, ref) {
|
|
73
79
|
orientation,
|
74
80
|
titleCase,
|
75
81
|
});
|
76
|
-
return (React.createElement(
|
77
|
-
root: ownerState => {
|
78
|
-
return {
|
79
|
-
className: twMerge(getOpacityClass(ownerState.selected, ownerState.disabled, orientation), rootClassesByOrientation(ownerState.selected)[orientation], classesByVariant[variant], ownerState.disabled
|
80
|
-
? 'cursor-default text-gray-500'
|
81
|
-
: 'cursor-pointer', ownerState.disabled && 'pointer-events-none', icon && isHorizontal && 'min-h-0 pt-[0.5625rem] pr-6', 'min-w-0 sm:min-w-[160px] md:min-w-[auto]', 'border-0 cursor-pointer inline-flex outline-none', 'items-center select-none align-middle appearance-none', 'justify-center no-underline [-webkit-tap-highlight-color:transparent]', 'normal-case whitespace-normal leading-4', 'relative ', className),
|
82
|
-
};
|
83
|
-
},
|
84
|
-
} }),
|
82
|
+
return (React.createElement("button", Object.assign({ className: twMerge(getOpacityClass(selected, !!disabled, orientation), rootClassesByOrientation(selected)[orientation], classesByVariant[variant], disabled ? 'cursor-default text-gray-500' : 'cursor-pointer', disabled && 'pointer-events-none', icon && isHorizontal && 'min-h-0 pt-0 pr-6', 'min-w-0 sm:min-w-[160px] md:min-w-[auto]', 'border-0 cursor-pointer inline-flex outline-none', 'items-center select-none align-middle appearance-none', 'justify-center no-underline [-webkit-tap-highlight-color:transparent]', 'normal-case whitespace-normal leading-4', 'relative ', className), ref: ref, tabIndex: disabled ? -1 : 0, disabled: disabled, onClick: handleClick, role: 'tab', "aria-selected": selected, "aria-disabled": disabled, type: 'button' }, rest),
|
85
83
|
React.createElement("span", { className: twJoin('w-full', wrapperClassesByOrientation[orientation]) },
|
86
84
|
renderLabel,
|
87
|
-
icon && React.createElement("span", { className: 'absolute right-0 mb-0
|
85
|
+
icon && React.createElement("span", { className: 'absolute right-0 mb-0' }, icon))));
|
88
86
|
});
|
89
|
-
Tab.defaultProps = {};
|
90
87
|
Tab.displayName = 'Tab';
|
91
88
|
const getLabelComponent = ({ avatar, description, disabled, label, orientation, titleCase, }) => {
|
92
89
|
if (!label) {
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"Tab.js","sourceRoot":"","sources":["../../../src/Tab/Tab.tsx"],"names":[],"mappings":";;;;;;;;;;;AACA,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,
|
1
|
+
{"version":3,"file":"Tab.js","sourceRoot":"","sources":["../../../src/Tab/Tab.tsx"],"names":[],"mappings":"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"}
|
@@ -1,12 +1,12 @@
|
|
1
|
-
import type { ReactNode } from 'react';
|
1
|
+
import type { ReactNode, ChangeEvent } from 'react';
|
2
2
|
import React from 'react';
|
3
3
|
import type { BaseProps } from '@toptal/picasso-shared';
|
4
|
-
|
4
|
+
import { type TabsValueType } from './TabsContext';
|
5
5
|
export interface Props<V extends TabsValueType> extends BaseProps {
|
6
6
|
/** Tabs content containing Tab components */
|
7
7
|
children: ReactNode;
|
8
8
|
/** Callback fired when the value changes. */
|
9
|
-
onChange?: (event:
|
9
|
+
onChange?: (event: ChangeEvent<{}>, value: V) => void;
|
10
10
|
/**
|
11
11
|
* The value of the currently selected Tab.
|
12
12
|
* If you don't want any selected Tab, you can set this property to null.
|
@@ -16,11 +16,11 @@ export interface Props<V extends TabsValueType> extends BaseProps {
|
|
16
16
|
orientation?: 'horizontal' | 'vertical';
|
17
17
|
/** Determines additional display behavior of the tabs */
|
18
18
|
variant?: 'scrollable' | 'fullWidth';
|
19
|
+
/** The default value. Use when the component is not controlled. */
|
20
|
+
defaultValue?: V;
|
21
|
+
/** The direction of the text. */
|
22
|
+
direction?: 'ltr' | 'rtl';
|
19
23
|
}
|
20
|
-
export declare const TabsContext: React.Context<{
|
21
|
-
orientation: 'horizontal' | 'vertical';
|
22
|
-
variant: 'scrollable' | 'fullWidth';
|
23
|
-
}>;
|
24
24
|
export declare const Tabs: React.ForwardRefExoticComponent<Props<TabsValueType> & React.RefAttributes<HTMLDivElement>>;
|
25
25
|
export default Tabs;
|
26
26
|
//# sourceMappingURL=Tabs.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../src/Tabs/Tabs.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;
|
1
|
+
{"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../src/Tabs/Tabs.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AACnD,OAAO,KAA2C,MAAM,OAAO,CAAA;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAGvD,OAAO,EAAe,KAAK,aAAa,EAAE,MAAM,eAAe,CAAA;AAE/D,MAAM,WAAW,KAAK,CAAC,CAAC,SAAS,aAAa,CAAE,SAAQ,SAAS;IAC/D,6CAA6C;IAC7C,QAAQ,EAAE,SAAS,CAAA;IAEnB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAA;IAErD;;;OAGG;IACH,KAAK,EAAE,CAAC,CAAA;IAER,oDAAoD;IACpD,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAA;IAEvC,yDAAyD;IACzD,OAAO,CAAC,EAAE,YAAY,GAAG,WAAW,CAAA;IAEpC,mEAAmE;IACnE,YAAY,CAAC,EAAE,CAAC,CAAA;IAEhB,iCAAiC;IACjC,SAAS,CAAC,EAAE,KAAK,GAAG,KAAK,CAAA;CAC1B;AAmCD,eAAO,MAAM,IAAI,6FA2FhB,CAAA;AAID,eAAe,IAAI,CAAA"}
|
@@ -9,11 +9,9 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
9
9
|
}
|
10
10
|
return t;
|
11
11
|
};
|
12
|
-
import React, { forwardRef, useMemo } from 'react';
|
13
|
-
import { Tabs as MUITabs } from '@mui/base/Tabs';
|
14
|
-
import { TabsList } from '@mui/base/TabsList';
|
12
|
+
import React, { forwardRef, useMemo, useCallback } from 'react';
|
15
13
|
import { twJoin, twMerge } from '@toptal/picasso-tailwind-merge';
|
16
|
-
|
14
|
+
import { TabsContext } from './TabsContext';
|
17
15
|
const indicatorClasses = [
|
18
16
|
'after:absolute',
|
19
17
|
'after:content-[""]',
|
@@ -44,23 +42,40 @@ const classesByVariant = {
|
|
44
42
|
scroller: 'w-full overflow-hidden',
|
45
43
|
},
|
46
44
|
};
|
47
|
-
// eslint-disable-next-line react/display-name
|
48
45
|
export const Tabs = forwardRef(function Tabs(props, ref) {
|
49
|
-
const { children, orientation = 'horizontal', onChange, value, variant = 'scrollable', className } = props, rest = __rest(props, ["children", "orientation", "onChange", "value", "variant", "className"]);
|
46
|
+
const { children, orientation = 'horizontal', onChange, value: valueProp, defaultValue, variant = 'scrollable', direction = 'ltr', className } = props, rest = __rest(props, ["children", "orientation", "onChange", "value", "defaultValue", "variant", "direction", "className"]);
|
47
|
+
const [value, setValue] = React.useState(defaultValue !== null && defaultValue !== void 0 ? defaultValue : null);
|
48
|
+
const isControlled = valueProp !== undefined;
|
49
|
+
const currentValue = isControlled ? valueProp : value;
|
50
|
+
const handleChange = useCallback((event, newValue) => {
|
51
|
+
if (!isControlled) {
|
52
|
+
setValue(newValue);
|
53
|
+
}
|
54
|
+
onChange === null || onChange === void 0 ? void 0 : onChange(event, newValue);
|
55
|
+
}, [isControlled, onChange]);
|
50
56
|
const contextValue = useMemo(() => ({
|
57
|
+
value: currentValue,
|
58
|
+
onChange: handleChange,
|
51
59
|
orientation,
|
52
60
|
variant,
|
53
|
-
|
61
|
+
direction,
|
62
|
+
}), [currentValue, handleChange, orientation, variant, direction]);
|
54
63
|
const isVertical = orientation === 'vertical';
|
64
|
+
const childrenWithIndex = React.Children.map(children, (child, idx) => {
|
65
|
+
if (React.isValidElement(child) &&
|
66
|
+
// @ts-expect-error: type check for Picasso Tab
|
67
|
+
(child.type.displayName === 'Tab' || child.type.name === 'Tab') &&
|
68
|
+
child.props.value === undefined) {
|
69
|
+
return React.cloneElement(child, {
|
70
|
+
value: idx,
|
71
|
+
});
|
72
|
+
}
|
73
|
+
return child;
|
74
|
+
});
|
55
75
|
return (React.createElement(TabsContext.Provider, { value: contextValue },
|
56
|
-
React.createElement(
|
57
|
-
root: {
|
58
|
-
ref,
|
59
|
-
className: twMerge('relative min-h-0 flex overflow-hidden', classesByOrientation[orientation].root, classesByVariant[variant].root, className),
|
60
|
-
},
|
61
|
-
}, onChange: onChange, value: value, orientation: orientation }),
|
76
|
+
React.createElement("div", Object.assign({}, rest, { ref: ref, "data-component-type": 'tabs', className: twMerge('relative min-h-0 flex overflow-hidden', classesByOrientation[orientation].root, classesByVariant[variant].root, className), "aria-orientation": orientation }),
|
62
77
|
React.createElement("div", { className: twJoin(classesByVariant[variant].scroller, classesByOrientation[orientation].scroller, 'flex-auto inline-block relative whitespace-nowrap') },
|
63
|
-
React.createElement(
|
78
|
+
React.createElement("div", { className: twJoin('flex', isVertical && 'flex-col'), role: 'tablist', tabIndex: -1 }, childrenWithIndex)))));
|
64
79
|
});
|
65
80
|
Tabs.displayName = 'Tabs';
|
66
81
|
export default Tabs;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"Tabs.js","sourceRoot":"","sources":["../../../src/Tabs/Tabs.tsx"],"names":[],"mappings":";;;;;;;;;;;AACA,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,
|
1
|
+
{"version":3,"file":"Tabs.js","sourceRoot":"","sources":["../../../src/Tabs/Tabs.tsx"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
export declare type TabsValueType = string | number | null;
|
3
|
+
export interface TabsContextValue {
|
4
|
+
value: TabsValueType;
|
5
|
+
onChange: (event: React.ChangeEvent<{}>, value: TabsValueType) => void;
|
6
|
+
orientation: 'horizontal' | 'vertical';
|
7
|
+
variant: 'scrollable' | 'fullWidth';
|
8
|
+
}
|
9
|
+
export declare const TabsContext: React.Context<TabsContextValue>;
|
10
|
+
export declare const useTabsContext: () => TabsContextValue;
|
11
|
+
//# sourceMappingURL=TabsContext.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"TabsContext.d.ts","sourceRoot":"","sources":["../../../src/Tabs/TabsContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,oBAAY,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;AAElD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,aAAa,CAAA;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IACtE,WAAW,EAAE,YAAY,GAAG,UAAU,CAAA;IACtC,OAAO,EAAE,YAAY,GAAG,WAAW,CAAA;CACpC;AAED,eAAO,MAAM,WAAW,iCAKtB,CAAA;AAEF,eAAO,MAAM,cAAc,wBAQ1B,CAAA"}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
export const TabsContext = React.createContext({
|
3
|
+
value: null,
|
4
|
+
onChange: () => { },
|
5
|
+
orientation: 'horizontal',
|
6
|
+
variant: 'scrollable',
|
7
|
+
});
|
8
|
+
export const useTabsContext = () => {
|
9
|
+
const context = React.useContext(TabsContext);
|
10
|
+
if (!context) {
|
11
|
+
throw new Error('useTabsContext must be used within a TabsProvider');
|
12
|
+
}
|
13
|
+
return context;
|
14
|
+
};
|
15
|
+
//# sourceMappingURL=TabsContext.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"TabsContext.js","sourceRoot":"","sources":["../../../src/Tabs/TabsContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAWzB,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC,aAAa,CAAmB;IAC/D,KAAK,EAAE,IAAI;IACX,QAAQ,EAAE,GAAG,EAAE,GAAE,CAAC;IAClB,WAAW,EAAE,YAAY;IACzB,OAAO,EAAE,YAAY;CACtB,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,EAAE;IACjC,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,CAAA;IAE7C,IAAI,CAAC,OAAO,EAAE;QACZ,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;KACrE;IAED,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA"}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import type { OmitInternalProps } from '@toptal/picasso-shared';
|
2
|
-
import type { Props
|
2
|
+
import type { Props } from './Tabs';
|
3
|
+
import type { TabsValueType } from './TabsContext';
|
3
4
|
export { default as Tabs } from './Tabs';
|
4
5
|
export declare type TabsProps = OmitInternalProps<Props<TabsValueType>>;
|
5
|
-
export type { TabsValueType } from './
|
6
|
+
export type { TabsValueType } from './TabsContext';
|
6
7
|
//# sourceMappingURL=index.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/Tabs/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE/D,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/Tabs/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE/D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAElD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAA;AACxC,oBAAY,SAAS,GAAG,iBAAiB,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAA;AAC/D,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/Tabs/index.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/Tabs/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAA"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@toptal/picasso-tabs",
|
3
|
-
"version": "5.0.15-alpha-ff-7-tabs-
|
3
|
+
"version": "5.0.15-alpha-ff-7-tabs-17eb872bb.13+17eb872bb",
|
4
4
|
"description": "Toptal UI components library - Tabs",
|
5
5
|
"publishConfig": {
|
6
6
|
"access": "public"
|
@@ -22,14 +22,13 @@
|
|
22
22
|
},
|
23
23
|
"homepage": "https://github.com/toptal/picasso/tree/master/packages/picasso#readme",
|
24
24
|
"dependencies": {
|
25
|
-
"@
|
26
|
-
"@toptal/picasso-
|
27
|
-
"@toptal/picasso-
|
28
|
-
"@toptal/picasso-
|
29
|
-
"@toptal/picasso-typography": "4.0.4-alpha-ff-7-tabs-
|
30
|
-
"@toptal/picasso-
|
31
|
-
"@toptal/picasso-
|
32
|
-
"@toptal/picasso-utils": "3.1.1-alpha-ff-7-tabs-19babbfd6.8+19babbfd6",
|
25
|
+
"@toptal/picasso-container": "3.1.3-alpha-ff-7-tabs-17eb872bb.13+17eb872bb",
|
26
|
+
"@toptal/picasso-icons": "1.12.2-alpha-ff-7-tabs-17eb872bb.13+17eb872bb",
|
27
|
+
"@toptal/picasso-shared": "15.0.1-alpha-ff-7-tabs-17eb872bb.359+17eb872bb",
|
28
|
+
"@toptal/picasso-typography": "4.0.4-alpha-ff-7-tabs-17eb872bb.13+17eb872bb",
|
29
|
+
"@toptal/picasso-typography-overflow": "4.0.4-alpha-ff-7-tabs-17eb872bb.13+17eb872bb",
|
30
|
+
"@toptal/picasso-user-badge": "5.1.12-alpha-ff-7-tabs-17eb872bb.13+17eb872bb",
|
31
|
+
"@toptal/picasso-utils": "3.1.1-alpha-ff-7-tabs-17eb872bb.13+17eb872bb",
|
33
32
|
"ap-style-title-case": "^1.1.2"
|
34
33
|
},
|
35
34
|
"sideEffects": [
|
@@ -46,14 +45,14 @@
|
|
46
45
|
".": "./dist-package/src/index.js"
|
47
46
|
},
|
48
47
|
"devDependencies": {
|
49
|
-
"@toptal/picasso-provider": "5.0.1-alpha-ff-7-tabs-
|
50
|
-
"@toptal/picasso-tailwind-merge": "2.0.4-alpha-ff-7-tabs-
|
51
|
-
"@toptal/picasso-test-utils": "1.1.2-alpha-ff-7-tabs-
|
48
|
+
"@toptal/picasso-provider": "5.0.1-alpha-ff-7-tabs-17eb872bb.280+17eb872bb",
|
49
|
+
"@toptal/picasso-tailwind-merge": "2.0.4-alpha-ff-7-tabs-17eb872bb.13+17eb872bb",
|
50
|
+
"@toptal/picasso-test-utils": "1.1.2-alpha-ff-7-tabs-17eb872bb.359+17eb872bb"
|
52
51
|
},
|
53
52
|
"files": [
|
54
53
|
"dist-package/**",
|
55
54
|
"!dist-package/tsconfig.tsbuildinfo",
|
56
55
|
"src"
|
57
56
|
],
|
58
|
-
"gitHead": "
|
57
|
+
"gitHead": "17eb872bb0410897243666d7cc7a58eb1479ed78"
|
59
58
|
}
|
package/src/Tab/Tab.tsx
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
import type { ReactNode, HTMLAttributes, ReactElement } from 'react'
|
2
|
-
import React, { forwardRef
|
3
|
-
import type { TabProps } from '@mui/base/Tab'
|
4
|
-
import { Tab as MUITab } from '@mui/base/Tab'
|
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 {
|
8
|
+
import { useTabsContext, type TabsValueType } from '../Tabs/TabsContext'
|
11
9
|
import { TabLabel } from '../TabLabel'
|
12
10
|
import { TabDescription } from '../TabDescription'
|
13
11
|
|
@@ -21,8 +19,8 @@ export interface Props
|
|
21
19
|
*/
|
22
20
|
disabled?: boolean
|
23
21
|
|
24
|
-
/**
|
25
|
-
value?:
|
22
|
+
/** The value of the tab */
|
23
|
+
value?: TabsValueType
|
26
24
|
|
27
25
|
/** The label element */
|
28
26
|
label?: ReactNode
|
@@ -38,9 +36,9 @@ export interface Props
|
|
38
36
|
|
39
37
|
// Properties below are managed by Tabs component
|
40
38
|
|
41
|
-
selected?: boolean
|
42
|
-
onChange?: TabProps['onChange']
|
43
|
-
onClick?: TabProps['onClick']
|
39
|
+
// selected?: boolean
|
40
|
+
// onChange?: TabProps['onChange']
|
41
|
+
// onClick?: TabProps['onClick']
|
44
42
|
}
|
45
43
|
|
46
44
|
const getOpacityClass = (
|
@@ -51,7 +49,6 @@ const getOpacityClass = (
|
|
51
49
|
if (disabled) {
|
52
50
|
return 'opacity-50'
|
53
51
|
}
|
54
|
-
|
55
52
|
if (selected || orientation === 'vertical') {
|
56
53
|
return 'opacity-100 '
|
57
54
|
}
|
@@ -60,13 +57,13 @@ const getOpacityClass = (
|
|
60
57
|
}
|
61
58
|
|
62
59
|
const wrapperClassesByOrientation = {
|
63
|
-
horizontal: 'inline-flex items-center
|
60
|
+
horizontal: 'inline-flex flex-row items-center justify-center',
|
64
61
|
vertical: 'block',
|
65
62
|
}
|
66
63
|
|
67
64
|
const rootClassesByOrientation = (selected: boolean) => ({
|
68
65
|
horizontal: [
|
69
|
-
'm-0 [&:not(:last-child)]:mr-8 pt-
|
66
|
+
'm-0 [&:not(:last-child)]:mr-8 pt-0 pb-[0.4375rem] px-0',
|
70
67
|
'text-center bg-transparent transition-shadow z-10 rounded-none',
|
71
68
|
'text-black',
|
72
69
|
selected && 'shadow-blue-500 shadow-[inset_0_-2px_0]',
|
@@ -105,17 +102,29 @@ export const Tab = forwardRef<HTMLButtonElement, Props>(function Tab(
|
|
105
102
|
value,
|
106
103
|
label,
|
107
104
|
icon,
|
108
|
-
onChange,
|
109
|
-
onClick,
|
110
105
|
titleCase: propsTitleCase,
|
111
106
|
description,
|
112
107
|
avatar,
|
113
108
|
className,
|
109
|
+
onClick,
|
114
110
|
...rest
|
115
111
|
} = props
|
116
112
|
const titleCase = useTitleCase(propsTitleCase)
|
117
|
-
const {
|
113
|
+
const {
|
114
|
+
value: selectedValue,
|
115
|
+
onChange,
|
116
|
+
orientation,
|
117
|
+
variant,
|
118
|
+
} = useTabsContext()
|
118
119
|
const isHorizontal = orientation === 'horizontal'
|
120
|
+
const selected = value === selectedValue
|
121
|
+
|
122
|
+
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
123
|
+
if (!disabled && onChange) {
|
124
|
+
onChange(event, value as TabsValueType)
|
125
|
+
}
|
126
|
+
onClick?.(event)
|
127
|
+
}
|
119
128
|
|
120
129
|
const renderLabel = getLabelComponent({
|
121
130
|
avatar,
|
@@ -127,65 +136,44 @@ export const Tab = forwardRef<HTMLButtonElement, Props>(function Tab(
|
|
127
136
|
})
|
128
137
|
|
129
138
|
return (
|
130
|
-
<
|
131
|
-
className=
|
132
|
-
|
139
|
+
<button
|
140
|
+
className={twMerge(
|
141
|
+
getOpacityClass(selected, !!disabled, orientation),
|
142
|
+
rootClassesByOrientation(selected)[orientation],
|
143
|
+
classesByVariant[variant],
|
144
|
+
disabled ? 'cursor-default text-gray-500' : 'cursor-pointer',
|
145
|
+
disabled && 'pointer-events-none',
|
146
|
+
icon && isHorizontal && 'min-h-0 pt-0 pr-6',
|
147
|
+
'min-w-0 sm:min-w-[160px] md:min-w-[auto]',
|
148
|
+
'border-0 cursor-pointer inline-flex outline-none',
|
149
|
+
'items-center select-none align-middle appearance-none',
|
150
|
+
'justify-center no-underline [-webkit-tap-highlight-color:transparent]',
|
151
|
+
'normal-case whitespace-normal leading-4',
|
152
|
+
'relative ',
|
153
|
+
className
|
154
|
+
)}
|
133
155
|
ref={ref}
|
134
|
-
tabIndex={0}
|
156
|
+
tabIndex={disabled ? -1 : 0}
|
135
157
|
disabled={disabled}
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
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
|
-
}}
|
158
|
+
onClick={handleClick}
|
159
|
+
role='tab'
|
160
|
+
aria-selected={selected}
|
161
|
+
aria-disabled={disabled}
|
162
|
+
type='button'
|
163
|
+
{...rest}
|
166
164
|
>
|
167
165
|
<span
|
168
166
|
className={twJoin('w-full', wrapperClassesByOrientation[orientation])}
|
169
167
|
>
|
170
168
|
{renderLabel}
|
171
|
-
{icon && <span className='absolute right-0 mb-0
|
169
|
+
{icon && <span className='absolute right-0 mb-0'>{icon}</span>}
|
172
170
|
</span>
|
173
|
-
</
|
171
|
+
</button>
|
174
172
|
)
|
175
173
|
})
|
176
174
|
|
177
|
-
Tab.defaultProps = {}
|
178
|
-
|
179
175
|
Tab.displayName = 'Tab'
|
180
176
|
|
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
177
|
const getLabelComponent = ({
|
190
178
|
avatar,
|
191
179
|
description,
|
@@ -193,14 +181,19 @@ const getLabelComponent = ({
|
|
193
181
|
label,
|
194
182
|
orientation,
|
195
183
|
titleCase,
|
196
|
-
}:
|
184
|
+
}: {
|
185
|
+
avatar?: string | null
|
186
|
+
description?: string
|
187
|
+
disabled?: boolean
|
188
|
+
label?: React.ReactNode
|
189
|
+
orientation: 'horizontal' | 'vertical'
|
190
|
+
titleCase?: boolean
|
191
|
+
}): React.ReactNode => {
|
197
192
|
if (!label) {
|
198
193
|
return null
|
199
194
|
}
|
200
|
-
|
201
195
|
const isHorizontal = orientation === 'horizontal'
|
202
196
|
const isCustomLabel = typeof label !== 'string'
|
203
|
-
|
204
197
|
const Label = () => (
|
205
198
|
<TabLabel titleCase={titleCase} label={label} orientation={orientation} />
|
206
199
|
)
|
@@ -208,7 +201,6 @@ const getLabelComponent = ({
|
|
208
201
|
if (isHorizontal || isCustomLabel) {
|
209
202
|
return <Label />
|
210
203
|
}
|
211
|
-
|
212
204
|
if (typeof avatar === 'undefined') {
|
213
205
|
return (
|
214
206
|
<>
|
@@ -6,31 +6,29 @@ exports[`Tab Tab disabled tab 1`] = `
|
|
6
6
|
class="Picasso-root"
|
7
7
|
>
|
8
8
|
<div
|
9
|
-
|
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="
|
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="
|
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="
|
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="
|
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
|
-
|
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="
|
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="
|
61
|
+
class="flex"
|
72
62
|
role="tablist"
|
63
|
+
tabindex="-1"
|
73
64
|
>
|
74
65
|
<button
|
75
66
|
aria-selected="false"
|
76
|
-
class="
|
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="
|
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
|
-
|
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="
|
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="
|
103
|
+
class="flex"
|
121
104
|
role="tablist"
|
105
|
+
tabindex="-1"
|
122
106
|
>
|
123
107
|
<button
|
124
108
|
aria-selected="false"
|
125
|
-
class="
|
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="
|
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 right-0 mb-0"
|
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>
|
@@ -3,10 +3,12 @@ import { Container, Tabs, Tooltip, Badge } from '@toptal/picasso'
|
|
3
3
|
import { SPACING_4 } from '@toptal/picasso-utils'
|
4
4
|
import { Exclamation16 } from '@toptal/picasso-icons'
|
5
5
|
|
6
|
+
import type { TabsValueType } from '../../Tabs/TabsContext'
|
7
|
+
|
6
8
|
const Example = () => {
|
7
|
-
const [value, setValue] = React.useState(0)
|
9
|
+
const [value, setValue] = React.useState<TabsValueType>(0)
|
8
10
|
|
9
|
-
const handleChange = (_: React.ChangeEvent<{}>, newValue:
|
11
|
+
const handleChange = (_: React.ChangeEvent<{}>, newValue: TabsValueType) => {
|
10
12
|
setValue(newValue)
|
11
13
|
}
|
12
14
|
|
@@ -24,7 +26,10 @@ const Example = () => {
|
|
24
26
|
}
|
25
27
|
/>
|
26
28
|
<Tabs.Tab label='Label' />
|
27
|
-
<Tabs.Tab
|
29
|
+
<Tabs.Tab
|
30
|
+
label='Label'
|
31
|
+
icon={<Badge content={10} variant='white' className='mt-[1px]' />}
|
32
|
+
/>
|
28
33
|
</Tabs>
|
29
34
|
|
30
35
|
{value === 0 && (
|
package/src/Tabs/Tabs.tsx
CHANGED
@@ -1,18 +1,16 @@
|
|
1
|
-
import type { ReactNode } from 'react'
|
2
|
-
import React, { forwardRef, useMemo } from 'react'
|
3
|
-
import { Tabs as MUITabs } from '@mui/base/Tabs'
|
4
|
-
import { TabsList } from '@mui/base/TabsList'
|
1
|
+
import type { ReactNode, ChangeEvent } from 'react'
|
2
|
+
import React, { forwardRef, useMemo, useCallback } from 'react'
|
5
3
|
import type { BaseProps } from '@toptal/picasso-shared'
|
6
4
|
import { twJoin, twMerge } from '@toptal/picasso-tailwind-merge'
|
7
5
|
|
8
|
-
|
6
|
+
import { TabsContext, type TabsValueType } from './TabsContext'
|
9
7
|
|
10
8
|
export interface Props<V extends TabsValueType> extends BaseProps {
|
11
9
|
/** Tabs content containing Tab components */
|
12
10
|
children: ReactNode
|
13
11
|
|
14
12
|
/** Callback fired when the value changes. */
|
15
|
-
onChange?: (event:
|
13
|
+
onChange?: (event: ChangeEvent<{}>, value: V) => void
|
16
14
|
|
17
15
|
/**
|
18
16
|
* The value of the currently selected Tab.
|
@@ -25,12 +23,13 @@ export interface Props<V extends TabsValueType> extends BaseProps {
|
|
25
23
|
|
26
24
|
/** Determines additional display behavior of the tabs */
|
27
25
|
variant?: 'scrollable' | 'fullWidth'
|
28
|
-
}
|
29
26
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
27
|
+
/** The default value. Use when the component is not controlled. */
|
28
|
+
defaultValue?: V
|
29
|
+
|
30
|
+
/** The direction of the text. */
|
31
|
+
direction?: 'ltr' | 'rtl'
|
32
|
+
}
|
34
33
|
|
35
34
|
const indicatorClasses = [
|
36
35
|
'after:absolute',
|
@@ -65,48 +64,77 @@ const classesByVariant = {
|
|
65
64
|
},
|
66
65
|
}
|
67
66
|
|
68
|
-
// eslint-disable-next-line react/display-name
|
69
67
|
export const Tabs = forwardRef<HTMLDivElement, Props<TabsValueType>>(
|
70
68
|
function Tabs(props, ref) {
|
71
69
|
const {
|
72
70
|
children,
|
73
71
|
orientation = 'horizontal',
|
74
72
|
onChange,
|
75
|
-
value,
|
73
|
+
value: valueProp,
|
74
|
+
defaultValue,
|
76
75
|
variant = 'scrollable',
|
76
|
+
direction = 'ltr',
|
77
77
|
className,
|
78
78
|
...rest
|
79
79
|
} = props
|
80
80
|
|
81
|
+
const [value, setValue] = React.useState<TabsValueType>(
|
82
|
+
defaultValue ?? null
|
83
|
+
)
|
84
|
+
const isControlled = valueProp !== undefined
|
85
|
+
const currentValue = isControlled ? valueProp : value
|
86
|
+
|
87
|
+
const handleChange = useCallback(
|
88
|
+
(event: ChangeEvent<{}>, newValue: TabsValueType) => {
|
89
|
+
if (!isControlled) {
|
90
|
+
setValue(newValue)
|
91
|
+
}
|
92
|
+
onChange?.(event, newValue as TabsValueType)
|
93
|
+
},
|
94
|
+
[isControlled, onChange]
|
95
|
+
)
|
96
|
+
|
81
97
|
const contextValue = useMemo(
|
82
98
|
() => ({
|
99
|
+
value: currentValue,
|
100
|
+
onChange: handleChange,
|
83
101
|
orientation,
|
84
102
|
variant,
|
103
|
+
direction,
|
85
104
|
}),
|
86
|
-
[orientation, variant]
|
105
|
+
[currentValue, handleChange, orientation, variant, direction]
|
87
106
|
)
|
88
107
|
|
89
108
|
const isVertical = orientation === 'vertical'
|
90
109
|
|
110
|
+
const childrenWithIndex = React.Children.map(children, (child, idx) => {
|
111
|
+
if (
|
112
|
+
React.isValidElement(child) &&
|
113
|
+
// @ts-expect-error: type check for Picasso Tab
|
114
|
+
(child.type.displayName === 'Tab' || child.type.name === 'Tab') &&
|
115
|
+
child.props.value === undefined
|
116
|
+
) {
|
117
|
+
return React.cloneElement(child as React.ReactElement<any>, {
|
118
|
+
value: idx,
|
119
|
+
})
|
120
|
+
}
|
121
|
+
|
122
|
+
return child
|
123
|
+
})
|
124
|
+
|
91
125
|
return (
|
92
126
|
<TabsContext.Provider value={contextValue}>
|
93
|
-
<
|
127
|
+
<div
|
94
128
|
{...rest}
|
129
|
+
ref={ref}
|
95
130
|
data-component-type='tabs'
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
className
|
104
|
-
),
|
105
|
-
},
|
106
|
-
}}
|
107
|
-
onChange={onChange}
|
108
|
-
value={value}
|
109
|
-
orientation={orientation}
|
131
|
+
className={twMerge(
|
132
|
+
'relative min-h-0 flex overflow-hidden',
|
133
|
+
classesByOrientation[orientation].root,
|
134
|
+
classesByVariant[variant].root,
|
135
|
+
className
|
136
|
+
)}
|
137
|
+
aria-orientation={orientation}
|
110
138
|
>
|
111
139
|
<div
|
112
140
|
className={twJoin(
|
@@ -115,11 +143,15 @@ export const Tabs = forwardRef<HTMLDivElement, Props<TabsValueType>>(
|
|
115
143
|
'flex-auto inline-block relative whitespace-nowrap'
|
116
144
|
)}
|
117
145
|
>
|
118
|
-
<
|
119
|
-
{
|
120
|
-
|
146
|
+
<div
|
147
|
+
className={twJoin('flex', isVertical && 'flex-col')}
|
148
|
+
role='tablist'
|
149
|
+
tabIndex={-1}
|
150
|
+
>
|
151
|
+
{childrenWithIndex}
|
152
|
+
</div>
|
121
153
|
</div>
|
122
|
-
</
|
154
|
+
</div>
|
123
155
|
</TabsContext.Provider>
|
124
156
|
)
|
125
157
|
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
|
3
|
+
export type TabsValueType = string | number | null
|
4
|
+
|
5
|
+
export interface TabsContextValue {
|
6
|
+
value: TabsValueType
|
7
|
+
onChange: (event: React.ChangeEvent<{}>, value: TabsValueType) => void
|
8
|
+
orientation: 'horizontal' | 'vertical'
|
9
|
+
variant: 'scrollable' | 'fullWidth'
|
10
|
+
}
|
11
|
+
|
12
|
+
export const TabsContext = React.createContext<TabsContextValue>({
|
13
|
+
value: null,
|
14
|
+
onChange: () => {},
|
15
|
+
orientation: 'horizontal',
|
16
|
+
variant: 'scrollable',
|
17
|
+
})
|
18
|
+
|
19
|
+
export const useTabsContext = () => {
|
20
|
+
const context = React.useContext(TabsContext)
|
21
|
+
|
22
|
+
if (!context) {
|
23
|
+
throw new Error('useTabsContext must be used within a TabsProvider')
|
24
|
+
}
|
25
|
+
|
26
|
+
return context
|
27
|
+
}
|
@@ -6,29 +6,28 @@ exports[`Tabs renders 1`] = `
|
|
6
6
|
class="Picasso-root"
|
7
7
|
>
|
8
8
|
<div
|
9
|
-
|
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
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"
|
14
15
|
>
|
15
16
|
<div
|
16
|
-
class="
|
17
|
+
class="flex"
|
17
18
|
role="tablist"
|
18
19
|
tabindex="-1"
|
19
20
|
>
|
20
21
|
<button
|
21
|
-
aria-disabled="false"
|
22
22
|
aria-selected="false"
|
23
|
-
class="
|
23
|
+
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"
|
24
24
|
data-testid="tab-1"
|
25
|
-
id=":r0:"
|
26
25
|
role="tab"
|
27
26
|
tabindex="0"
|
28
27
|
type="button"
|
29
28
|
>
|
30
29
|
<span
|
31
|
-
class="w-full inline-flex items-center
|
30
|
+
class="w-full inline-flex flex-row items-center justify-center"
|
32
31
|
>
|
33
32
|
<div
|
34
33
|
class="m-0 text-sm text-inherit font-semibold leading-[1.1rem]"
|
@@ -38,17 +37,15 @@ exports[`Tabs renders 1`] = `
|
|
38
37
|
</span>
|
39
38
|
</button>
|
40
39
|
<button
|
41
|
-
aria-disabled="false"
|
42
40
|
aria-selected="false"
|
43
|
-
class="
|
41
|
+
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"
|
44
42
|
data-testid="tab-2"
|
45
|
-
id=":r1:"
|
46
43
|
role="tab"
|
47
44
|
tabindex="0"
|
48
45
|
type="button"
|
49
46
|
>
|
50
47
|
<span
|
51
|
-
class="w-full inline-flex items-center
|
48
|
+
class="w-full inline-flex flex-row items-center justify-center"
|
52
49
|
>
|
53
50
|
<div
|
54
51
|
class="m-0 text-sm text-inherit font-semibold leading-[1.1rem]"
|
@@ -70,29 +67,28 @@ exports[`Tabs renders in full width 1`] = `
|
|
70
67
|
class="Picasso-root"
|
71
68
|
>
|
72
69
|
<div
|
73
|
-
|
70
|
+
aria-orientation="horizontal"
|
71
|
+
class="relative min-h flex overflow-hidden"
|
74
72
|
data-component-type="tabs"
|
75
73
|
>
|
76
74
|
<div
|
77
75
|
class="w-full overflow-hidden 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"
|
78
76
|
>
|
79
77
|
<div
|
80
|
-
class="
|
78
|
+
class="flex"
|
81
79
|
role="tablist"
|
82
80
|
tabindex="-1"
|
83
81
|
>
|
84
82
|
<button
|
85
|
-
aria-disabled="false"
|
86
83
|
aria-selected="false"
|
87
|
-
class="
|
84
|
+
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 flex-grow basis-0 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"
|
88
85
|
data-testid="tab-1"
|
89
|
-
id=":re:"
|
90
86
|
role="tab"
|
91
87
|
tabindex="0"
|
92
88
|
type="button"
|
93
89
|
>
|
94
90
|
<span
|
95
|
-
class="w-full inline-flex items-center
|
91
|
+
class="w-full inline-flex flex-row items-center justify-center"
|
96
92
|
>
|
97
93
|
<div
|
98
94
|
class="m-0 text-sm text-inherit font-semibold leading-[1.1rem]"
|
@@ -102,17 +98,15 @@ exports[`Tabs renders in full width 1`] = `
|
|
102
98
|
</span>
|
103
99
|
</button>
|
104
100
|
<button
|
105
|
-
aria-disabled="false"
|
106
101
|
aria-selected="false"
|
107
|
-
class="
|
102
|
+
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 flex-grow basis-0 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"
|
108
103
|
data-testid="tab-2"
|
109
|
-
id=":rf:"
|
110
104
|
role="tab"
|
111
105
|
tabindex="0"
|
112
106
|
type="button"
|
113
107
|
>
|
114
108
|
<span
|
115
|
-
class="w-full inline-flex items-center
|
109
|
+
class="w-full inline-flex flex-row items-center justify-center"
|
116
110
|
>
|
117
111
|
<div
|
118
112
|
class="m-0 text-sm text-inherit font-semibold leading-[1.1rem]"
|
@@ -134,24 +128,22 @@ exports[`Tabs renders in vertical orientation 1`] = `
|
|
134
128
|
class="Picasso-root"
|
135
129
|
>
|
136
130
|
<div
|
137
|
-
|
131
|
+
aria-orientation="vertical"
|
132
|
+
class="relative min-h flex overflow-hidden w-[200px] m-0 flex-col overflow-x"
|
138
133
|
data-component-type="tabs"
|
139
134
|
>
|
140
135
|
<div
|
141
136
|
class="pl-2 flex-auto inline-block relative whitespace-nowrap"
|
142
137
|
>
|
143
138
|
<div
|
144
|
-
|
145
|
-
class="base-TabsList base-TabsList flex flex-col"
|
139
|
+
class="flex flex-col"
|
146
140
|
role="tablist"
|
147
141
|
tabindex="-1"
|
148
142
|
>
|
149
143
|
<button
|
150
|
-
aria-disabled="false"
|
151
144
|
aria-selected="false"
|
152
|
-
class="
|
145
|
+
class="opacity-100 first:mt-4 last:mb-4 my-1 mx-0 py-2 px-4 text-left rounded-l rounded-r transition-all w-full overflow-hidden bg-gray hover:bg-gray text-graphite hover: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"
|
153
146
|
data-testid="tab-1"
|
154
|
-
id=":r2:"
|
155
147
|
role="tab"
|
156
148
|
tabindex="0"
|
157
149
|
type="button"
|
@@ -167,11 +159,9 @@ exports[`Tabs renders in vertical orientation 1`] = `
|
|
167
159
|
</span>
|
168
160
|
</button>
|
169
161
|
<button
|
170
|
-
aria-disabled="false"
|
171
162
|
aria-selected="false"
|
172
|
-
class="
|
163
|
+
class="opacity-100 first:mt-4 last:mb-4 my-1 mx-0 py-2 px-4 text-left rounded-l rounded-r transition-all w-full overflow-hidden bg-gray hover:bg-gray text-graphite hover: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"
|
173
164
|
data-testid="tab-2"
|
174
|
-
id=":r3:"
|
175
165
|
role="tab"
|
176
166
|
tabindex="0"
|
177
167
|
type="button"
|
@@ -199,29 +189,28 @@ exports[`Tabs renders with a pre-selected option 1`] = `
|
|
199
189
|
class="Picasso-root"
|
200
190
|
>
|
201
191
|
<div
|
202
|
-
|
192
|
+
aria-orientation="horizontal"
|
193
|
+
class="relative min-h flex overflow-hidden overflow-x"
|
203
194
|
data-component-type="tabs"
|
204
195
|
>
|
205
196
|
<div
|
206
197
|
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"
|
207
198
|
>
|
208
199
|
<div
|
209
|
-
class="
|
200
|
+
class="flex"
|
210
201
|
role="tablist"
|
211
202
|
tabindex="-1"
|
212
203
|
>
|
213
204
|
<button
|
214
|
-
aria-disabled="false"
|
215
205
|
aria-selected="false"
|
216
|
-
class="
|
206
|
+
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"
|
217
207
|
data-testid="tab-1"
|
218
|
-
id=":r4:"
|
219
208
|
role="tab"
|
220
209
|
tabindex="0"
|
221
210
|
type="button"
|
222
211
|
>
|
223
212
|
<span
|
224
|
-
class="w-full inline-flex items-center
|
213
|
+
class="w-full inline-flex flex-row items-center justify-center"
|
225
214
|
>
|
226
215
|
<div
|
227
216
|
class="m-0 text-sm text-inherit font-semibold leading-[1.1rem]"
|
@@ -231,17 +220,15 @@ exports[`Tabs renders with a pre-selected option 1`] = `
|
|
231
220
|
</span>
|
232
221
|
</button>
|
233
222
|
<button
|
234
|
-
aria-disabled="false"
|
235
223
|
aria-selected="true"
|
236
|
-
class="
|
224
|
+
class="opacity-100 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 shadow-blue shadow-[inset_0_-2px_0] 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"
|
237
225
|
data-testid="tab-2"
|
238
|
-
id=":r5:"
|
239
226
|
role="tab"
|
240
227
|
tabindex="0"
|
241
228
|
type="button"
|
242
229
|
>
|
243
230
|
<span
|
244
|
-
class="w-full inline-flex items-center
|
231
|
+
class="w-full inline-flex flex-row items-center justify-center"
|
245
232
|
>
|
246
233
|
<div
|
247
234
|
class="m-0 text-sm text-inherit font-semibold leading-[1.1rem]"
|
@@ -270,29 +257,28 @@ exports[`Tabs renders with a pre-selected option using custom value 1`] = `
|
|
270
257
|
class="Picasso-root"
|
271
258
|
>
|
272
259
|
<div
|
273
|
-
|
260
|
+
aria-orientation="horizontal"
|
261
|
+
class="relative min-h flex overflow-hidden overflow-x"
|
274
262
|
data-component-type="tabs"
|
275
263
|
>
|
276
264
|
<div
|
277
265
|
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"
|
278
266
|
>
|
279
267
|
<div
|
280
|
-
class="
|
268
|
+
class="flex"
|
281
269
|
role="tablist"
|
282
270
|
tabindex="-1"
|
283
271
|
>
|
284
272
|
<button
|
285
|
-
aria-disabled="false"
|
286
273
|
aria-selected="true"
|
287
|
-
class="
|
274
|
+
class="opacity-100 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 shadow-blue shadow-[inset_0_-2px_0] 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"
|
288
275
|
data-testid="tab-1"
|
289
|
-
id=":r6:"
|
290
276
|
role="tab"
|
291
277
|
tabindex="0"
|
292
278
|
type="button"
|
293
279
|
>
|
294
280
|
<span
|
295
|
-
class="w-full inline-flex items-center
|
281
|
+
class="w-full inline-flex flex-row items-center justify-center"
|
296
282
|
>
|
297
283
|
<div
|
298
284
|
class="m-0 text-sm text-inherit font-semibold leading-[1.1rem]"
|
@@ -302,17 +288,15 @@ exports[`Tabs renders with a pre-selected option using custom value 1`] = `
|
|
302
288
|
</span>
|
303
289
|
</button>
|
304
290
|
<button
|
305
|
-
aria-disabled="false"
|
306
291
|
aria-selected="false"
|
307
|
-
class="
|
292
|
+
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"
|
308
293
|
data-testid="tab-2"
|
309
|
-
id=":r7:"
|
310
294
|
role="tab"
|
311
295
|
tabindex="0"
|
312
296
|
type="button"
|
313
297
|
>
|
314
298
|
<span
|
315
|
-
class="w-full inline-flex items-center
|
299
|
+
class="w-full inline-flex flex-row items-center justify-center"
|
316
300
|
>
|
317
301
|
<div
|
318
302
|
class="m-0 text-sm text-inherit font-semibold leading-[1.1rem]"
|
package/src/Tabs/index.ts
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
import type { OmitInternalProps } from '@toptal/picasso-shared'
|
2
2
|
|
3
|
-
import type { Props
|
3
|
+
import type { Props } from './Tabs'
|
4
|
+
import type { TabsValueType } from './TabsContext'
|
4
5
|
|
5
6
|
export { default as Tabs } from './Tabs'
|
6
7
|
export type TabsProps = OmitInternalProps<Props<TabsValueType>>
|
7
|
-
export type { TabsValueType } from './
|
8
|
+
export type { TabsValueType } from './TabsContext'
|
@@ -2,10 +2,12 @@ import React from 'react'
|
|
2
2
|
import { Container, Tabs } from '@toptal/picasso'
|
3
3
|
import { SPACING_4 } from '@toptal/picasso-utils'
|
4
4
|
|
5
|
+
import type { TabsValueType } from '../TabsContext'
|
6
|
+
|
5
7
|
const Example = () => {
|
6
|
-
const [value, setValue] = React.useState(0)
|
8
|
+
const [value, setValue] = React.useState<TabsValueType>(0)
|
7
9
|
|
8
|
-
const handleChange = (_: React.ChangeEvent<{}
|
10
|
+
const handleChange = (_: React.ChangeEvent<{}>, newValue: TabsValueType) => {
|
9
11
|
setValue(newValue)
|
10
12
|
}
|
11
13
|
|