@arbor-education/design-system.components 0.0.3 → 0.0.4
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/components/icon/Icon.stories.d.ts +7 -0
- package/dist/components/icon/Icon.stories.d.ts.map +1 -1
- package/dist/components/icon/Icon.stories.js +8 -0
- package/dist/components/icon/Icon.stories.js.map +1 -1
- package/dist/components/tabs/Tabs.d.ts +14 -18
- package/dist/components/tabs/Tabs.d.ts.map +1 -1
- package/dist/components/tabs/Tabs.js +6 -39
- package/dist/components/tabs/Tabs.js.map +1 -1
- package/dist/components/tabs/Tabs.stories.d.ts +35 -6
- package/dist/components/tabs/Tabs.stories.d.ts.map +1 -1
- package/dist/components/tabs/Tabs.stories.js +17 -45
- package/dist/components/tabs/Tabs.stories.js.map +1 -1
- package/dist/components/tabs/Tabs.test.d.ts.map +1 -1
- package/dist/components/tabs/Tabs.test.js +90 -97
- package/dist/components/tabs/Tabs.test.js.map +1 -1
- package/dist/components/tabs/TabsItem.d.ts +15 -0
- package/dist/components/tabs/TabsItem.d.ts.map +1 -0
- package/dist/components/tabs/TabsItem.js +18 -0
- package/dist/components/tabs/TabsItem.js.map +1 -0
- package/dist/components/tabs/TabsItem.stories.d.ts +618 -0
- package/dist/components/tabs/TabsItem.stories.d.ts.map +1 -0
- package/dist/components/tabs/TabsItem.stories.js +48 -0
- package/dist/components/tabs/TabsItem.stories.js.map +1 -0
- package/dist/index.css +56 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/icon/Icon.stories.tsx +8 -0
- package/src/components/tabs/Tabs.stories.tsx +92 -0
- package/src/components/tabs/Tabs.test.tsx +220 -0
- package/src/components/tabs/Tabs.tsx +14 -0
- package/src/components/tabs/TabsItem.stories.tsx +55 -0
- package/src/components/tabs/TabsItem.tsx +42 -0
- package/src/components/tabs/tabs.scss +61 -0
- package/src/index.scss +1 -0
- package/src/index.ts +1 -0
- package/src/tokens.scss +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Icon.stories.d.ts","sourceRoot":"","sources":["../../../src/components/icon/Icon.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"Icon.stories.d.ts","sourceRoot":"","sources":["../../../src/components/icon/Icon.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAG9B,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,IAAI,CAG3B,CAAC;AAEF,eAAO,MAAM,OAAO;;;;;;;;;;;;CAYnB,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Icon } from './Icon';
|
|
2
|
+
import { allowedIcons } from './allowedIcons';
|
|
2
3
|
const meta = {
|
|
3
4
|
title: 'Components/Icon',
|
|
4
5
|
component: Icon,
|
|
@@ -8,6 +9,13 @@ export const Default = {
|
|
|
8
9
|
name: '3-dot',
|
|
9
10
|
size: 16,
|
|
10
11
|
},
|
|
12
|
+
argTypes: {
|
|
13
|
+
name: {
|
|
14
|
+
control: 'select',
|
|
15
|
+
description: 'Icon name',
|
|
16
|
+
options: Object.keys(allowedIcons),
|
|
17
|
+
},
|
|
18
|
+
},
|
|
11
19
|
};
|
|
12
20
|
export default meta;
|
|
13
21
|
//# sourceMappingURL=Icon.stories.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Icon.stories.js","sourceRoot":"","sources":["../../../src/components/icon/Icon.stories.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"Icon.stories.js","sourceRoot":"","sources":["../../../src/components/icon/Icon.stories.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,MAAM,IAAI,GAAsB;IAC9B,KAAK,EAAE,iBAAiB;IACxB,SAAS,EAAE,IAAI;CAChB,CAAC;AAEF,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,IAAI,EAAE;QACJ,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,EAAE;KACT;IACD,QAAQ,EAAE;QACR,IAAI,EAAE;YACJ,OAAO,EAAE,QAAQ;YACjB,WAAW,EAAE,WAAW;YACxB,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC;SACnC;KACF;CACF,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -1,21 +1,17 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
type TabsProps = {
|
|
3
|
-
children: ReactNode;
|
|
4
|
-
defaultActiveTab?: string;
|
|
5
|
-
className?: string;
|
|
6
|
-
onTabChange?: (tabId: string) => void;
|
|
7
|
-
};
|
|
1
|
+
import { type HTMLAttributes } from 'react';
|
|
8
2
|
export declare const Tabs: {
|
|
9
|
-
(
|
|
10
|
-
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
3
|
+
(props: HTMLAttributes<HTMLUListElement> & {
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
Item: (props: {
|
|
7
|
+
active?: boolean;
|
|
8
|
+
iconName?: keyof typeof import("../icon/allowedIcons").allowedIcons;
|
|
9
|
+
} & (({
|
|
10
|
+
tabElement?: "button";
|
|
11
|
+
tabElementProps?: import("react").ButtonHTMLAttributes<HTMLButtonElement>;
|
|
12
|
+
} | {
|
|
13
|
+
tabElement?: "link";
|
|
14
|
+
tabElementProps?: import("react").AnchorHTMLAttributes<HTMLAnchorElement>;
|
|
15
|
+
}) & HTMLAttributes<HTMLLIElement>)) => import("react/jsx-runtime").JSX.Element;
|
|
18
16
|
};
|
|
19
|
-
export declare const TabsItem: ({ children, tabId, label, disabled, className, }: TabsItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
20
|
-
export {};
|
|
21
17
|
//# sourceMappingURL=Tabs.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../src/components/tabs/Tabs.tsx"],"names":[],"mappings":"AACA,
|
|
1
|
+
{"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../src/components/tabs/Tabs.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,OAAO,CAAC;AAG5C,eAAO,MAAM,IAAI;YAAW,cAAc,CAAC,gBAAgB,CAAC,GAAG;QAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;KAAE;;;;;;;;;;;CAO3F,CAAC"}
|
|
@@ -1,43 +1,10 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import classNames from 'classnames';
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
throw new Error('Tabs.Item must be used within a Tabs component');
|
|
9
|
-
}
|
|
10
|
-
return context;
|
|
3
|
+
import {} from 'react';
|
|
4
|
+
import { TabsItem } from './TabsItem';
|
|
5
|
+
export const Tabs = (props) => {
|
|
6
|
+
const { children, className, ...rest } = props;
|
|
7
|
+
return (_jsx("ul", { role: "tablist", className: classNames('ds-tabs', className), ...rest, children: children }));
|
|
11
8
|
};
|
|
12
|
-
export const Tabs = ({ children, defaultActiveTab, className = '', onTabChange, }) => {
|
|
13
|
-
const [activeTab, setActiveTab] = useState(defaultActiveTab || '');
|
|
14
|
-
const handleTabChange = (tabId) => {
|
|
15
|
-
setActiveTab(tabId);
|
|
16
|
-
onTabChange?.(tabId);
|
|
17
|
-
};
|
|
18
|
-
return (_jsx(TabsContext.Provider, { value: { activeTab, setActiveTab: handleTabChange }, children: _jsx("div", { className: classNames('ds-tabs', className), children: children }) }));
|
|
19
|
-
};
|
|
20
|
-
export const TabsItem = ({ children, tabId, label, disabled = false, className = '', }) => {
|
|
21
|
-
const { activeTab, setActiveTab } = useTabsContext();
|
|
22
|
-
const isActive = activeTab === tabId;
|
|
23
|
-
const handleClick = () => {
|
|
24
|
-
if (!disabled) {
|
|
25
|
-
setActiveTab(tabId);
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
const handleKeyDown = (e) => {
|
|
29
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
30
|
-
e.preventDefault();
|
|
31
|
-
if (!disabled) {
|
|
32
|
-
setActiveTab(tabId);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
return (_jsxs("div", { className: classNames('ds-tabs__item', className), children: [_jsx("button", { className: classNames('ds-tabs__tab', {
|
|
37
|
-
'ds-tabs__tab--active': isActive,
|
|
38
|
-
'ds-tabs__tab--disabled': disabled,
|
|
39
|
-
}), onClick: handleClick, onKeyDown: handleKeyDown, disabled: disabled, role: "tab", "aria-selected": isActive, "aria-controls": `tabpanel-${tabId}`, id: `tab-${tabId}`, tabIndex: isActive ? 0 : -1, children: label }), isActive && (_jsx("div", { className: "ds-tabs__content", role: "tabpanel", id: `tabpanel-${tabId}`, "aria-labelledby": `tab-${tabId}`, children: children }))] }));
|
|
40
|
-
};
|
|
41
|
-
// Compound component pattern
|
|
42
9
|
Tabs.Item = TabsItem;
|
|
43
10
|
//# sourceMappingURL=Tabs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tabs.js","sourceRoot":"","sources":["../../../src/components/tabs/Tabs.tsx"],"names":[],"mappings":";AAAA,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,
|
|
1
|
+
{"version":3,"file":"Tabs.js","sourceRoot":"","sources":["../../../src/components/tabs/Tabs.tsx"],"names":[],"mappings":";AAAA,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,EAAuB,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,KAAuE,EAAE,EAAE;IAC9F,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC;IAC/C,OAAO,CACL,aAAI,IAAI,EAAC,SAAS,EAAC,SAAS,EAAE,UAAU,CAAC,SAAS,EAAE,SAAS,CAAC,KAAM,IAAI,YACrE,QAAQ,GACN,CACN,CAAC;AACJ,CAAC,CAAC;AAEF,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC"}
|
|
@@ -1,11 +1,40 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import type { StoryObj } from '@storybook/react-vite';
|
|
2
|
+
declare const meta: {
|
|
3
|
+
title: string;
|
|
4
|
+
component: {
|
|
5
|
+
(props: import("react").HTMLAttributes<HTMLUListElement> & {
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
Item: (props: {
|
|
9
|
+
active?: boolean;
|
|
10
|
+
iconName?: keyof typeof import("../icon/allowedIcons").allowedIcons;
|
|
11
|
+
} & (({
|
|
12
|
+
tabElement?: "button";
|
|
13
|
+
tabElementProps?: import("react").ButtonHTMLAttributes<HTMLButtonElement>;
|
|
14
|
+
} | {
|
|
15
|
+
tabElement?: "link";
|
|
16
|
+
tabElementProps?: import("react").AnchorHTMLAttributes<HTMLAnchorElement>;
|
|
17
|
+
}) & import("react").HTMLAttributes<HTMLLIElement>)) => import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
};
|
|
19
|
+
parameters: {
|
|
20
|
+
layout: string;
|
|
21
|
+
};
|
|
22
|
+
tags: string[];
|
|
23
|
+
argTypes: {
|
|
24
|
+
children: {
|
|
25
|
+
control: false;
|
|
26
|
+
description: string;
|
|
27
|
+
};
|
|
28
|
+
className: {
|
|
29
|
+
control: "text";
|
|
30
|
+
description: string;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
};
|
|
4
34
|
export default meta;
|
|
5
35
|
type Story = StoryObj<typeof meta>;
|
|
6
36
|
export declare const Default: Story;
|
|
7
|
-
export declare const
|
|
37
|
+
export declare const WithLinks: Story;
|
|
38
|
+
export declare const Mixed: Story;
|
|
8
39
|
export declare const ManyTabs: Story;
|
|
9
|
-
export declare const WithRichContent: Story;
|
|
10
|
-
export declare const CustomStyling: Story;
|
|
11
40
|
//# sourceMappingURL=Tabs.stories.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tabs.stories.d.ts","sourceRoot":"","sources":["../../../src/components/tabs/Tabs.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"Tabs.stories.d.ts","sourceRoot":"","sources":["../../../src/components/tabs/Tabs.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAQ,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAG5D,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiBmB,CAAC;AAE9B,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAGnC,eAAO,MAAM,OAAO,EAAE,KAUrB,CAAC;AAGF,eAAO,MAAM,SAAS,EAAE,KAgBvB,CAAC;AAGF,eAAO,MAAM,KAAK,EAAE,KAenB,CAAC;AAGF,eAAO,MAAM,QAAQ,EAAE,KAetB,CAAC"}
|
|
@@ -1,74 +1,46 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Tabs } from './Tabs';
|
|
3
3
|
const meta = {
|
|
4
4
|
title: 'Components/Tabs',
|
|
5
5
|
component: Tabs,
|
|
6
6
|
parameters: {
|
|
7
7
|
layout: 'padded',
|
|
8
|
-
docs: {
|
|
9
|
-
description: {
|
|
10
|
-
component: 'A flexible tabs component with compound component pattern. Use Tabs.Item to create individual tab items.',
|
|
11
|
-
},
|
|
12
|
-
},
|
|
13
8
|
},
|
|
9
|
+
tags: ['autodocs'],
|
|
14
10
|
argTypes: {
|
|
15
|
-
|
|
16
|
-
control:
|
|
17
|
-
description: '
|
|
18
|
-
},
|
|
19
|
-
onTabChange: {
|
|
20
|
-
action: 'tab changed',
|
|
21
|
-
description: 'Callback function called when the active tab changes',
|
|
11
|
+
children: {
|
|
12
|
+
control: false,
|
|
13
|
+
description: 'Tab items to display',
|
|
22
14
|
},
|
|
23
15
|
className: {
|
|
24
16
|
control: 'text',
|
|
25
|
-
description: 'Additional CSS
|
|
17
|
+
description: 'Additional CSS classes',
|
|
26
18
|
},
|
|
27
19
|
},
|
|
28
20
|
};
|
|
29
21
|
export default meta;
|
|
22
|
+
// Basic tabs with buttons
|
|
30
23
|
export const Default = {
|
|
31
24
|
args: {
|
|
32
|
-
|
|
33
|
-
},
|
|
34
|
-
render: (args) => (_jsxs(Tabs, { ...args, children: [_jsx(Tabs.Item, { tabId: "tab1", label: "Overview", children: _jsxs("div", { children: [_jsx("h3", { children: "Overview" }), _jsx("p", { children: "This is the overview tab content. It contains general information about the topic." })] }) }), _jsx(Tabs.Item, { tabId: "tab2", label: "Details", children: _jsxs("div", { children: [_jsx("h3", { children: "Details" }), _jsx("p", { children: "This is the details tab content. It provides more specific information and data." })] }) }), _jsx(Tabs.Item, { tabId: "tab3", label: "Settings", children: _jsxs("div", { children: [_jsx("h3", { children: "Settings" }), _jsx("p", { children: "This is the settings tab content. It contains configuration options and preferences." })] }) })] })),
|
|
35
|
-
};
|
|
36
|
-
export const WithDisabledTab = {
|
|
37
|
-
args: {
|
|
38
|
-
defaultActiveTab: 'tab1',
|
|
25
|
+
children: (_jsxs(_Fragment, { children: [_jsx(Tabs.Item, { active: true, children: "Overview" }), _jsx(Tabs.Item, { children: "Details" }), _jsx(Tabs.Item, { children: "Settings" })] })),
|
|
39
26
|
},
|
|
40
|
-
render: (args) => (_jsxs(Tabs, { ...args, children: [_jsx(Tabs.Item, { tabId: "tab1", label: "Available", children: _jsxs("div", { children: [_jsx("h3", { children: "Available" }), _jsx("p", { children: "This tab is available and can be clicked." })] }) }), _jsx(Tabs.Item, { tabId: "tab2", label: "Disabled", disabled: true, children: _jsxs("div", { children: [_jsx("h3", { children: "Disabled" }), _jsx("p", { children: "This tab is disabled and cannot be clicked." })] }) }), _jsx(Tabs.Item, { tabId: "tab3", label: "Another Available", children: _jsxs("div", { children: [_jsx("h3", { children: "Another Available" }), _jsx("p", { children: "This tab is also available and can be clicked." })] }) })] })),
|
|
41
27
|
};
|
|
42
|
-
|
|
28
|
+
// Tabs with links
|
|
29
|
+
export const WithLinks = {
|
|
43
30
|
args: {
|
|
44
|
-
|
|
31
|
+
children: (_jsxs(_Fragment, { children: [_jsx(Tabs.Item, { tabElement: "link", tabElementProps: { href: '#overview' }, active: true, children: "Overview" }), _jsx(Tabs.Item, { tabElement: "link", tabElementProps: { href: '#details' }, children: "Details" }), _jsx(Tabs.Item, { tabElement: "link", tabElementProps: { href: '#settings' }, children: "Settings" })] })),
|
|
45
32
|
},
|
|
46
|
-
render: (args) => (_jsxs(Tabs, { ...args, children: [_jsx(Tabs.Item, { tabId: "tab1", label: "First", children: _jsxs("div", { children: [_jsx("h3", { children: "First Tab" }), _jsx("p", { children: "Content for the first tab." })] }) }), _jsx(Tabs.Item, { tabId: "tab2", label: "Second", children: _jsxs("div", { children: [_jsx("h3", { children: "Second Tab" }), _jsx("p", { children: "Content for the second tab." })] }) }), _jsx(Tabs.Item, { tabId: "tab3", label: "Third", children: _jsxs("div", { children: [_jsx("h3", { children: "Third Tab" }), _jsx("p", { children: "Content for the third tab." })] }) }), _jsx(Tabs.Item, { tabId: "tab4", label: "Fourth", children: _jsxs("div", { children: [_jsx("h3", { children: "Fourth Tab" }), _jsx("p", { children: "Content for the fourth tab." })] }) }), _jsx(Tabs.Item, { tabId: "tab5", label: "Fifth", children: _jsxs("div", { children: [_jsx("h3", { children: "Fifth Tab" }), _jsx("p", { children: "Content for the fifth tab." })] }) }), _jsx(Tabs.Item, { tabId: "tab6", label: "Sixth", children: _jsxs("div", { children: [_jsx("h3", { children: "Sixth Tab" }), _jsx("p", { children: "Content for the sixth tab." })] }) })] })),
|
|
47
33
|
};
|
|
48
|
-
|
|
34
|
+
// Mixed tabs (buttons and links)
|
|
35
|
+
export const Mixed = {
|
|
49
36
|
args: {
|
|
50
|
-
|
|
37
|
+
children: (_jsxs(_Fragment, { children: [_jsx(Tabs.Item, { active: true, children: "Home" }), _jsx(Tabs.Item, { tabElement: "link", tabElementProps: { href: '#about' }, children: "About" }), _jsx(Tabs.Item, { children: "Contact" }), _jsx(Tabs.Item, { tabElement: "link", tabElementProps: { href: '#help' }, children: "Help" })] })),
|
|
51
38
|
},
|
|
52
|
-
render: (args) => (_jsxs(Tabs, { ...args, children: [_jsx(Tabs.Item, { tabId: "dashboard", label: "Dashboard", children: _jsxs("div", { children: [_jsx("h3", { children: "Dashboard" }), _jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '16px', marginTop: '16px' }, children: [_jsxs("div", { style: { padding: '16px', backgroundColor: '#f5f5f5', borderRadius: '8px' }, children: [_jsx("h4", { children: "Total Users" }), _jsx("p", { style: { fontSize: '24px', fontWeight: 'bold', margin: '8px 0' }, children: "1,234" })] }), _jsxs("div", { style: { padding: '16px', backgroundColor: '#f5f5f5', borderRadius: '8px' }, children: [_jsx("h4", { children: "Active Sessions" }), _jsx("p", { style: { fontSize: '24px', fontWeight: 'bold', margin: '8px 0' }, children: "567" })] })] })] }) }), _jsx(Tabs.Item, { tabId: "analytics", label: "Analytics", children: _jsxs("div", { children: [_jsx("h3", { children: "Analytics" }), _jsx("p", { children: "View detailed analytics and reports for your application." }), _jsxs("ul", { style: { marginTop: '16px' }, children: [_jsx("li", { children: "Page views" }), _jsx("li", { children: "User engagement" }), _jsx("li", { children: "Conversion rates" }), _jsx("li", { children: "Performance metrics" })] })] }) }), _jsx(Tabs.Item, { tabId: "settings", label: "Settings", children: _jsxs("div", { children: [_jsx("h3", { children: "Settings" }), _jsxs("form", { style: { marginTop: '16px' }, children: [_jsxs("div", { style: { marginBottom: '16px' }, children: [_jsx("label", { htmlFor: "theme", children: "Theme:" }), _jsxs("select", { id: "theme", style: { marginLeft: '8px', padding: '4px 8px' }, children: [_jsx("option", { children: "Light" }), _jsx("option", { children: "Dark" }), _jsx("option", { children: "Auto" })] })] }), _jsx("div", { style: { marginBottom: '16px' }, children: _jsxs("label", { children: [_jsx("input", { type: "checkbox", style: { marginRight: '8px' } }), "Enable notifications"] }) }), _jsx("button", { type: "submit", style: { padding: '8px 16px', backgroundColor: '#007bff', color: 'white', border: 'none', borderRadius: '4px' }, children: "Save Settings" })] })] }) })] })),
|
|
53
39
|
};
|
|
54
|
-
|
|
40
|
+
// Many tabs
|
|
41
|
+
export const ManyTabs = {
|
|
55
42
|
args: {
|
|
56
|
-
|
|
57
|
-
className: 'custom-tabs-container',
|
|
43
|
+
children: (_jsxs(_Fragment, { children: [_jsx(Tabs.Item, { active: true, iconName: "list", children: "Tab 1" }), _jsx(Tabs.Item, { iconName: "list", children: "Tab 2" }), _jsx(Tabs.Item, { iconName: "list", children: "Tab 3" }), _jsx(Tabs.Item, { iconName: "list", children: "Tab 4" }), _jsx(Tabs.Item, { iconName: "list", children: "Tab 5" }), _jsx(Tabs.Item, { iconName: "list", children: "Tab 6" }), _jsx(Tabs.Item, { iconName: "list", children: "Tab 7" }), _jsx(Tabs.Item, { iconName: "list", children: "Tab 8" })] })),
|
|
58
44
|
},
|
|
59
|
-
render: (args) => (_jsxs("div", { children: [_jsx("style", { children: `
|
|
60
|
-
.custom-tabs-container {
|
|
61
|
-
border: 2px solid #e0e0e0;
|
|
62
|
-
border-radius: 8px;
|
|
63
|
-
padding: 16px;
|
|
64
|
-
}
|
|
65
|
-
.custom-tabs-container .ds-tabs__tab {
|
|
66
|
-
border-radius: 4px;
|
|
67
|
-
margin-right: 4px;
|
|
68
|
-
}
|
|
69
|
-
.custom-tabs-container .ds-tabs__tab--active {
|
|
70
|
-
background-color: #f0f8ff;
|
|
71
|
-
}
|
|
72
|
-
` }), _jsxs(Tabs, { ...args, children: [_jsx(Tabs.Item, { tabId: "tab1", label: "Styled Tab 1", children: _jsxs("div", { children: [_jsx("h3", { children: "Custom Styled Tab" }), _jsx("p", { children: "This tab has custom styling applied to the container." })] }) }), _jsx(Tabs.Item, { tabId: "tab2", label: "Styled Tab 2", children: _jsxs("div", { children: [_jsx("h3", { children: "Another Custom Tab" }), _jsx("p", { children: "Notice the custom border and styling around the tabs container." })] }) })] })] })),
|
|
73
45
|
};
|
|
74
46
|
//# sourceMappingURL=Tabs.stories.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tabs.stories.js","sourceRoot":"","sources":["../../../src/components/tabs/Tabs.stories.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,MAAM,IAAI,
|
|
1
|
+
{"version":3,"file":"Tabs.stories.js","sourceRoot":"","sources":["../../../src/components/tabs/Tabs.stories.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,MAAM,IAAI,GAAG;IACX,KAAK,EAAE,iBAAiB;IACxB,SAAS,EAAE,IAAI;IACf,UAAU,EAAE;QACV,MAAM,EAAE,QAAQ;KACjB;IACD,IAAI,EAAE,CAAC,UAAU,CAAC;IAClB,QAAQ,EAAE;QACR,QAAQ,EAAE;YACR,OAAO,EAAE,KAAK;YACd,WAAW,EAAE,sBAAsB;SACpC;QACD,SAAS,EAAE;YACT,OAAO,EAAE,MAAM;YACf,WAAW,EAAE,wBAAwB;SACtC;KACF;CAC0B,CAAC;AAE9B,eAAe,IAAI,CAAC;AAGpB,0BAA0B;AAC1B,MAAM,CAAC,MAAM,OAAO,GAAU;IAC5B,IAAI,EAAE;QACJ,QAAQ,EAAE,CACR,8BACE,KAAC,IAAI,CAAC,IAAI,IAAC,MAAM,+BAAqB,EACtC,KAAC,IAAI,CAAC,IAAI,0BAAoB,EAC9B,KAAC,IAAI,CAAC,IAAI,2BAAqB,IAC9B,CACJ;KACF;CACF,CAAC;AAEF,kBAAkB;AAClB,MAAM,CAAC,MAAM,SAAS,GAAU;IAC9B,IAAI,EAAE;QACJ,QAAQ,EAAE,CACR,8BACE,KAAC,IAAI,CAAC,IAAI,IAAC,UAAU,EAAC,MAAM,EAAC,eAAe,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,MAAM,+BAE/D,EACZ,KAAC,IAAI,CAAC,IAAI,IAAC,UAAU,EAAC,MAAM,EAAC,eAAe,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,wBAEtD,EACZ,KAAC,IAAI,CAAC,IAAI,IAAC,UAAU,EAAC,MAAM,EAAC,eAAe,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,yBAEvD,IACX,CACJ;KACF;CACF,CAAC;AAEF,iCAAiC;AACjC,MAAM,CAAC,MAAM,KAAK,GAAU;IAC1B,IAAI,EAAE;QACJ,QAAQ,EAAE,CACR,8BACE,KAAC,IAAI,CAAC,IAAI,IAAC,MAAM,2BAAiB,EAClC,KAAC,IAAI,CAAC,IAAI,IAAC,UAAU,EAAC,MAAM,EAAC,eAAe,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,sBAEpD,EACZ,KAAC,IAAI,CAAC,IAAI,0BAAoB,EAC9B,KAAC,IAAI,CAAC,IAAI,IAAC,UAAU,EAAC,MAAM,EAAC,eAAe,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,qBAEnD,IACX,CACJ;KACF;CACF,CAAC;AAEF,YAAY;AACZ,MAAM,CAAC,MAAM,QAAQ,GAAU;IAC7B,IAAI,EAAE;QACJ,QAAQ,EAAE,CACR,8BACE,KAAC,IAAI,CAAC,IAAI,IAAC,MAAM,QAAC,QAAQ,EAAC,MAAM,sBAAkB,EACnD,KAAC,IAAI,CAAC,IAAI,IAAC,QAAQ,EAAC,MAAM,sBAAkB,EAC5C,KAAC,IAAI,CAAC,IAAI,IAAC,QAAQ,EAAC,MAAM,sBAAkB,EAC5C,KAAC,IAAI,CAAC,IAAI,IAAC,QAAQ,EAAC,MAAM,sBAAkB,EAC5C,KAAC,IAAI,CAAC,IAAI,IAAC,QAAQ,EAAC,MAAM,sBAAkB,EAC5C,KAAC,IAAI,CAAC,IAAI,IAAC,QAAQ,EAAC,MAAM,sBAAkB,EAC5C,KAAC,IAAI,CAAC,IAAI,IAAC,QAAQ,EAAC,MAAM,sBAAkB,EAC5C,KAAC,IAAI,CAAC,IAAI,IAAC,QAAQ,EAAC,MAAM,sBAAkB,IAC3C,CACJ;KACF;CACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tabs.test.d.ts","sourceRoot":"","sources":["../../../src/components/tabs/Tabs.test.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Tabs.test.d.ts","sourceRoot":"","sources":["../../../src/components/tabs/Tabs.test.tsx"],"names":[],"mappings":"AAGA,OAAO,kCAAkC,CAAC"}
|
|
@@ -1,115 +1,108 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { expect, test, describe, vi } from
|
|
3
|
-
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
4
|
-
import userEvent from '@testing-library/user-event';
|
|
2
|
+
import { expect, test, describe, vi } from 'vitest';
|
|
5
3
|
import { Tabs } from './Tabs';
|
|
4
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
6
5
|
import '@testing-library/jest-dom/vitest';
|
|
7
|
-
describe('Tabs
|
|
8
|
-
test('renders tabs with
|
|
9
|
-
render(_jsxs(Tabs, {
|
|
10
|
-
|
|
11
|
-
expect(
|
|
12
|
-
expect(
|
|
13
|
-
expect(
|
|
6
|
+
describe('Tabs component', () => {
|
|
7
|
+
test('renders tabs container with correct role', () => {
|
|
8
|
+
render(_jsxs(Tabs, { children: [_jsx(Tabs.Item, { children: "Tab 1" }), _jsx(Tabs.Item, { children: "Tab 2" })] }));
|
|
9
|
+
const tabsContainer = screen.getByRole('tablist');
|
|
10
|
+
expect(tabsContainer).toBeInTheDocument();
|
|
11
|
+
expect(tabsContainer.tagName).toBe('UL');
|
|
12
|
+
expect(tabsContainer).toHaveClass('ds-tabs');
|
|
14
13
|
});
|
|
15
|
-
test('
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
expect(screen.getByText('Content 2')).toBeInTheDocument();
|
|
21
|
-
expect(screen.queryByText('Content 1')).not.toBeInTheDocument();
|
|
14
|
+
test('renders children correctly', () => {
|
|
15
|
+
render(_jsxs(Tabs, { children: [_jsx(Tabs.Item, { children: "Overview" }), _jsx(Tabs.Item, { children: "Details" }), _jsx(Tabs.Item, { children: "Settings" })] }));
|
|
16
|
+
expect(screen.getByText('Overview')).toBeInTheDocument();
|
|
17
|
+
expect(screen.getByText('Details')).toBeInTheDocument();
|
|
18
|
+
expect(screen.getByText('Settings')).toBeInTheDocument();
|
|
22
19
|
});
|
|
23
|
-
test('
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
const tab2Button = screen.getByText('Tab 2');
|
|
28
|
-
await user.click(tab2Button);
|
|
29
|
-
expect(onTabChange).toHaveBeenCalledWith('tab2');
|
|
20
|
+
test('applies custom className', () => {
|
|
21
|
+
render(_jsx(Tabs, { className: "custom-tabs", children: _jsx(Tabs.Item, { children: "Tab 1" }) }));
|
|
22
|
+
const tabsContainer = screen.getByRole('tablist');
|
|
23
|
+
expect(tabsContainer).toHaveClass('ds-tabs', 'custom-tabs');
|
|
30
24
|
});
|
|
31
|
-
test('
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
tab2Button.focus();
|
|
36
|
-
await user.keyboard('{Enter}');
|
|
37
|
-
expect(screen.getByText('Content 2')).toBeInTheDocument();
|
|
38
|
-
expect(screen.queryByText('Content 1')).not.toBeInTheDocument();
|
|
25
|
+
test('passes through additional props', () => {
|
|
26
|
+
render(_jsx(Tabs, { "data-testid": "tabs-container", "aria-label": "Navigation tabs", children: _jsx(Tabs.Item, { children: "Tab 1" }) }));
|
|
27
|
+
const tabsContainer = screen.getByTestId('tabs-container');
|
|
28
|
+
expect(tabsContainer).toHaveAttribute('aria-label', 'Navigation tabs');
|
|
39
29
|
});
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
expect(
|
|
47
|
-
|
|
30
|
+
});
|
|
31
|
+
describe('TabsItem component', () => {
|
|
32
|
+
test('renders as button by default', () => {
|
|
33
|
+
render(_jsx(Tabs, { children: _jsx(Tabs.Item, { children: "Tab Button" }) }));
|
|
34
|
+
const tabButton = screen.getByRole('tab');
|
|
35
|
+
expect(tabButton.tagName).toBe('BUTTON');
|
|
36
|
+
expect(tabButton).toHaveTextContent('Tab Button');
|
|
37
|
+
});
|
|
38
|
+
test('renders as link when tabElement is link', () => {
|
|
39
|
+
render(_jsx(Tabs, { children: _jsx(Tabs.Item, { tabElement: "link", tabElementProps: { href: '#overview' }, children: "Overview Link" }) }));
|
|
40
|
+
const tabLink = screen.getByRole('tab');
|
|
41
|
+
expect(tabLink.tagName).toBe('A');
|
|
42
|
+
expect(tabLink).toHaveAttribute('href', '#overview');
|
|
43
|
+
expect(tabLink).toHaveTextContent('Overview Link');
|
|
48
44
|
});
|
|
49
|
-
test('
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
expect(
|
|
56
|
-
expect(
|
|
57
|
-
expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
|
|
45
|
+
test('applies active state correctly', () => {
|
|
46
|
+
render(_jsxs(Tabs, { children: [_jsx(Tabs.Item, { active: true, children: "Active Tab" }), _jsx(Tabs.Item, { children: "Inactive Tab" })] }));
|
|
47
|
+
const activeTab = screen.getByText('Active Tab');
|
|
48
|
+
const inactiveTab = screen.getByText('Inactive Tab');
|
|
49
|
+
expect(activeTab).toHaveClass('ds-tabs-item__tab--active');
|
|
50
|
+
expect(activeTab).toHaveAttribute('aria-selected', 'true');
|
|
51
|
+
expect(inactiveTab).not.toHaveClass('ds-tabs-item__tab--active');
|
|
52
|
+
expect(inactiveTab).toHaveAttribute('aria-selected', 'false');
|
|
58
53
|
});
|
|
59
|
-
test('
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
await user.keyboard('{Enter}');
|
|
66
|
-
expect(onTabChange).not.toHaveBeenCalled();
|
|
67
|
-
expect(screen.getByText('Content 1')).toBeInTheDocument();
|
|
68
|
-
expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
|
|
54
|
+
test('applies correct CSS classes', () => {
|
|
55
|
+
render(_jsx(Tabs, { children: _jsx(Tabs.Item, { children: "Tab Item" }) }));
|
|
56
|
+
const listItem = screen.getByRole('presentation');
|
|
57
|
+
const tabElement = screen.getByRole('tab');
|
|
58
|
+
expect(listItem).toHaveClass('ds-tabs-item');
|
|
59
|
+
expect(tabElement).toHaveClass('ds-tabs-item__tab');
|
|
69
60
|
});
|
|
70
|
-
test('applies custom className to
|
|
71
|
-
render(_jsx(Tabs, {
|
|
72
|
-
const
|
|
73
|
-
expect(
|
|
61
|
+
test('applies custom className to list item', () => {
|
|
62
|
+
render(_jsx(Tabs, { children: _jsx(Tabs.Item, { className: "custom-tab-item", children: "Tab Item" }) }));
|
|
63
|
+
const listItem = screen.getByRole('presentation');
|
|
64
|
+
expect(listItem).toHaveClass('ds-tabs-item', 'custom-tab-item');
|
|
74
65
|
});
|
|
75
|
-
test('
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
66
|
+
test('handles click events on button tabs', () => {
|
|
67
|
+
const handleClick = vi.fn();
|
|
68
|
+
render(_jsx(Tabs, { children: _jsx(Tabs.Item, { tabElementProps: { onClick: handleClick }, children: "Clickable Tab" }) }));
|
|
69
|
+
fireEvent.click(screen.getByRole('tab'));
|
|
70
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
79
71
|
});
|
|
80
|
-
test('
|
|
81
|
-
render(
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
expect(tab1Button).toHaveAttribute('role', 'tab');
|
|
85
|
-
expect(tab1Button).toHaveAttribute('aria-selected', 'true');
|
|
86
|
-
expect(tab1Button).toHaveAttribute('aria-controls', 'tabpanel-tab1');
|
|
87
|
-
expect(tab1Button).toHaveAttribute('id', 'tab-tab1');
|
|
88
|
-
expect(tab2Button).toHaveAttribute('role', 'tab');
|
|
89
|
-
expect(tab2Button).toHaveAttribute('aria-selected', 'false');
|
|
90
|
-
expect(tab2Button).toHaveAttribute('aria-controls', 'tabpanel-tab2');
|
|
91
|
-
expect(tab2Button).toHaveAttribute('id', 'tab-tab2');
|
|
92
|
-
const contentPanel = screen.getByText('Content 1');
|
|
93
|
-
expect(contentPanel).toHaveAttribute('role', 'tabpanel');
|
|
94
|
-
expect(contentPanel).toHaveAttribute('id', 'tabpanel-tab1');
|
|
95
|
-
expect(contentPanel).toHaveAttribute('aria-labelledby', 'tab-tab1');
|
|
72
|
+
test('passes through additional props to button', () => {
|
|
73
|
+
render(_jsx(Tabs, { children: _jsx(Tabs.Item, { tabElementProps: { 'disabled': true, 'data-testid': 'tab-button' }, children: "Disabled Tab" }) }));
|
|
74
|
+
const tabButton = screen.getByTestId('tab-button');
|
|
75
|
+
expect(tabButton).toBeDisabled();
|
|
96
76
|
});
|
|
97
|
-
test('
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
77
|
+
test('passes through additional props to link', () => {
|
|
78
|
+
render(_jsx(Tabs, { children: _jsx(Tabs.Item, { tabElement: "link", tabElementProps: {
|
|
79
|
+
'href': '#test',
|
|
80
|
+
'target': '_blank',
|
|
81
|
+
// @ts-expect-error - data-testid is not a valid prop for AnchorHTMLAttributes
|
|
82
|
+
'data-testid': 'tab-link',
|
|
83
|
+
}, children: "Link Tab" }) }));
|
|
84
|
+
const tabLink = screen.getByTestId('tab-link');
|
|
85
|
+
expect(tabLink).toHaveAttribute('href', '#test');
|
|
86
|
+
expect(tabLink).toHaveAttribute('target', '_blank');
|
|
104
87
|
});
|
|
105
88
|
test('renders multiple tabs correctly', () => {
|
|
106
|
-
render(_jsxs(Tabs, {
|
|
107
|
-
|
|
108
|
-
expect(
|
|
109
|
-
expect(
|
|
110
|
-
expect(
|
|
111
|
-
expect(
|
|
112
|
-
expect(
|
|
89
|
+
render(_jsxs(Tabs, { children: [_jsx(Tabs.Item, { active: true, children: "Tab 1" }), _jsx(Tabs.Item, { children: "Tab 2" }), _jsx(Tabs.Item, { tabElement: "link", tabElementProps: { href: '#tab3' }, children: "Tab 3" })] }));
|
|
90
|
+
const tabs = screen.getAllByRole('tab');
|
|
91
|
+
expect(tabs).toHaveLength(3);
|
|
92
|
+
expect(tabs[0]).toHaveTextContent('Tab 1');
|
|
93
|
+
expect(tabs[0]).toHaveAttribute('aria-selected', 'true');
|
|
94
|
+
expect(tabs[1]).toHaveTextContent('Tab 2');
|
|
95
|
+
expect(tabs[1]).toHaveAttribute('aria-selected', 'false');
|
|
96
|
+
expect(tabs[2]).toHaveTextContent('Tab 3');
|
|
97
|
+
expect(tabs[2]).toHaveAttribute('href', '#tab3');
|
|
98
|
+
});
|
|
99
|
+
test('handles mixed tab types', () => {
|
|
100
|
+
render(_jsxs(Tabs, { children: [_jsx(Tabs.Item, { active: true, children: "Button Tab" }), _jsx(Tabs.Item, { tabElement: "link", tabElementProps: { href: '#link-tab' }, children: "Link Tab" })] }));
|
|
101
|
+
const buttonTab = screen.getByText('Button Tab');
|
|
102
|
+
const linkTab = screen.getByText('Link Tab');
|
|
103
|
+
expect(buttonTab.tagName).toBe('BUTTON');
|
|
104
|
+
expect(linkTab.tagName).toBe('A');
|
|
105
|
+
expect(linkTab).toHaveAttribute('href', '#link-tab');
|
|
113
106
|
});
|
|
114
107
|
});
|
|
115
108
|
//# sourceMappingURL=Tabs.test.js.map
|