@usefui/components 1.5.1
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/CHANGELOG.md +233 -0
- package/LICENSE +21 -0
- package/README.md +0 -0
- package/babel.config.js +12 -0
- package/dist/index.d.mts +1299 -0
- package/dist/index.d.ts +1299 -0
- package/dist/index.js +3701 -0
- package/dist/index.mjs +3586 -0
- package/package.json +44 -0
- package/src/__tests__/Accordion.test.tsx +106 -0
- package/src/__tests__/Avatar.test.tsx +89 -0
- package/src/__tests__/Badge.test.tsx +58 -0
- package/src/__tests__/Button.test.tsx +88 -0
- package/src/__tests__/Checkbox.test.tsx +106 -0
- package/src/__tests__/Collapsible.test.tsx +79 -0
- package/src/__tests__/Dialog.test.tsx +109 -0
- package/src/__tests__/Dropdown.test.tsx +159 -0
- package/src/__tests__/Field.test.tsx +100 -0
- package/src/__tests__/OTPField.test.tsx +199 -0
- package/src/__tests__/Overlay.test.tsx +70 -0
- package/src/__tests__/Page.test.tsx +98 -0
- package/src/__tests__/Portal.test.tsx +28 -0
- package/src/__tests__/Sheet.test.tsx +125 -0
- package/src/__tests__/Switch.test.tsx +90 -0
- package/src/__tests__/Tabs.test.tsx +129 -0
- package/src/__tests__/Toggle.test.tsx +67 -0
- package/src/__tests__/Toolbar.test.tsx +147 -0
- package/src/__tests__/Tooltip.test.tsx +88 -0
- package/src/accordion/Accordion.stories.tsx +89 -0
- package/src/accordion/hooks/index.tsx +39 -0
- package/src/accordion/index.tsx +170 -0
- package/src/avatar/Avatar.stories.tsx +62 -0
- package/src/avatar/index.tsx +90 -0
- package/src/avatar/styles/index.ts +79 -0
- package/src/badge/Badge.stories.tsx +60 -0
- package/src/badge/index.tsx +58 -0
- package/src/badge/styles/index.ts +109 -0
- package/src/button/Button.stories.tsx +47 -0
- package/src/button/index.tsx +79 -0
- package/src/button/styles/index.ts +180 -0
- package/src/checkbox/Checkbox.stories.tsx +100 -0
- package/src/checkbox/hooks/index.tsx +40 -0
- package/src/checkbox/index.tsx +147 -0
- package/src/checkbox/styles/index.ts +139 -0
- package/src/collapsible/Collapsible.stories.tsx +95 -0
- package/src/collapsible/hooks/index.tsx +50 -0
- package/src/collapsible/index.tsx +137 -0
- package/src/dialog/Dialog.stories.tsx +73 -0
- package/src/dialog/hooks/index.tsx +35 -0
- package/src/dialog/index.tsx +221 -0
- package/src/dialog/styles/index.ts +72 -0
- package/src/divider/index.ts +10 -0
- package/src/dropdown/Dropdown.stories.tsx +100 -0
- package/src/dropdown/hooks/index.tsx +64 -0
- package/src/dropdown/index.tsx +316 -0
- package/src/dropdown/styles/index.ts +90 -0
- package/src/field/Field.stories.tsx +146 -0
- package/src/field/hooks/index.tsx +28 -0
- package/src/field/index.tsx +183 -0
- package/src/field/styles/index.ts +166 -0
- package/src/index.ts +33 -0
- package/src/otp-field/OTPField.stories.tsx +50 -0
- package/src/otp-field/hooks/index.tsx +13 -0
- package/src/otp-field/index.tsx +234 -0
- package/src/otp-field/styles/index.ts +33 -0
- package/src/otp-field/types/index.ts +23 -0
- package/src/overlay/Overlay.stories.tsx +59 -0
- package/src/overlay/index.tsx +58 -0
- package/src/overlay/styles/index.ts +26 -0
- package/src/page/Page.stories.tsx +85 -0
- package/src/page/index.tsx +265 -0
- package/src/page/styles/index.ts +59 -0
- package/src/portal/Portal.stories.tsx +27 -0
- package/src/portal/index.tsx +36 -0
- package/src/scrollarea/Scrollarea.stories.tsx +99 -0
- package/src/scrollarea/index.tsx +27 -0
- package/src/scrollarea/styles/index.ts +71 -0
- package/src/sheet/Sheet.stories.tsx +86 -0
- package/src/sheet/hooks/index.tsx +47 -0
- package/src/sheet/index.tsx +190 -0
- package/src/sheet/styles/index.ts +69 -0
- package/src/switch/Switch.stories.tsx +96 -0
- package/src/switch/hooks/index.tsx +33 -0
- package/src/switch/index.tsx +122 -0
- package/src/switch/styles/index.ts +118 -0
- package/src/table/index.tsx +138 -0
- package/src/table/styles/index.ts +48 -0
- package/src/tabs/Tabs.stories.tsx +87 -0
- package/src/tabs/hooks/index.tsx +35 -0
- package/src/tabs/index.tsx +161 -0
- package/src/tabs/styles/index.ts +9 -0
- package/src/toggle/Toggle.stories.tsx +118 -0
- package/src/toggle/index.tsx +55 -0
- package/src/toggle/styles/index.ts +0 -0
- package/src/toolbar/Toolbar.stories.tsx +89 -0
- package/src/toolbar/hooks/index.tsx +35 -0
- package/src/toolbar/index.tsx +243 -0
- package/src/toolbar/styles/index.ts +129 -0
- package/src/tooltip/Tooltip.stories.tsx +60 -0
- package/src/tooltip/index.tsx +177 -0
- package/src/tooltip/styles/index.ts +38 -0
- package/src/utils/index.ts +2 -0
- package/tsconfig.json +18 -0
- package/vitest.config.ts +16 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React, { useState, createContext, useContext } from "react";
|
|
2
|
+
import { IReactChildren, IComponentAPI } from "../../../../../types";
|
|
3
|
+
|
|
4
|
+
const defaultComponentAPI = {
|
|
5
|
+
id: "",
|
|
6
|
+
states: {},
|
|
7
|
+
methods: {},
|
|
8
|
+
};
|
|
9
|
+
const SwitchContext = createContext<IComponentAPI>(defaultComponentAPI);
|
|
10
|
+
export const useSwitch = () => useContext(SwitchContext);
|
|
11
|
+
|
|
12
|
+
export const SwitchProvider = ({ children }: IReactChildren): JSX.Element => {
|
|
13
|
+
const context = useSwitchProvider();
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<SwitchContext.Provider value={context}>{children}</SwitchContext.Provider>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function useSwitchProvider(): IComponentAPI {
|
|
21
|
+
const [checked, setChecked] = useState<boolean>(false);
|
|
22
|
+
const switchId = React.useId();
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
id: switchId,
|
|
26
|
+
states: {
|
|
27
|
+
checked,
|
|
28
|
+
},
|
|
29
|
+
methods: {
|
|
30
|
+
toggleSwitch: (): boolean | void => setChecked(!checked),
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { SwitchProvider, useSwitch } from "./hooks";
|
|
5
|
+
import { TriggerWrapper, Thumb } from "./styles";
|
|
6
|
+
import {
|
|
7
|
+
IReactChildren,
|
|
8
|
+
IComponentStyling,
|
|
9
|
+
ComponentSizeEnum,
|
|
10
|
+
ComponentVariantEnum,
|
|
11
|
+
IComponentSize,
|
|
12
|
+
IComponentVariant,
|
|
13
|
+
} from "../../../../types";
|
|
14
|
+
|
|
15
|
+
export interface ISwitchComposition {
|
|
16
|
+
Root: typeof SwitchRoot;
|
|
17
|
+
Thumb: typeof SwitchThumb;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ISwitchProperties
|
|
21
|
+
extends React.ComponentProps<"button">,
|
|
22
|
+
IComponentSize,
|
|
23
|
+
IComponentVariant,
|
|
24
|
+
IComponentStyling {
|
|
25
|
+
defaultChecked?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface ISwitchThumbProperties
|
|
28
|
+
extends React.ComponentProps<"span">,
|
|
29
|
+
IComponentSize,
|
|
30
|
+
IComponentStyling {}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Switch are toggle components that allows the user to turn a setting on or off.
|
|
34
|
+
*
|
|
35
|
+
* **Best practices:**
|
|
36
|
+
*
|
|
37
|
+
* - Use a clear and descriptive label for each switch.
|
|
38
|
+
* - The interaction must have predictable behavior.
|
|
39
|
+
*
|
|
40
|
+
* @param {ISwitchProperties} props - The props for the Switch component.
|
|
41
|
+
* @param {boolean} props.raw - Whether the switch should be rendered without any styles.
|
|
42
|
+
* @param {ComponentSizeEnum} props.sizing - The size of the switch.
|
|
43
|
+
* @param {ComponentVariantEnum} props.variant - The variant of the switch.
|
|
44
|
+
* @param {boolean} props.defaultChecked - The initial state of the switch.
|
|
45
|
+
* @param {ReactNode} props.children - The content to be rendered inside the switch.
|
|
46
|
+
* @returns {ReactElement} The Switch component.
|
|
47
|
+
*/
|
|
48
|
+
const Switch = (props: ISwitchProperties) => {
|
|
49
|
+
const {
|
|
50
|
+
raw,
|
|
51
|
+
sizing = ComponentSizeEnum.Medium,
|
|
52
|
+
variant = ComponentVariantEnum.Primary,
|
|
53
|
+
value,
|
|
54
|
+
defaultChecked,
|
|
55
|
+
disabled,
|
|
56
|
+
onClick,
|
|
57
|
+
children,
|
|
58
|
+
...restProps
|
|
59
|
+
} = props;
|
|
60
|
+
const { id, states, methods } = useSwitch();
|
|
61
|
+
const { toggleSwitch } = methods;
|
|
62
|
+
|
|
63
|
+
const handleClick = (event: any) => {
|
|
64
|
+
if (onClick) onClick(event);
|
|
65
|
+
if (toggleSwitch) toggleSwitch();
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
React.useEffect(() => {
|
|
69
|
+
if (defaultChecked && toggleSwitch) toggleSwitch();
|
|
70
|
+
}, [defaultChecked]);
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<TriggerWrapper
|
|
74
|
+
type="button"
|
|
75
|
+
role="switch"
|
|
76
|
+
title="switch-trigger"
|
|
77
|
+
onClick={handleClick}
|
|
78
|
+
value={String(states.checked)}
|
|
79
|
+
aria-label={`${id}-switch-trigger`}
|
|
80
|
+
aria-checked={Boolean(states.checked)}
|
|
81
|
+
data-disabled={String(disabled ?? false)}
|
|
82
|
+
data-variant={variant}
|
|
83
|
+
data-size={sizing}
|
|
84
|
+
data-raw={Boolean(raw)}
|
|
85
|
+
{...restProps}
|
|
86
|
+
>
|
|
87
|
+
<title>Switch</title>
|
|
88
|
+
{children}
|
|
89
|
+
</TriggerWrapper>
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
Switch.displayName = "Switch";
|
|
93
|
+
|
|
94
|
+
const SwitchRoot = ({ children }: IReactChildren) => {
|
|
95
|
+
return <SwitchProvider>{children}</SwitchProvider>;
|
|
96
|
+
};
|
|
97
|
+
SwitchRoot.displayName = "Switch.Root";
|
|
98
|
+
|
|
99
|
+
const SwitchThumb = (props: ISwitchThumbProperties) => {
|
|
100
|
+
const { raw, sizing } = props;
|
|
101
|
+
const { id, states } = useSwitch();
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<Thumb
|
|
105
|
+
role="presentation"
|
|
106
|
+
title="switch-thumb"
|
|
107
|
+
tabIndex={-1}
|
|
108
|
+
aria-hidden={true}
|
|
109
|
+
aria-label={`${id}-switch-thumb`}
|
|
110
|
+
data-checked={states.checked}
|
|
111
|
+
data-raw={Boolean(raw)}
|
|
112
|
+
data-size={sizing ?? ComponentSizeEnum.Medium}
|
|
113
|
+
{...props}
|
|
114
|
+
/>
|
|
115
|
+
);
|
|
116
|
+
};
|
|
117
|
+
SwitchThumb.displayName = "Switch.Thumb";
|
|
118
|
+
|
|
119
|
+
Switch.Root = SwitchRoot;
|
|
120
|
+
Switch.Thumb = SwitchThumb;
|
|
121
|
+
|
|
122
|
+
export { SwitchRoot, Switch, SwitchThumb };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import styled, { css } from "styled-components";
|
|
2
|
+
|
|
3
|
+
const SwitchDefaultStyles = css`
|
|
4
|
+
all: unset;
|
|
5
|
+
|
|
6
|
+
border: var(--measurement-small-10) solid transparent;
|
|
7
|
+
border-radius: var(--measurement-large-90);
|
|
8
|
+
transition: all 0.2s ease-in-out 0s;
|
|
9
|
+
|
|
10
|
+
cursor: pointer;
|
|
11
|
+
|
|
12
|
+
&:disabled {
|
|
13
|
+
cursor: not-allowed;
|
|
14
|
+
opacity: 0.6;
|
|
15
|
+
}
|
|
16
|
+
`;
|
|
17
|
+
const SwitchVariantsStyles = css`
|
|
18
|
+
&[data-variant="primary"] {
|
|
19
|
+
&[aria-checked="true"] {
|
|
20
|
+
background-color: var(--color-green);
|
|
21
|
+
border-color: var(--font-color-alpha-10);
|
|
22
|
+
}
|
|
23
|
+
&[aria-checked="false"] {
|
|
24
|
+
background-color: var(--font-color-alpha-10);
|
|
25
|
+
border-color: var(--font-color-alpha-10);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
&[data-variant="secondary"] {
|
|
29
|
+
&[aria-checked="true"] {
|
|
30
|
+
background-color: var(--font-color-alpha-10);
|
|
31
|
+
border-color: var(--font-color-alpha-10);
|
|
32
|
+
}
|
|
33
|
+
&[aria-checked="false"] {
|
|
34
|
+
background-color: var(--body-color-alpha-10);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
&[data-variant="ghost"] {
|
|
39
|
+
&[aria-checked="true"] {
|
|
40
|
+
border-color: var(--font-color-alpha-10);
|
|
41
|
+
background-color: var(--body-color-alpha-10);
|
|
42
|
+
}
|
|
43
|
+
&[aria-checked="false"] {
|
|
44
|
+
border-color: var(--font-color-alpha-10);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
`;
|
|
48
|
+
const SwitchSizeStyles = css`
|
|
49
|
+
&[data-size="small"] {
|
|
50
|
+
width: calc(var(--measurement-medium-60) * 1.33);
|
|
51
|
+
height: var(--measurement-medium-50);
|
|
52
|
+
|
|
53
|
+
span {
|
|
54
|
+
width: var(--measurement-medium-40);
|
|
55
|
+
height: var(--measurement-medium-40);
|
|
56
|
+
&[data-checked="true"] {
|
|
57
|
+
transform: translateX(var(--measurement-medium-40));
|
|
58
|
+
}
|
|
59
|
+
&[data-checked="false"] {
|
|
60
|
+
transform: translateX(var(--measurement-small-60));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
&[data-size="medium"] {
|
|
66
|
+
width: calc(var(--measurement-medium-60) * 1.66);
|
|
67
|
+
height: var(--measurement-medium-60);
|
|
68
|
+
|
|
69
|
+
span {
|
|
70
|
+
width: var(--measurement-medium-50);
|
|
71
|
+
height: var(--measurement-medium-50);
|
|
72
|
+
&[data-checked="true"] {
|
|
73
|
+
transform: translateX(var(--measurement-medium-50));
|
|
74
|
+
}
|
|
75
|
+
&[data-checked="false"] {
|
|
76
|
+
transform: translateX(var(--measurement-small-60));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
&[data-size="large"] {
|
|
82
|
+
width: calc(var(--measurement-medium-60) * 2.33);
|
|
83
|
+
height: var(--measurement-medium-70);
|
|
84
|
+
|
|
85
|
+
span {
|
|
86
|
+
width: var(--measurement-medium-60);
|
|
87
|
+
height: var(--measurement-medium-60);
|
|
88
|
+
&[data-checked="true"] {
|
|
89
|
+
transform: translateX(calc(var(--measurement-medium-60) * 1.133));
|
|
90
|
+
}
|
|
91
|
+
&[data-checked="false"] {
|
|
92
|
+
transform: translateX(var(--measurement-small-80));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
`;
|
|
97
|
+
|
|
98
|
+
export const TriggerWrapper = styled.button<any>`
|
|
99
|
+
&[data-raw="false"] {
|
|
100
|
+
${SwitchDefaultStyles}
|
|
101
|
+
${SwitchVariantsStyles}
|
|
102
|
+
${SwitchSizeStyles}
|
|
103
|
+
}
|
|
104
|
+
`;
|
|
105
|
+
export const Thumb = styled.span<any>`
|
|
106
|
+
&[data-raw="false"] {
|
|
107
|
+
all: unset;
|
|
108
|
+
display: block;
|
|
109
|
+
|
|
110
|
+
background: var(--font-color-alpha-60);
|
|
111
|
+
border-radius: 100%;
|
|
112
|
+
transition: all 0.1s ease-in-out 0.2s;
|
|
113
|
+
|
|
114
|
+
&[data-checked="true"] {
|
|
115
|
+
background: var(--font-color);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
`;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { ScrollArea, IScrollAreaProperties } from "../scrollarea";
|
|
5
|
+
import {
|
|
6
|
+
TableLayer,
|
|
7
|
+
TableWrapper,
|
|
8
|
+
RowWrapper,
|
|
9
|
+
HeadCellWrapper,
|
|
10
|
+
CellWrapper,
|
|
11
|
+
} from "./styles";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Table component that provides a scrollable table with styled elements.
|
|
15
|
+
*
|
|
16
|
+
* @param {IScrollAreaProperties & React.ComponentProps<"table">} props - The props for the Table component
|
|
17
|
+
* @returns {React.ReactElement} The Table component
|
|
18
|
+
*/
|
|
19
|
+
const Table = ({
|
|
20
|
+
children,
|
|
21
|
+
...restProps
|
|
22
|
+
}: IScrollAreaProperties & React.ComponentProps<"table">) => {
|
|
23
|
+
return (
|
|
24
|
+
<ScrollArea as={TableLayer} role="presentation" tabIndex={-1}>
|
|
25
|
+
<TableWrapper {...restProps} cellSpacing="0" cellPadding="0">
|
|
26
|
+
{children}
|
|
27
|
+
</TableWrapper>
|
|
28
|
+
</ScrollArea>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
Table.displayName = "Table";
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Table head component
|
|
35
|
+
*
|
|
36
|
+
* @param {React.ComponentProps<"thead">} props - The props for the TableHead component
|
|
37
|
+
* @returns {React.ReactElement} The TableHead component
|
|
38
|
+
*/
|
|
39
|
+
const TableHead = ({
|
|
40
|
+
children,
|
|
41
|
+
...restProps
|
|
42
|
+
}: React.ComponentProps<"thead">) => {
|
|
43
|
+
return <thead {...restProps}>{children}</thead>;
|
|
44
|
+
};
|
|
45
|
+
TableHead.displayName = "Table.Head";
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Table body component
|
|
49
|
+
*
|
|
50
|
+
* @param {React.ComponentProps<"tbody">} props - The props for the TableBody component
|
|
51
|
+
* @returns {React.ReactElement} The TableBody component
|
|
52
|
+
*/
|
|
53
|
+
const TableBody = ({
|
|
54
|
+
children,
|
|
55
|
+
...restProps
|
|
56
|
+
}: React.ComponentProps<"tbody">) => {
|
|
57
|
+
return <tbody {...restProps}>{children}</tbody>;
|
|
58
|
+
};
|
|
59
|
+
TableBody.displayName = "Table.Body";
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Table head cell component
|
|
63
|
+
*
|
|
64
|
+
* @param {React.ComponentProps<"th">} props - The props for the TableHeadCell component
|
|
65
|
+
* @returns {React.ReactElement} The TableHeadCell component
|
|
66
|
+
*/
|
|
67
|
+
const TableHeadCell = ({
|
|
68
|
+
children,
|
|
69
|
+
...restProps
|
|
70
|
+
}: React.ComponentProps<"th">) => {
|
|
71
|
+
return (
|
|
72
|
+
<HeadCellWrapper colSpan={1} {...restProps}>
|
|
73
|
+
<div className="flex align-center g-medium-30">{children}</div>
|
|
74
|
+
</HeadCellWrapper>
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
TableHeadCell.displayName = "Table.HeadCell";
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Table row component
|
|
81
|
+
*
|
|
82
|
+
* @param {React.ComponentProps<"tr">} props - The props for the TableRow component
|
|
83
|
+
* @returns {React.ReactElement} The TableRow component
|
|
84
|
+
*/
|
|
85
|
+
const TableRow = ({ children, ...restProps }: React.ComponentProps<"tr">) => {
|
|
86
|
+
return (
|
|
87
|
+
<RowWrapper className="p-medium-30" {...restProps}>
|
|
88
|
+
{children}
|
|
89
|
+
</RowWrapper>
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
TableRow.displayName = "Table.Row";
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Table cell component
|
|
96
|
+
*
|
|
97
|
+
* @param {React.ComponentProps<"td">} props - The props for the TableCell component
|
|
98
|
+
* @returns {React.ReactElement} The TableCell component
|
|
99
|
+
*/
|
|
100
|
+
const TableCell = ({ children, ...restProps }: React.ComponentProps<"td">) => {
|
|
101
|
+
return (
|
|
102
|
+
<CellWrapper {...restProps}>
|
|
103
|
+
<div className="flex align-center g-medium-30">{children}</div>
|
|
104
|
+
</CellWrapper>
|
|
105
|
+
);
|
|
106
|
+
};
|
|
107
|
+
TableCell.displayName = "Table.Cell";
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Table footer component
|
|
111
|
+
*
|
|
112
|
+
* @param {React.ComponentProps<"tfoot">} props - The props for the TableFooter component
|
|
113
|
+
* @returns {React.ReactElement} The TableFooter component
|
|
114
|
+
*/
|
|
115
|
+
const TableFooter = ({
|
|
116
|
+
children,
|
|
117
|
+
...restProps
|
|
118
|
+
}: React.ComponentProps<"tfoot">) => {
|
|
119
|
+
return <tfoot {...restProps}>{children}</tfoot>;
|
|
120
|
+
};
|
|
121
|
+
TableFooter.displayName = "Table.Footer";
|
|
122
|
+
|
|
123
|
+
Table.Head = TableHead;
|
|
124
|
+
Table.Body = TableBody;
|
|
125
|
+
Table.HeadCell = TableHeadCell;
|
|
126
|
+
Table.Row = TableRow;
|
|
127
|
+
Table.Cell = TableCell;
|
|
128
|
+
Table.Footer = TableFooter;
|
|
129
|
+
|
|
130
|
+
export {
|
|
131
|
+
Table,
|
|
132
|
+
TableHead,
|
|
133
|
+
TableHeadCell,
|
|
134
|
+
TableBody,
|
|
135
|
+
TableRow,
|
|
136
|
+
TableCell,
|
|
137
|
+
TableFooter,
|
|
138
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import styled, { css } from "styled-components";
|
|
2
|
+
|
|
3
|
+
const CellStyles = css`
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
border: none;
|
|
6
|
+
line-height: 1;
|
|
7
|
+
font-weight: 500;
|
|
8
|
+
padding: var(--measurement-medium-40) var(--measurement-medium-30);
|
|
9
|
+
letter-spacing: calc(
|
|
10
|
+
var(--fontsize-small-10) - ((var(--fontsize-small-10) * 1.066))
|
|
11
|
+
);
|
|
12
|
+
`;
|
|
13
|
+
|
|
14
|
+
export const TableLayer = styled.div`
|
|
15
|
+
border-radius: var(--measurement-medium-30);
|
|
16
|
+
border: var(--measurement-small-10) solid var(--font-color-alpha-10);
|
|
17
|
+
`;
|
|
18
|
+
export const TableWrapper = styled.table<any>`
|
|
19
|
+
border-collapse: collapse;
|
|
20
|
+
|
|
21
|
+
tbody {
|
|
22
|
+
tr {
|
|
23
|
+
&:last-of-type {
|
|
24
|
+
border-bottom: none;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
export const RowWrapper = styled.tr<any>`
|
|
30
|
+
border-bottom: var(--measurement-small-10) solid var(--font-color-alpha-10);
|
|
31
|
+
|
|
32
|
+
transition: background-color linear 0.1s;
|
|
33
|
+
|
|
34
|
+
&:hover {
|
|
35
|
+
background-color: var(--font-color-alpha-10);
|
|
36
|
+
}
|
|
37
|
+
`;
|
|
38
|
+
export const HeadCellWrapper = styled.th<any>`
|
|
39
|
+
font-size: var(--fontsize-medium-10);
|
|
40
|
+
${CellStyles}
|
|
41
|
+
|
|
42
|
+
div {
|
|
43
|
+
color: var(--font-color-alpha-60);
|
|
44
|
+
}
|
|
45
|
+
`;
|
|
46
|
+
export const CellWrapper = styled.td<any>`
|
|
47
|
+
${CellStyles}
|
|
48
|
+
`;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
|
|
4
|
+
import { Tabs } from "..";
|
|
5
|
+
import { ComponentVariantEnum, ComponentSizeEnum } from "../../../../types";
|
|
6
|
+
|
|
7
|
+
// Duplicated doc: The JSDoc content isn't rendering on Storybook.
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Tabs are components for a set of tab panels that allows the user to switch between them.
|
|
11
|
+
*
|
|
12
|
+
* **Best practices:**
|
|
13
|
+
*
|
|
14
|
+
* - Ensure that the tabs can be navigated and activated using the keyboard.
|
|
15
|
+
* - Ensure that the focus is managed correctly when switching between tabs.
|
|
16
|
+
* - Ensure that the active tab is visibly indicated and that its content is visible and focusable.
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
const meta = {
|
|
20
|
+
title: "Components/Tabs",
|
|
21
|
+
component: Tabs,
|
|
22
|
+
tags: ["autodocs"],
|
|
23
|
+
decorators: [
|
|
24
|
+
(Story) => (
|
|
25
|
+
<div className="m-medium-30">
|
|
26
|
+
<Story />
|
|
27
|
+
</div>
|
|
28
|
+
),
|
|
29
|
+
],
|
|
30
|
+
} satisfies Meta<typeof Tabs>;
|
|
31
|
+
export default meta;
|
|
32
|
+
|
|
33
|
+
type Story = StoryObj<typeof meta>;
|
|
34
|
+
export const Default: Story = {
|
|
35
|
+
args: {
|
|
36
|
+
raw: false,
|
|
37
|
+
defaultOpen: "",
|
|
38
|
+
value: "",
|
|
39
|
+
},
|
|
40
|
+
argTypes: {
|
|
41
|
+
variant: {
|
|
42
|
+
options: [
|
|
43
|
+
ComponentVariantEnum.Primary,
|
|
44
|
+
ComponentVariantEnum.Secondary,
|
|
45
|
+
ComponentVariantEnum.Tertiary,
|
|
46
|
+
ComponentVariantEnum.Mono,
|
|
47
|
+
ComponentVariantEnum.Border,
|
|
48
|
+
ComponentVariantEnum.Ghost,
|
|
49
|
+
],
|
|
50
|
+
control: { type: "radio" },
|
|
51
|
+
},
|
|
52
|
+
sizing: {
|
|
53
|
+
options: [
|
|
54
|
+
ComponentSizeEnum.Small,
|
|
55
|
+
ComponentSizeEnum.Medium,
|
|
56
|
+
ComponentSizeEnum.Large,
|
|
57
|
+
],
|
|
58
|
+
control: { type: "radio" },
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
render: ({ ...args }) => (
|
|
62
|
+
<Tabs.Root>
|
|
63
|
+
<Tabs>
|
|
64
|
+
<div className="flex g-medium-30">
|
|
65
|
+
<Tabs.Trigger value="🐻❄️">🐻❄️</Tabs.Trigger>
|
|
66
|
+
<Tabs.Trigger value="🐻">🐻</Tabs.Trigger>
|
|
67
|
+
</div>
|
|
68
|
+
</Tabs>
|
|
69
|
+
<Tabs.Content value="🐻❄️">🐻❄️</Tabs.Content>
|
|
70
|
+
<Tabs.Content value="🐻">🐻</Tabs.Content>
|
|
71
|
+
</Tabs.Root>
|
|
72
|
+
),
|
|
73
|
+
};
|
|
74
|
+
export const DefaultOpen: Story = {
|
|
75
|
+
render: ({ ...args }) => (
|
|
76
|
+
<Tabs.Root>
|
|
77
|
+
<Tabs defaultOpen="🐻">
|
|
78
|
+
<div className="flex g-medium-30">
|
|
79
|
+
<Tabs.Trigger value="🐻❄️">🐻❄️</Tabs.Trigger>
|
|
80
|
+
<Tabs.Trigger value="🐻">🐻</Tabs.Trigger>
|
|
81
|
+
</div>
|
|
82
|
+
</Tabs>
|
|
83
|
+
<Tabs.Content value="🐻❄️">🐻❄️</Tabs.Content>
|
|
84
|
+
<Tabs.Content value="🐻">🐻</Tabs.Content>
|
|
85
|
+
</Tabs.Root>
|
|
86
|
+
),
|
|
87
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React, { createContext, useContext, useState } from "react";
|
|
2
|
+
import { IReactChildren, IComponentAPI } from "../../../../../types";
|
|
3
|
+
|
|
4
|
+
const defaultComponentAPI = {
|
|
5
|
+
id: "",
|
|
6
|
+
states: {},
|
|
7
|
+
methods: {},
|
|
8
|
+
};
|
|
9
|
+
const TabsContext = createContext<IComponentAPI>(defaultComponentAPI);
|
|
10
|
+
export const useTabs = () => useContext(TabsContext);
|
|
11
|
+
|
|
12
|
+
export const TabsProvider = ({ children }: IReactChildren): JSX.Element => {
|
|
13
|
+
const context = useTabsProvider();
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<TabsContext.Provider value={context}>{children}</TabsContext.Provider>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function useTabsProvider(): IComponentAPI {
|
|
21
|
+
const [value, setValue] = useState<string | null>(null);
|
|
22
|
+
const tabsId = React.useId();
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
id: tabsId,
|
|
26
|
+
states: {
|
|
27
|
+
value: value,
|
|
28
|
+
},
|
|
29
|
+
methods: {
|
|
30
|
+
applyValue: (value: string): string | void => setValue(value),
|
|
31
|
+
getTabsId: ({ value, type }: Record<string, string>): string =>
|
|
32
|
+
`${tabsId}-${type}-${value}`,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|