@navikt/ds-react 0.17.12 → 0.17.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/cjs/index.js +2 -0
- package/cjs/stepper/Step.js +63 -0
- package/cjs/stepper/Stepper.js +60 -0
- package/cjs/stepper/index.js +23 -0
- package/cjs/stepper/package.json +6 -0
- package/cjs/tabs/Tab.js +61 -0
- package/cjs/tabs/TabList.js +109 -0
- package/cjs/tabs/TabPanel.js +47 -0
- package/cjs/tabs/Tabs.js +58 -0
- package/cjs/tabs/index.js +8 -0
- package/cjs/tabs/package.json +6 -0
- package/esm/index.d.ts +2 -0
- package/esm/index.js +2 -0
- package/esm/index.js.map +1 -1
- package/esm/stepper/Step.d.ts +16 -0
- package/esm/stepper/Step.js +36 -0
- package/esm/stepper/Step.js.map +1 -0
- package/esm/stepper/Stepper.d.ts +31 -0
- package/esm/stepper/Stepper.js +32 -0
- package/esm/stepper/Stepper.js.map +1 -0
- package/esm/stepper/index.d.ts +2 -0
- package/esm/stepper/index.js +3 -0
- package/esm/stepper/index.js.map +1 -0
- package/esm/tabs/Tab.d.ts +24 -0
- package/esm/tabs/Tab.js +34 -0
- package/esm/tabs/Tab.js.map +1 -0
- package/esm/tabs/TabList.d.ts +14 -0
- package/esm/tabs/TabList.js +82 -0
- package/esm/tabs/TabList.js.map +1 -0
- package/esm/tabs/TabPanel.d.ts +14 -0
- package/esm/tabs/TabPanel.js +20 -0
- package/esm/tabs/TabPanel.js.map +1 -0
- package/esm/tabs/Tabs.d.ts +43 -0
- package/esm/tabs/Tabs.js +30 -0
- package/esm/tabs/Tabs.js.map +1 -0
- package/esm/tabs/index.d.ts +2 -0
- package/esm/tabs/index.js +2 -0
- package/esm/tabs/index.js.map +1 -0
- package/package.json +3 -2
- package/src/index.ts +2 -0
- package/src/step-indicator/stories/step-indicator.stories.mdx +1 -1
- package/src/stepper/Step.tsx +59 -0
- package/src/stepper/Stepper.tsx +73 -0
- package/src/stepper/index.ts +2 -0
- package/src/stepper/stories/Example.tsx +28 -0
- package/src/stepper/stories/stepper.stories.mdx +61 -0
- package/src/stepper/stories/stepper.stories.tsx +54 -0
- package/src/tabs/Tab.tsx +79 -0
- package/src/tabs/TabList.tsx +127 -0
- package/src/tabs/TabPanel.tsx +30 -0
- package/src/tabs/Tabs.stories.tsx +188 -0
- package/src/tabs/Tabs.tsx +89 -0
- package/src/tabs/index.ts +2 -0
package/src/tabs/Tab.tsx
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as RadixTabs from "@radix-ui/react-tabs";
|
|
2
|
+
import cl from "classnames";
|
|
3
|
+
import React, { forwardRef, useContext } from "react";
|
|
4
|
+
import { Label, OverridableComponent } from "..";
|
|
5
|
+
import { TabsContext } from "./Tabs";
|
|
6
|
+
|
|
7
|
+
export interface TabProps
|
|
8
|
+
extends Omit<React.HTMLAttributes<HTMLButtonElement>, "children"> {
|
|
9
|
+
/**
|
|
10
|
+
* Content
|
|
11
|
+
*/
|
|
12
|
+
label?: React.ReactNode;
|
|
13
|
+
/**
|
|
14
|
+
* Icon
|
|
15
|
+
*/
|
|
16
|
+
icon?: React.ReactNode;
|
|
17
|
+
/**
|
|
18
|
+
* Value for state-handling
|
|
19
|
+
*/
|
|
20
|
+
value: string;
|
|
21
|
+
/**
|
|
22
|
+
* Icon position
|
|
23
|
+
* @default "left"
|
|
24
|
+
*/
|
|
25
|
+
iconPosition?: "left" | "top";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type TabType = OverridableComponent<TabProps, HTMLButtonElement>;
|
|
29
|
+
|
|
30
|
+
const Tab: TabType = forwardRef(
|
|
31
|
+
(
|
|
32
|
+
{
|
|
33
|
+
className,
|
|
34
|
+
as: Component = "button",
|
|
35
|
+
label,
|
|
36
|
+
icon,
|
|
37
|
+
iconPosition,
|
|
38
|
+
value,
|
|
39
|
+
...rest
|
|
40
|
+
},
|
|
41
|
+
ref
|
|
42
|
+
) => {
|
|
43
|
+
const context = useContext(TabsContext);
|
|
44
|
+
|
|
45
|
+
if (!label && !icon) {
|
|
46
|
+
console.error("<Tabs.Tab/> needs label/icon");
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<RadixTabs.Trigger value={value} asChild>
|
|
52
|
+
<Component
|
|
53
|
+
ref={ref}
|
|
54
|
+
className={cl(
|
|
55
|
+
"navds-tabs__tab",
|
|
56
|
+
`navds-tabs__tab--${context?.size ?? "medium"}`,
|
|
57
|
+
`navds-tabs__tab-icon--${iconPosition}`,
|
|
58
|
+
className,
|
|
59
|
+
{
|
|
60
|
+
"navds-tabs__tab--icon-only": icon && !label,
|
|
61
|
+
}
|
|
62
|
+
)}
|
|
63
|
+
{...rest}
|
|
64
|
+
>
|
|
65
|
+
<Label
|
|
66
|
+
as="span"
|
|
67
|
+
className="navds-tabs__tab-inner"
|
|
68
|
+
size={context?.size}
|
|
69
|
+
>
|
|
70
|
+
{icon}
|
|
71
|
+
{label}
|
|
72
|
+
</Label>
|
|
73
|
+
</Component>
|
|
74
|
+
</RadixTabs.Trigger>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
export default Tab;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { debounce } from "@material-ui/core";
|
|
2
|
+
import { Back, Next } from "@navikt/ds-icons";
|
|
3
|
+
import { TabsList } from "@radix-ui/react-tabs";
|
|
4
|
+
import cl from "classnames";
|
|
5
|
+
import React, { forwardRef, useEffect, useMemo, useRef, useState } from "react";
|
|
6
|
+
import mergeRefs from "react-merge-refs";
|
|
7
|
+
|
|
8
|
+
export interface ListProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
9
|
+
/**
|
|
10
|
+
* Tab elements
|
|
11
|
+
*/
|
|
12
|
+
children: React.ReactNode;
|
|
13
|
+
/**
|
|
14
|
+
* Loops back to start when navigating past last item
|
|
15
|
+
*/
|
|
16
|
+
loop?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type ListType = React.ForwardRefExoticComponent<
|
|
20
|
+
ListProps & React.RefAttributes<HTMLDivElement>
|
|
21
|
+
>;
|
|
22
|
+
|
|
23
|
+
const List = forwardRef<HTMLDivElement, ListProps>(
|
|
24
|
+
({ className, ...rest }, ref) => {
|
|
25
|
+
const listRef = useRef<HTMLDivElement | null>(null);
|
|
26
|
+
const mergedRef = mergeRefs([listRef, ref]);
|
|
27
|
+
const [displayScroll, setDisplayScroll] = useState({
|
|
28
|
+
start: false,
|
|
29
|
+
end: false,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const updateScrollButtonState = useMemo(
|
|
33
|
+
() =>
|
|
34
|
+
debounce(() => {
|
|
35
|
+
if (!listRef?.current) return;
|
|
36
|
+
const { scrollWidth, clientWidth } = listRef?.current;
|
|
37
|
+
let showStartScroll;
|
|
38
|
+
let showEndScroll;
|
|
39
|
+
|
|
40
|
+
const scrollLeft = listRef?.current?.scrollLeft;
|
|
41
|
+
// use 1 for the potential rounding error with browser zooms.
|
|
42
|
+
showStartScroll = scrollLeft > 1;
|
|
43
|
+
showEndScroll = scrollLeft < scrollWidth - clientWidth - 1;
|
|
44
|
+
|
|
45
|
+
setDisplayScroll((displayScroll) =>
|
|
46
|
+
showStartScroll === displayScroll.start &&
|
|
47
|
+
showEndScroll === displayScroll.end
|
|
48
|
+
? displayScroll
|
|
49
|
+
: { start: showStartScroll, end: showEndScroll }
|
|
50
|
+
);
|
|
51
|
+
}),
|
|
52
|
+
[]
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
const handleResize = () => updateScrollButtonState();
|
|
57
|
+
const win = listRef.current?.ownerDocument ?? document ?? window;
|
|
58
|
+
win.addEventListener("resize", handleResize);
|
|
59
|
+
|
|
60
|
+
let resizeObserver;
|
|
61
|
+
|
|
62
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
63
|
+
resizeObserver = new ResizeObserver(handleResize);
|
|
64
|
+
resizeObserver.observe(listRef.current);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return () => {
|
|
68
|
+
win.removeEventListener("resize", handleResize);
|
|
69
|
+
if (resizeObserver) {
|
|
70
|
+
resizeObserver.disconnect();
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}, [updateScrollButtonState]);
|
|
74
|
+
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
updateScrollButtonState();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
return () => {
|
|
81
|
+
updateScrollButtonState.clear();
|
|
82
|
+
};
|
|
83
|
+
}, [updateScrollButtonState]);
|
|
84
|
+
|
|
85
|
+
const ScrollButton = ({
|
|
86
|
+
dir,
|
|
87
|
+
hidden,
|
|
88
|
+
}: {
|
|
89
|
+
dir: 1 | -1;
|
|
90
|
+
hidden: boolean;
|
|
91
|
+
}) => (
|
|
92
|
+
<div
|
|
93
|
+
className={cl("navds-tabs__scroll-button", {
|
|
94
|
+
"navds-tabs__scroll-button--hidden": hidden,
|
|
95
|
+
})}
|
|
96
|
+
onClick={() => {
|
|
97
|
+
if (!listRef.current) return;
|
|
98
|
+
listRef.current.scrollLeft &&= listRef.current.scrollLeft + dir * 100;
|
|
99
|
+
}}
|
|
100
|
+
>
|
|
101
|
+
{dir === -1 ? (
|
|
102
|
+
<Back title="scroll tilbake" />
|
|
103
|
+
) : (
|
|
104
|
+
<Next title="scroll neste" />
|
|
105
|
+
)}
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const showSteppers = displayScroll.end || displayScroll.start;
|
|
110
|
+
return (
|
|
111
|
+
<div className="navds-tabs__tablist-wrapper">
|
|
112
|
+
{showSteppers && (
|
|
113
|
+
<ScrollButton dir={-1} hidden={!displayScroll.start} />
|
|
114
|
+
)}
|
|
115
|
+
<TabsList
|
|
116
|
+
{...rest}
|
|
117
|
+
ref={mergedRef}
|
|
118
|
+
onScroll={updateScrollButtonState}
|
|
119
|
+
className={cl("navds-tabs__tablist", className)}
|
|
120
|
+
/>
|
|
121
|
+
{showSteppers && <ScrollButton dir={1} hidden={!displayScroll.end} />}
|
|
122
|
+
</div>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
) as ListType;
|
|
126
|
+
|
|
127
|
+
export default List;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { TabsContent } from "@radix-ui/react-tabs";
|
|
2
|
+
import cl from "classnames";
|
|
3
|
+
import React, { forwardRef } from "react";
|
|
4
|
+
|
|
5
|
+
export interface PanelProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
6
|
+
/**
|
|
7
|
+
* Tab panel
|
|
8
|
+
*/
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
/**
|
|
11
|
+
* Value for state-handling
|
|
12
|
+
*/
|
|
13
|
+
value: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type PanelType = React.ForwardRefExoticComponent<
|
|
17
|
+
PanelProps & React.RefAttributes<HTMLDivElement>
|
|
18
|
+
>;
|
|
19
|
+
|
|
20
|
+
const Panel = forwardRef<HTMLDivElement, PanelProps>(
|
|
21
|
+
({ className, ...rest }, ref) => (
|
|
22
|
+
<TabsContent
|
|
23
|
+
{...rest}
|
|
24
|
+
ref={ref}
|
|
25
|
+
className={cl("navds-tabs__tabpanel", className)}
|
|
26
|
+
/>
|
|
27
|
+
)
|
|
28
|
+
) as PanelType;
|
|
29
|
+
|
|
30
|
+
export default Panel;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { Cup, Dishwasher, Freezer } from "@navikt/ds-icons";
|
|
2
|
+
import { Meta } from "@storybook/react/types-6-0";
|
|
3
|
+
import React, { useState } from "react";
|
|
4
|
+
import { Tabs } from ".";
|
|
5
|
+
import { Link } from "../link";
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
title: "ds-react/tabs",
|
|
9
|
+
component: Tabs,
|
|
10
|
+
} as Meta;
|
|
11
|
+
|
|
12
|
+
export const UUDemo = () => (
|
|
13
|
+
<Tabs defaultValue="skap" lang="no">
|
|
14
|
+
<Tabs.List>
|
|
15
|
+
<Tabs.Tab value="skap" label="Skap" icon={<Cup aria-hidden />} />
|
|
16
|
+
<Tabs.Tab
|
|
17
|
+
value="oppvaskmaskin"
|
|
18
|
+
label="Oppvaskmaskin"
|
|
19
|
+
icon={<Dishwasher aria-hidden />}
|
|
20
|
+
/>
|
|
21
|
+
<Tabs.Tab value="fryser" icon={<Freezer aria-hidden />} label="Fryser" />
|
|
22
|
+
</Tabs.List>
|
|
23
|
+
<Tabs.Panel
|
|
24
|
+
value="skap"
|
|
25
|
+
style={{ background: "var(--navds-global-color-gray-50)", height: 300 }}
|
|
26
|
+
>
|
|
27
|
+
Innholdspanel for skap med lenke <Link href="#">Dette er en lenke</Link>
|
|
28
|
+
</Tabs.Panel>
|
|
29
|
+
<Tabs.Panel
|
|
30
|
+
value="oppvaskmaskin"
|
|
31
|
+
style={{ background: "var(--navds-global-color-green-50)", height: 300 }}
|
|
32
|
+
>
|
|
33
|
+
Innholdspanel for oppvaskmaskin med lenke{" "}
|
|
34
|
+
<Link href="#">Dette er en lenke</Link>
|
|
35
|
+
</Tabs.Panel>
|
|
36
|
+
<Tabs.Panel
|
|
37
|
+
value="fryser"
|
|
38
|
+
style={{ background: "var(--navds-global-color-red-50)", height: 300 }}
|
|
39
|
+
>
|
|
40
|
+
Innholdspanel for fryser med lenke <Link href="#">Dette er en lenke</Link>
|
|
41
|
+
</Tabs.Panel>
|
|
42
|
+
</Tabs>
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const Panel = () => {
|
|
46
|
+
return (
|
|
47
|
+
<>
|
|
48
|
+
<Tabs.Panel
|
|
49
|
+
value="test1"
|
|
50
|
+
style={{ background: "var(--navds-global-color-gray-50)", height: 100 }}
|
|
51
|
+
>
|
|
52
|
+
Innholdspanel for Skap-tab
|
|
53
|
+
</Tabs.Panel>
|
|
54
|
+
<Tabs.Panel
|
|
55
|
+
value="test2"
|
|
56
|
+
style={{
|
|
57
|
+
background: "var(--navds-global-color-green-50)",
|
|
58
|
+
height: 100,
|
|
59
|
+
}}
|
|
60
|
+
>
|
|
61
|
+
Innholdspanel for Oppvaskmaskin-tab
|
|
62
|
+
</Tabs.Panel>
|
|
63
|
+
<Tabs.Panel
|
|
64
|
+
value="test3"
|
|
65
|
+
style={{ background: "var(--navds-global-color-red-50)", height: 100 }}
|
|
66
|
+
>
|
|
67
|
+
Innholdspanel for Fryser-tab
|
|
68
|
+
</Tabs.Panel>
|
|
69
|
+
</>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const All = () => {
|
|
74
|
+
const [activeValue, setActiveValue] = useState("test1");
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<div>
|
|
78
|
+
<h2>Tabs</h2>
|
|
79
|
+
<Tabs defaultValue="test2">
|
|
80
|
+
<Tabs.List>
|
|
81
|
+
<Tabs.Tab value="test1" icon={<Cup />} label="Skap" />
|
|
82
|
+
<Tabs.Tab value="test2" label="Oppvaskmaskin" icon={<Dishwasher />} />
|
|
83
|
+
<Tabs.Tab value="test3" icon={<Freezer />} label="Fryser" />
|
|
84
|
+
</Tabs.List>
|
|
85
|
+
<Panel />
|
|
86
|
+
</Tabs>
|
|
87
|
+
|
|
88
|
+
<h2>Controlled</h2>
|
|
89
|
+
<Tabs value={activeValue} onChange={setActiveValue}>
|
|
90
|
+
<Tabs.List>
|
|
91
|
+
<Tabs.Tab value="test1" icon={<Cup />} label="Skap" />
|
|
92
|
+
<Tabs.Tab value="test2" label="Oppvaskmaskin" icon={<Dishwasher />} />
|
|
93
|
+
<Tabs.Tab value="test3" icon={<Freezer />} label="Fryser" />
|
|
94
|
+
</Tabs.List>
|
|
95
|
+
<Panel />
|
|
96
|
+
</Tabs>
|
|
97
|
+
|
|
98
|
+
<h2>selectionFollowsFocus</h2>
|
|
99
|
+
<Tabs defaultValue="test2" selectionFollowsFocus>
|
|
100
|
+
<Tabs.List>
|
|
101
|
+
<Tabs.Tab value="test1" icon={<Cup />} label="Skap" />
|
|
102
|
+
<Tabs.Tab value="test2" label="Oppvaskmaskin" icon={<Dishwasher />} />
|
|
103
|
+
<Tabs.Tab value="test3" icon={<Freezer />} label="Fryser" />
|
|
104
|
+
</Tabs.List>
|
|
105
|
+
<Panel />
|
|
106
|
+
</Tabs>
|
|
107
|
+
|
|
108
|
+
<h2>Tabs iconPosition="top"</h2>
|
|
109
|
+
<Tabs defaultValue="test2">
|
|
110
|
+
<Tabs.List>
|
|
111
|
+
<Tabs.Tab
|
|
112
|
+
value="test1"
|
|
113
|
+
icon={<Cup />}
|
|
114
|
+
label="Skap"
|
|
115
|
+
iconPosition="top"
|
|
116
|
+
/>
|
|
117
|
+
<Tabs.Tab
|
|
118
|
+
value="test2"
|
|
119
|
+
label="Oppvaskmaskin"
|
|
120
|
+
icon={<Dishwasher />}
|
|
121
|
+
iconPosition="top"
|
|
122
|
+
/>
|
|
123
|
+
<Tabs.Tab
|
|
124
|
+
value="test3"
|
|
125
|
+
icon={<Freezer />}
|
|
126
|
+
label="Fryser"
|
|
127
|
+
iconPosition="top"
|
|
128
|
+
/>
|
|
129
|
+
</Tabs.List>
|
|
130
|
+
<Panel />
|
|
131
|
+
</Tabs>
|
|
132
|
+
|
|
133
|
+
<h2>Tabs small</h2>
|
|
134
|
+
<Tabs defaultValue="test2" size="small">
|
|
135
|
+
<Tabs.List>
|
|
136
|
+
<Tabs.Tab value="test1" icon={<Cup />} label="Skap" />
|
|
137
|
+
<Tabs.Tab value="test2" label="Oppvaskmaskin" icon={<Dishwasher />} />
|
|
138
|
+
<Tabs.Tab value="test3" icon={<Freezer />} label="Fryser" />
|
|
139
|
+
</Tabs.List>
|
|
140
|
+
<Panel />
|
|
141
|
+
</Tabs>
|
|
142
|
+
<br />
|
|
143
|
+
<Tabs defaultValue="test2" size="small">
|
|
144
|
+
<Tabs.List>
|
|
145
|
+
<Tabs.Tab
|
|
146
|
+
value="test1"
|
|
147
|
+
icon={<Cup />}
|
|
148
|
+
label="Skap"
|
|
149
|
+
iconPosition="top"
|
|
150
|
+
/>
|
|
151
|
+
|
|
152
|
+
<Tabs.Tab
|
|
153
|
+
value="test2"
|
|
154
|
+
label="Oppvaskmaskin"
|
|
155
|
+
icon={<Dishwasher />}
|
|
156
|
+
iconPosition="top"
|
|
157
|
+
/>
|
|
158
|
+
<Tabs.Tab
|
|
159
|
+
value="test3"
|
|
160
|
+
icon={<Freezer />}
|
|
161
|
+
label="Fryser"
|
|
162
|
+
iconPosition="top"
|
|
163
|
+
/>
|
|
164
|
+
</Tabs.List>
|
|
165
|
+
<Panel />
|
|
166
|
+
</Tabs>
|
|
167
|
+
|
|
168
|
+
<h2>Tabs Icon-only</h2>
|
|
169
|
+
<Tabs defaultValue="test2">
|
|
170
|
+
<Tabs.List>
|
|
171
|
+
<Tabs.Tab value="test1" icon={<Cup />} />
|
|
172
|
+
<Tabs.Tab value="test2" icon={<Dishwasher />} />
|
|
173
|
+
<Tabs.Tab value="test3" icon={<Freezer />} />
|
|
174
|
+
</Tabs.List>
|
|
175
|
+
<Panel />
|
|
176
|
+
</Tabs>
|
|
177
|
+
<br />
|
|
178
|
+
<Tabs defaultValue="test2" size="small">
|
|
179
|
+
<Tabs.List>
|
|
180
|
+
<Tabs.Tab value="test1" icon={<Cup />} />
|
|
181
|
+
<Tabs.Tab value="test2" icon={<Dishwasher />} />
|
|
182
|
+
<Tabs.Tab value="test3" icon={<Freezer />} />
|
|
183
|
+
</Tabs.List>
|
|
184
|
+
<Panel />
|
|
185
|
+
</Tabs>
|
|
186
|
+
</div>
|
|
187
|
+
);
|
|
188
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import cl from "classnames";
|
|
2
|
+
import React, { createContext, forwardRef, HTMLAttributes } from "react";
|
|
3
|
+
import * as RadixTabs from "@radix-ui/react-tabs";
|
|
4
|
+
import Tab, { TabType } from "./Tab";
|
|
5
|
+
import List, { ListType } from "./TabList";
|
|
6
|
+
import Panel, { PanelType } from "./TabPanel";
|
|
7
|
+
|
|
8
|
+
export interface TabsProps
|
|
9
|
+
extends Omit<HTMLAttributes<HTMLDivElement>, "onChange" | "dir"> {
|
|
10
|
+
/**
|
|
11
|
+
* Tabs elements
|
|
12
|
+
*/
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
/**
|
|
15
|
+
* Changes padding and font-size
|
|
16
|
+
* @default "medium"
|
|
17
|
+
*/
|
|
18
|
+
size?: "medium" | "small";
|
|
19
|
+
/**
|
|
20
|
+
* onChange
|
|
21
|
+
*/
|
|
22
|
+
onChange?: (value: string) => void;
|
|
23
|
+
/**
|
|
24
|
+
* Controlled selected value
|
|
25
|
+
*/
|
|
26
|
+
value?: string;
|
|
27
|
+
/**
|
|
28
|
+
* If not controlled, a default-value needs to be set
|
|
29
|
+
*/
|
|
30
|
+
defaultValue?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Automatically activates tab on focus/navigation
|
|
33
|
+
* @default false
|
|
34
|
+
*/
|
|
35
|
+
selectionFollowsFocus?: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface TabsComponent
|
|
39
|
+
extends React.ForwardRefExoticComponent<
|
|
40
|
+
TabsProps & React.RefAttributes<HTMLDivElement>
|
|
41
|
+
> {
|
|
42
|
+
Tab: TabType;
|
|
43
|
+
List: ListType;
|
|
44
|
+
Panel: PanelType;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface TabsContextProps {
|
|
48
|
+
size: "medium" | "small";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const TabsContext = createContext<TabsContextProps | null>(null);
|
|
52
|
+
|
|
53
|
+
const Tabs = forwardRef<HTMLDivElement, TabsProps>(
|
|
54
|
+
(
|
|
55
|
+
{
|
|
56
|
+
className,
|
|
57
|
+
children,
|
|
58
|
+
onChange,
|
|
59
|
+
size = "medium",
|
|
60
|
+
selectionFollowsFocus = false,
|
|
61
|
+
...rest
|
|
62
|
+
},
|
|
63
|
+
ref
|
|
64
|
+
) => {
|
|
65
|
+
return (
|
|
66
|
+
<RadixTabs.Root
|
|
67
|
+
{...rest}
|
|
68
|
+
ref={ref}
|
|
69
|
+
className={cl("navds-tabs", className, `navds-tabs--${size}`)}
|
|
70
|
+
activationMode={selectionFollowsFocus ? "automatic" : "manual"}
|
|
71
|
+
onValueChange={onChange}
|
|
72
|
+
>
|
|
73
|
+
<TabsContext.Provider
|
|
74
|
+
value={{
|
|
75
|
+
size,
|
|
76
|
+
}}
|
|
77
|
+
>
|
|
78
|
+
{children}
|
|
79
|
+
</TabsContext.Provider>
|
|
80
|
+
</RadixTabs.Root>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
) as TabsComponent;
|
|
84
|
+
|
|
85
|
+
Tabs.Tab = Tab;
|
|
86
|
+
Tabs.List = List;
|
|
87
|
+
Tabs.Panel = Panel;
|
|
88
|
+
|
|
89
|
+
export default Tabs;
|