@purpurds/tabs 4.6.0 → 5.0.0
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/LICENSE.txt +1 -1
- package/dist/tab-header.d.ts +1 -0
- package/dist/tab-header.d.ts.map +1 -1
- package/dist/tabs.cjs.js +3 -3
- package/dist/tabs.cjs.js.map +1 -1
- package/dist/tabs.d.ts +1 -0
- package/dist/tabs.d.ts.map +1 -1
- package/dist/tabs.es.js +375 -365
- package/dist/tabs.es.js.map +1 -1
- package/dist/tabs.utils.d.ts +1 -1
- package/dist/tabs.utils.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/tab-header.tsx +11 -2
- package/src/tabs.stories.tsx +3 -55
- package/src/tabs.test.tsx +0 -30
- package/src/tabs.tsx +11 -6
- package/src/tabs.utils.ts +1 -1
package/dist/tabs.utils.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { TabContent } from './tab-content';
|
|
|
3
3
|
export type TabsCmp<P> = React.FunctionComponent<P> & {
|
|
4
4
|
Content: typeof TabContent;
|
|
5
5
|
};
|
|
6
|
-
export declare const tabsVariants: readonly ["line", "
|
|
6
|
+
export declare const tabsVariants: readonly ["line", "contained"];
|
|
7
7
|
export type TabsVariant = (typeof tabsVariants)[number];
|
|
8
8
|
export declare const createTabChangeDetailEvent: (value: string) => CustomEvent<TabChangeDetail>;
|
|
9
9
|
export type TabChangeDetail = {
|
package/dist/tabs.utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabs.utils.d.ts","sourceRoot":"","sources":["../src/tabs.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC,GAAG;IACpD,OAAO,EAAE,OAAO,UAAU,CAAC;CAC5B,CAAC;AAEF,eAAO,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"tabs.utils.d.ts","sourceRoot":"","sources":["../src/tabs.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC,GAAG;IACpD,OAAO,EAAE,OAAO,UAAU,CAAC;CAC5B,CAAC;AAEF,eAAO,MAAM,YAAY,gCAAiC,CAAC;AAE3D,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAExD,eAAO,MAAM,0BAA0B,UAAW,MAAM,iCACoB,CAAC;AAE7E,MAAM,MAAM,eAAe,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@purpurds/tabs",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"license": "AGPL-3.0-only",
|
|
5
5
|
"main": "./dist/tabs.cjs.js",
|
|
6
6
|
"types": "./dist/tabs.d.ts",
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"classnames": "~2.5.0",
|
|
18
18
|
"@radix-ui/react-tabs": "~1.0.4",
|
|
19
|
-
"@purpurds/
|
|
20
|
-
"@purpurds/
|
|
21
|
-
"@purpurds/
|
|
19
|
+
"@purpurds/icon": "5.0.0",
|
|
20
|
+
"@purpurds/tokens": "5.0.0",
|
|
21
|
+
"@purpurds/paragraph": "5.0.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@rushstack/eslint-patch": "~1.10.0",
|
package/src/tab-header.tsx
CHANGED
|
@@ -10,6 +10,7 @@ type TabHeaderProps = {
|
|
|
10
10
|
index: number;
|
|
11
11
|
tabId: string;
|
|
12
12
|
variant: TabsVariant;
|
|
13
|
+
negative?: boolean;
|
|
13
14
|
onFocus: FocusEventHandler<HTMLButtonElement>;
|
|
14
15
|
children: ReactNode;
|
|
15
16
|
};
|
|
@@ -19,12 +20,20 @@ const rootClassName = "purpur-tab-header";
|
|
|
19
20
|
|
|
20
21
|
export const TabHeader = forwardRef(
|
|
21
22
|
<T extends HTMLButtonElement>(
|
|
22
|
-
{
|
|
23
|
+
{
|
|
24
|
+
index,
|
|
25
|
+
tabId,
|
|
26
|
+
variant,
|
|
27
|
+
negative,
|
|
28
|
+
onFocus,
|
|
29
|
+
"data-testid": dataTestId,
|
|
30
|
+
children,
|
|
31
|
+
}: TabHeaderProps,
|
|
23
32
|
ref: ForwardedRef<T>
|
|
24
33
|
) => (
|
|
25
34
|
<Trigger
|
|
26
35
|
id={`${tabId}-trigger`}
|
|
27
|
-
className={cx([rootClassName, `${rootClassName}--${variant}`])}
|
|
36
|
+
className={cx([rootClassName, `${rootClassName}--${variant}${negative ? "-negative" : ""}`])}
|
|
28
37
|
value={tabId}
|
|
29
38
|
data-testid={dataTestId}
|
|
30
39
|
data-index={index}
|
package/src/tabs.stories.tsx
CHANGED
|
@@ -30,57 +30,6 @@ type Story = StoryObj<typeof Tabs>;
|
|
|
30
30
|
const tabId = "tab";
|
|
31
31
|
const name = "Tab name";
|
|
32
32
|
|
|
33
|
-
export const ActiveTab: Story = {
|
|
34
|
-
args: {
|
|
35
|
-
variant: tabsVariants[0],
|
|
36
|
-
defaultValue: `${tabId}-2`,
|
|
37
|
-
fullWidth: false,
|
|
38
|
-
children: [
|
|
39
|
-
<Tabs.Content
|
|
40
|
-
key="1"
|
|
41
|
-
tabId={`${tabId}-1`}
|
|
42
|
-
name={`${name}-1`}
|
|
43
|
-
style={{ padding: "var(--purpur-spacing-250" }}
|
|
44
|
-
>
|
|
45
|
-
<div>Content 1</div>
|
|
46
|
-
</Tabs.Content>,
|
|
47
|
-
<Tabs.Content
|
|
48
|
-
key="2"
|
|
49
|
-
tabId={`${tabId}-2`}
|
|
50
|
-
name={`${name}-2`}
|
|
51
|
-
style={{ padding: "var(--purpur-spacing-250" }}
|
|
52
|
-
>
|
|
53
|
-
<div>Content 2</div>
|
|
54
|
-
</Tabs.Content>,
|
|
55
|
-
<Tabs.Content
|
|
56
|
-
key="3"
|
|
57
|
-
tabId={`${tabId}-3`}
|
|
58
|
-
name={`${name}-3`}
|
|
59
|
-
style={{ padding: "var(--purpur-spacing-250" }}
|
|
60
|
-
>
|
|
61
|
-
<div>Content 3</div>
|
|
62
|
-
</Tabs.Content>,
|
|
63
|
-
],
|
|
64
|
-
},
|
|
65
|
-
render: ({ children, ...args }) => (
|
|
66
|
-
<div
|
|
67
|
-
style={{
|
|
68
|
-
padding: "var(--purpur-spacing-250)",
|
|
69
|
-
background: args.variant?.includes("negative")
|
|
70
|
-
? "var(--purpur-color-purple-900)"
|
|
71
|
-
: args.variant === "contained"
|
|
72
|
-
? "var(--purpur-color-gray-50)"
|
|
73
|
-
: "transparent",
|
|
74
|
-
color: `var(--purpur-color-text-default${
|
|
75
|
-
args.variant === "line-negative" ? "-negative" : ""
|
|
76
|
-
}`,
|
|
77
|
-
}}
|
|
78
|
-
>
|
|
79
|
-
<Tabs {...args}>{children}</Tabs>
|
|
80
|
-
</div>
|
|
81
|
-
),
|
|
82
|
-
};
|
|
83
|
-
|
|
84
33
|
export const Showcase: Story = {
|
|
85
34
|
args: {
|
|
86
35
|
variant: tabsVariants[0],
|
|
@@ -111,19 +60,18 @@ export const Showcase: Story = {
|
|
|
111
60
|
<div>Content 3</div>
|
|
112
61
|
</Tabs.Content>,
|
|
113
62
|
],
|
|
63
|
+
negative: false,
|
|
114
64
|
},
|
|
115
65
|
render: ({ children, ...args }) => (
|
|
116
66
|
<div
|
|
117
67
|
style={{
|
|
118
68
|
padding: "var(--purpur-spacing-250)",
|
|
119
|
-
background: args.
|
|
69
|
+
background: args.negative
|
|
120
70
|
? "var(--purpur-color-purple-900)"
|
|
121
71
|
: args.variant === "contained"
|
|
122
72
|
? "var(--purpur-color-gray-50)"
|
|
123
73
|
: "transparent",
|
|
124
|
-
color: `var(--purpur-color-text-default${
|
|
125
|
-
args.variant === "line-negative" ? "-negative" : ""
|
|
126
|
-
}`,
|
|
74
|
+
color: `var(--purpur-color-text-default${args.negative ? "-negative" : ""}`,
|
|
127
75
|
}}
|
|
128
76
|
>
|
|
129
77
|
<Tabs {...args}>{children}</Tabs>
|
package/src/tabs.test.tsx
CHANGED
|
@@ -119,21 +119,6 @@ describe("Tabs", () => {
|
|
|
119
119
|
expect(screen.getByTestId("tabs-test-selected-border")).toBeInTheDocument();
|
|
120
120
|
});
|
|
121
121
|
|
|
122
|
-
it("should render selected border for line-negative variant", () => {
|
|
123
|
-
render(
|
|
124
|
-
<Tabs variant="line-negative" data-testid="tabs-test">
|
|
125
|
-
<TabContent tabId="tab-1" name="Tab name 1">
|
|
126
|
-
<div>Content</div>
|
|
127
|
-
</TabContent>
|
|
128
|
-
<TabContent tabId="tab-2" name="Tab name 2">
|
|
129
|
-
<div>Content</div>
|
|
130
|
-
</TabContent>
|
|
131
|
-
</Tabs>
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
expect(screen.getByTestId("tabs-test-selected-border")).toBeInTheDocument();
|
|
135
|
-
});
|
|
136
|
-
|
|
137
122
|
it("should not render selected border for contained variant", () => {
|
|
138
123
|
render(
|
|
139
124
|
<Tabs variant="contained" data-testid="tabs-test">
|
|
@@ -149,21 +134,6 @@ describe("Tabs", () => {
|
|
|
149
134
|
expect(screen.queryByTestId("tabs-test-selected-border")).not.toBeInTheDocument();
|
|
150
135
|
});
|
|
151
136
|
|
|
152
|
-
it("should not render selected border for contained-negative variant", () => {
|
|
153
|
-
render(
|
|
154
|
-
<Tabs variant="contained-negative" data-testid="tabs-test">
|
|
155
|
-
<TabContent tabId="tab-1" name="Tab name 1">
|
|
156
|
-
<div>Content</div>
|
|
157
|
-
</TabContent>
|
|
158
|
-
<TabContent tabId="tab-2" name="Tab name 2">
|
|
159
|
-
<div>Content</div>
|
|
160
|
-
</TabContent>
|
|
161
|
-
</Tabs>
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
expect(screen.queryByTestId("tabs-test-selected-border")).not.toBeInTheDocument();
|
|
165
|
-
});
|
|
166
|
-
|
|
167
137
|
it("should throw error if duplicate tabId is found", () => {
|
|
168
138
|
expect(() => {
|
|
169
139
|
render(
|
package/src/tabs.tsx
CHANGED
|
@@ -11,6 +11,7 @@ import { createTabChangeDetailEvent, TabChangeDetail, TabsCmp, TabsVariant } fro
|
|
|
11
11
|
type TabsProps = {
|
|
12
12
|
children: Array<ReactElement<typeof TabContent>> | ReactElement<typeof TabContent>;
|
|
13
13
|
variant?: TabsVariant;
|
|
14
|
+
negative?: boolean;
|
|
14
15
|
fullWidth?: boolean;
|
|
15
16
|
/**
|
|
16
17
|
* Event handler called when the value changes.
|
|
@@ -66,6 +67,7 @@ const scrollToTarget = (target: HTMLElement, tabList?: HTMLDivElement | null) =>
|
|
|
66
67
|
export const Tabs: TabsCmp<TabsProps> = ({
|
|
67
68
|
children,
|
|
68
69
|
variant = "line",
|
|
70
|
+
negative = false,
|
|
69
71
|
fullWidth = false,
|
|
70
72
|
onChange,
|
|
71
73
|
className,
|
|
@@ -80,11 +82,11 @@ export const Tabs: TabsCmp<TabsProps> = ({
|
|
|
80
82
|
const tabList = useRef<HTMLDivElement | null>();
|
|
81
83
|
const tabChildren = useRef<HTMLButtonElement[]>(new Array(tabContentChildren.length));
|
|
82
84
|
const sideScrollAdjustmentSize = 200;
|
|
83
|
-
const isLineVariant = variant === "line"
|
|
85
|
+
const isLineVariant = variant === "line";
|
|
84
86
|
|
|
85
87
|
const classNames = cx([
|
|
86
88
|
rootClassName,
|
|
87
|
-
`${rootClassName}--${variant}`,
|
|
89
|
+
`${rootClassName}--${variant}${negative ? "-negative" : ""}`,
|
|
88
90
|
{ [`${rootClassName}--fullWidth`]: fullWidth },
|
|
89
91
|
className,
|
|
90
92
|
]);
|
|
@@ -147,11 +149,11 @@ export const Tabs: TabsCmp<TabsProps> = ({
|
|
|
147
149
|
return () => {
|
|
148
150
|
window.removeEventListener("resize", handleLinePosition);
|
|
149
151
|
};
|
|
150
|
-
}, []);
|
|
152
|
+
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
151
153
|
|
|
152
154
|
useEffect(() => {
|
|
153
155
|
handleLinePosition();
|
|
154
|
-
}, [activeIndex, fullWidth, tabContentChildren, variant]);
|
|
156
|
+
}, [activeIndex, fullWidth, tabContentChildren.length, variant]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
155
157
|
|
|
156
158
|
useEffect(() => {
|
|
157
159
|
const onIntersection = (entries: IntersectionObserverEntry[]): void => {
|
|
@@ -186,10 +188,12 @@ export const Tabs: TabsCmp<TabsProps> = ({
|
|
|
186
188
|
root: tabList.current,
|
|
187
189
|
});
|
|
188
190
|
|
|
189
|
-
tabChildren.current
|
|
191
|
+
const currentTabChildren = tabChildren.current;
|
|
192
|
+
|
|
193
|
+
currentTabChildren.forEach((el) => observer.observe(el));
|
|
190
194
|
|
|
191
195
|
return () => {
|
|
192
|
-
|
|
196
|
+
currentTabChildren.forEach((el) => observer.unobserve(el));
|
|
193
197
|
};
|
|
194
198
|
}, [tabContentChildren.length]);
|
|
195
199
|
|
|
@@ -225,6 +229,7 @@ export const Tabs: TabsCmp<TabsProps> = ({
|
|
|
225
229
|
scrollToTarget(e.target as HTMLElement, tabList.current);
|
|
226
230
|
}}
|
|
227
231
|
variant={variant}
|
|
232
|
+
negative={negative}
|
|
228
233
|
>
|
|
229
234
|
{name}
|
|
230
235
|
</TabHeader>
|
package/src/tabs.utils.ts
CHANGED
|
@@ -4,7 +4,7 @@ export type TabsCmp<P> = React.FunctionComponent<P> & {
|
|
|
4
4
|
Content: typeof TabContent;
|
|
5
5
|
};
|
|
6
6
|
|
|
7
|
-
export const tabsVariants = ["line", "
|
|
7
|
+
export const tabsVariants = ["line", "contained"] as const;
|
|
8
8
|
|
|
9
9
|
export type TabsVariant = (typeof tabsVariants)[number];
|
|
10
10
|
|