@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,161 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React, { Children } from "react";
|
|
4
|
+
import { TabsProvider, useTabs } from "./hooks";
|
|
5
|
+
import { Button, IButtonProperties } from "../button";
|
|
6
|
+
import { TabWrapper } from "./styles";
|
|
7
|
+
import { IReactChildren, ComponentVariantEnum } from "../../../../types";
|
|
8
|
+
|
|
9
|
+
export interface ITabsProperties extends React.ComponentProps<"div"> {
|
|
10
|
+
value?: string;
|
|
11
|
+
defaultOpen?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ITabsComposition {
|
|
15
|
+
Root: typeof TabsRoot;
|
|
16
|
+
Trigger: typeof TabsTrigger;
|
|
17
|
+
Content: typeof TabsContent;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Tabs are components for a set of tab panels that allows the user to switch between them.
|
|
22
|
+
*
|
|
23
|
+
* **Best practices:**
|
|
24
|
+
*
|
|
25
|
+
* - Ensure that the tabs can be navigated and activated using the keyboard.
|
|
26
|
+
* - Ensure that the focus is managed correctly when switching between tabs.
|
|
27
|
+
* - Ensure that the active tab is visibly indicated and that its content is visible and focusable.
|
|
28
|
+
*
|
|
29
|
+
* @param {ITabsProperties} props - The props for the Tabs component.
|
|
30
|
+
* @param {string} props.defaultOpen - The value of the tab panel that should be open by default.
|
|
31
|
+
* @param {ReactNode} props.children - The content to be rendered inside the tabs component.
|
|
32
|
+
* @returns {ReactElement} The Tabs component.
|
|
33
|
+
*/
|
|
34
|
+
const Tabs = (props: ITabsProperties) => {
|
|
35
|
+
const { defaultOpen, children, ...restProps } = props;
|
|
36
|
+
const { methods } = useTabs();
|
|
37
|
+
const { applyValue } = methods;
|
|
38
|
+
|
|
39
|
+
const childArray = Children.toArray(children);
|
|
40
|
+
const firstChild = childArray[0];
|
|
41
|
+
|
|
42
|
+
React.useEffect(() => {
|
|
43
|
+
if (React.isValidElement<{ value: string }>(firstChild)) {
|
|
44
|
+
if (childArray.length > 0 && applyValue)
|
|
45
|
+
applyValue(firstChild.props.value);
|
|
46
|
+
}
|
|
47
|
+
}, []);
|
|
48
|
+
|
|
49
|
+
React.useEffect(() => {
|
|
50
|
+
if (defaultOpen && applyValue) applyValue(defaultOpen);
|
|
51
|
+
}, []);
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<TabWrapper role="tablist" {...restProps}>
|
|
55
|
+
{children}
|
|
56
|
+
</TabWrapper>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
Tabs.displayName = "Tabs";
|
|
60
|
+
|
|
61
|
+
const TabsRoot = ({ children }: IReactChildren) => {
|
|
62
|
+
return <TabsProvider>{children}</TabsProvider>;
|
|
63
|
+
};
|
|
64
|
+
TabsRoot.displayName = "Tabs.Root";
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Tabs.Trigger is used to triggers the expansion and collapse of the associated Tabs.Content component.
|
|
68
|
+
*
|
|
69
|
+
* **Best practices:**
|
|
70
|
+
*
|
|
71
|
+
* - Use a clear and descriptive title for the trigger that accurately conveys the content of the associated tab panel.
|
|
72
|
+
* - Ensure that the trigger can be operated using only the keyboard.
|
|
73
|
+
* - Ensure that the focus is properly managed when the trigger is activated.
|
|
74
|
+
*
|
|
75
|
+
* @param {IButtonProperties} props - The props for the Tabs.Trigger component.
|
|
76
|
+
* @param {string} props.value - The value used to bind the Tabs.Trigger and Tabs.Content components.
|
|
77
|
+
* @param {ReactNode} props.children - The content to be rendered inside the tabs trigger.
|
|
78
|
+
* @returns {ReactElement} The Tabs.Trigger component.
|
|
79
|
+
*/
|
|
80
|
+
const TabsTrigger = (props: IButtonProperties) => {
|
|
81
|
+
const { value, onClick, children, ...restProps } = props;
|
|
82
|
+
const { states, methods } = useTabs();
|
|
83
|
+
const { applyValue, getTabsId } = methods;
|
|
84
|
+
|
|
85
|
+
const hasSameValueAsContext = value === states.value;
|
|
86
|
+
const IdHandler = {
|
|
87
|
+
trigger: getTabsId && getTabsId({ value, type: "trigger" }),
|
|
88
|
+
content: getTabsId && getTabsId({ value, type: "content" }),
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
92
|
+
if (applyValue) applyValue(value);
|
|
93
|
+
if (onClick) onClick(event);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<Button
|
|
98
|
+
type="button"
|
|
99
|
+
role="tab"
|
|
100
|
+
title={`${value}-tab`}
|
|
101
|
+
id={String(IdHandler.trigger)}
|
|
102
|
+
value={value}
|
|
103
|
+
onClick={handleClick}
|
|
104
|
+
aria-selected={hasSameValueAsContext}
|
|
105
|
+
data-controls={IdHandler.content}
|
|
106
|
+
data-state={hasSameValueAsContext ? "active" : "inactive"}
|
|
107
|
+
variant={props.variant ?? ComponentVariantEnum.Ghost}
|
|
108
|
+
{...restProps}
|
|
109
|
+
>
|
|
110
|
+
{children}
|
|
111
|
+
</Button>
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
TabsTrigger.displayName = "Tabs.Trigger";
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Tabs.Content is used to contains the content of the associated Tabs.Trigger component.
|
|
118
|
+
*
|
|
119
|
+
* **Best practices:**
|
|
120
|
+
*
|
|
121
|
+
* - Ensure that the content is hidden when the associated tab panel is collapsed.
|
|
122
|
+
* - Ensure that the content is properly focused when the associated tab panel is expanded.
|
|
123
|
+
*
|
|
124
|
+
* @param {ITabsProperties} props - The props for the Tabs.Content component.
|
|
125
|
+
* @param {string} props.value - The value used to bind the Tabs.Content and Tabs.Trigger components.
|
|
126
|
+
* @param {ReactNode} props.children - The content to be rendered inside the tab.
|
|
127
|
+
* @returns {ReactElement} The Tabs.Content component.
|
|
128
|
+
*/
|
|
129
|
+
const TabsContent = (props: ITabsProperties) => {
|
|
130
|
+
const { value, children, ...restProps } = props;
|
|
131
|
+
const { states, methods } = useTabs();
|
|
132
|
+
const { getTabsId } = methods;
|
|
133
|
+
|
|
134
|
+
const hasSameValueAsContext = value === states.value;
|
|
135
|
+
const IdHandler = {
|
|
136
|
+
trigger: getTabsId && getTabsId({ value, type: "trigger" }),
|
|
137
|
+
content: getTabsId && getTabsId({ value, type: "content" }),
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<div
|
|
142
|
+
tabIndex={0}
|
|
143
|
+
role="tabpanel"
|
|
144
|
+
title={`${value}-tabpanel`}
|
|
145
|
+
id={String(IdHandler.content)}
|
|
146
|
+
data-value={value}
|
|
147
|
+
data-state={hasSameValueAsContext ? "active" : "inactive"}
|
|
148
|
+
aria-labelledby={IdHandler.trigger ?? restProps["aria-labelledby"]}
|
|
149
|
+
{...restProps}
|
|
150
|
+
>
|
|
151
|
+
{hasSameValueAsContext && children}
|
|
152
|
+
</div>
|
|
153
|
+
);
|
|
154
|
+
};
|
|
155
|
+
TabsContent.displayName = "Tabs.Content";
|
|
156
|
+
|
|
157
|
+
Tabs.Root = TabsRoot;
|
|
158
|
+
Tabs.Trigger = TabsTrigger;
|
|
159
|
+
Tabs.Content = TabsContent;
|
|
160
|
+
|
|
161
|
+
export { TabsRoot, Tabs, TabsTrigger, TabsContent };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
|
|
4
|
+
import { Toggle } from "..";
|
|
5
|
+
import { ComponentVariantEnum } from "../../../../types";
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
title: "Components/Toggle",
|
|
9
|
+
component: Toggle,
|
|
10
|
+
tags: ["autodocs"],
|
|
11
|
+
decorators: [
|
|
12
|
+
(Story) => (
|
|
13
|
+
<div className="m-medium-30">
|
|
14
|
+
<Story />
|
|
15
|
+
</div>
|
|
16
|
+
),
|
|
17
|
+
],
|
|
18
|
+
} satisfies Meta<typeof Toggle>;
|
|
19
|
+
export default meta;
|
|
20
|
+
|
|
21
|
+
type Story = StoryObj<typeof meta>;
|
|
22
|
+
export const Default: Story = {
|
|
23
|
+
render: ({ ...args }) => {
|
|
24
|
+
const [checked, setChecked] = React.useState(false);
|
|
25
|
+
const variant = checked
|
|
26
|
+
? ComponentVariantEnum.Secondary
|
|
27
|
+
: ComponentVariantEnum.Border;
|
|
28
|
+
|
|
29
|
+
return <Toggle variant={variant} onClick={() => setChecked(!checked)} />;
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
export const DefaultChecked: Story = {
|
|
33
|
+
render: ({ ...args }) => {
|
|
34
|
+
const [checked, setChecked] = React.useState(true);
|
|
35
|
+
const variant = checked
|
|
36
|
+
? ComponentVariantEnum.Secondary
|
|
37
|
+
: ComponentVariantEnum.Border;
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<Toggle
|
|
41
|
+
defaultChecked
|
|
42
|
+
variant={variant}
|
|
43
|
+
onClick={() => setChecked(!checked)}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
export const Group: Story = {
|
|
49
|
+
render: ({ ...args }) => {
|
|
50
|
+
const [checkedItems, setCheckedItems] = React.useState<object>({
|
|
51
|
+
primary: false,
|
|
52
|
+
secondary: true,
|
|
53
|
+
tertiary: false,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const getVariant = (label) => {
|
|
57
|
+
return Boolean(checkedItems[label])
|
|
58
|
+
? ComponentVariantEnum.Secondary
|
|
59
|
+
: ComponentVariantEnum.Border;
|
|
60
|
+
};
|
|
61
|
+
const handleCheckedItem = (event: any) => {
|
|
62
|
+
checkedItems[event.target.name] = !checkedItems[event.target.name];
|
|
63
|
+
setCheckedItems({ ...checkedItems });
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<div className="flex justify-start align-center g-medium-30">
|
|
68
|
+
{[
|
|
69
|
+
Object.keys(checkedItems).map((item) => (
|
|
70
|
+
<Toggle
|
|
71
|
+
key={item}
|
|
72
|
+
name={item}
|
|
73
|
+
variant={getVariant(item)}
|
|
74
|
+
onClick={handleCheckedItem}
|
|
75
|
+
/>
|
|
76
|
+
)),
|
|
77
|
+
]}
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
export const Sizes: Story = {
|
|
83
|
+
render: ({ ...args }) => {
|
|
84
|
+
const [checkedItems, setCheckedItems] = React.useState<object>({
|
|
85
|
+
large: false,
|
|
86
|
+
medium: false,
|
|
87
|
+
small: false,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const getVariant = (label) => {
|
|
91
|
+
return Boolean(checkedItems[label])
|
|
92
|
+
? ComponentVariantEnum.Secondary
|
|
93
|
+
: ComponentVariantEnum.Border;
|
|
94
|
+
};
|
|
95
|
+
const handleCheckedItem = (event: any) => {
|
|
96
|
+
checkedItems[event.target.name] = !checkedItems[event.target.name];
|
|
97
|
+
setCheckedItems({ ...checkedItems });
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<div className="flex justify-start align-center g-medium-30">
|
|
102
|
+
{[
|
|
103
|
+
Object.keys(checkedItems).map((item) => (
|
|
104
|
+
<Toggle
|
|
105
|
+
key={item}
|
|
106
|
+
name={item}
|
|
107
|
+
variant={getVariant(item)}
|
|
108
|
+
sizing={item}
|
|
109
|
+
onClick={handleCheckedItem}
|
|
110
|
+
>
|
|
111
|
+
{item}
|
|
112
|
+
</Toggle>
|
|
113
|
+
)),
|
|
114
|
+
]}
|
|
115
|
+
</div>
|
|
116
|
+
);
|
|
117
|
+
},
|
|
118
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { Button, IButtonProperties } from "../button";
|
|
5
|
+
|
|
6
|
+
export interface IToggleProperties extends IButtonProperties {
|
|
7
|
+
defaultChecked?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Toggle are button that can be switched on or off.
|
|
12
|
+
*
|
|
13
|
+
* **Best practices:**
|
|
14
|
+
*
|
|
15
|
+
* - Define the checked state of toggles with different variants, labels.
|
|
16
|
+
* - The interaction must have predictable behavior.
|
|
17
|
+
*
|
|
18
|
+
* @param {IToggleProperties} props - The props for the Toggle component.
|
|
19
|
+
* @param {boolean} props.defaultChecked - The initial checked state of the toggle. Defaults to false.
|
|
20
|
+
* @param {ReactNode} props.children - The content to be rendered inside the toggle button.
|
|
21
|
+
* @returns {ReactElement} The Toggle component.
|
|
22
|
+
*/
|
|
23
|
+
export const Toggle = (props: IToggleProperties) => {
|
|
24
|
+
const { defaultChecked, onClick, disabled, children, ...restProps } = props;
|
|
25
|
+
const [checked, setChecked] = React.useState<boolean>(
|
|
26
|
+
defaultChecked ?? false
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
30
|
+
if (onClick) onClick(event);
|
|
31
|
+
if (!disabled) setChecked((prevChecked) => !prevChecked);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
React.useEffect(() => {
|
|
35
|
+
if (defaultChecked !== undefined) {
|
|
36
|
+
setChecked(Boolean(defaultChecked));
|
|
37
|
+
}
|
|
38
|
+
}, [defaultChecked]);
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<Button
|
|
42
|
+
role="switch"
|
|
43
|
+
onClick={handleClick}
|
|
44
|
+
value={String(checked)}
|
|
45
|
+
aria-checked={checked}
|
|
46
|
+
data-checked={Boolean(checked)}
|
|
47
|
+
data-disabled={Boolean(disabled)}
|
|
48
|
+
disabled={disabled}
|
|
49
|
+
{...restProps}
|
|
50
|
+
>
|
|
51
|
+
{children}
|
|
52
|
+
</Button>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
Toggle.displayName = "Toggle";
|
|
File without changes
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
|
|
4
|
+
import { Toolbar } from "..";
|
|
5
|
+
import {
|
|
6
|
+
ComponentSizeEnum,
|
|
7
|
+
ComponentSideEnum,
|
|
8
|
+
ComponentHeightEnum,
|
|
9
|
+
} from "../../../../types";
|
|
10
|
+
|
|
11
|
+
const meta = {
|
|
12
|
+
title: "Components/Toolbar",
|
|
13
|
+
component: Toolbar,
|
|
14
|
+
tags: ["autodocs"],
|
|
15
|
+
} satisfies Meta<typeof Toolbar>;
|
|
16
|
+
export default meta;
|
|
17
|
+
|
|
18
|
+
type Story = StoryObj<typeof meta>;
|
|
19
|
+
export const Default = {
|
|
20
|
+
args: {
|
|
21
|
+
raw: false,
|
|
22
|
+
defaultOpen: false,
|
|
23
|
+
showoncollapse: false,
|
|
24
|
+
showfirstchild: false,
|
|
25
|
+
shortcut: false,
|
|
26
|
+
hotkey: ":",
|
|
27
|
+
bindkey: null,
|
|
28
|
+
},
|
|
29
|
+
argTypes: {
|
|
30
|
+
side: {
|
|
31
|
+
options: [
|
|
32
|
+
ComponentSideEnum.Top,
|
|
33
|
+
ComponentSideEnum.Right,
|
|
34
|
+
ComponentSideEnum.Bottom,
|
|
35
|
+
ComponentSideEnum.Left,
|
|
36
|
+
],
|
|
37
|
+
control: { type: "radio" },
|
|
38
|
+
},
|
|
39
|
+
sizing: {
|
|
40
|
+
options: [
|
|
41
|
+
ComponentSizeEnum.Small,
|
|
42
|
+
ComponentSizeEnum.Medium,
|
|
43
|
+
ComponentSizeEnum.Large,
|
|
44
|
+
],
|
|
45
|
+
control: { type: "radio" },
|
|
46
|
+
},
|
|
47
|
+
height: {
|
|
48
|
+
options: [ComponentHeightEnum.Fullscreen, ComponentHeightEnum.Auto],
|
|
49
|
+
control: { type: "radio" },
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
render: ({ ...args }) => (
|
|
53
|
+
<Toolbar.Root>
|
|
54
|
+
<Toolbar>
|
|
55
|
+
<Toolbar.Section>
|
|
56
|
+
<Toolbar.Item>🐻❄️</Toolbar.Item>
|
|
57
|
+
</Toolbar.Section>
|
|
58
|
+
|
|
59
|
+
<Toolbar.Trigger>⇔</Toolbar.Trigger>
|
|
60
|
+
</Toolbar>
|
|
61
|
+
</Toolbar.Root>
|
|
62
|
+
),
|
|
63
|
+
};
|
|
64
|
+
export const DefaultOpen: Story = {
|
|
65
|
+
render: ({ ...args }) => (
|
|
66
|
+
<Toolbar.Root>
|
|
67
|
+
<Toolbar defaultOpen>
|
|
68
|
+
<Toolbar.Section>
|
|
69
|
+
<Toolbar.Item>🐻❄️</Toolbar.Item>
|
|
70
|
+
</Toolbar.Section>
|
|
71
|
+
|
|
72
|
+
<Toolbar.Trigger>⇔</Toolbar.Trigger>
|
|
73
|
+
</Toolbar>
|
|
74
|
+
</Toolbar.Root>
|
|
75
|
+
),
|
|
76
|
+
};
|
|
77
|
+
export const Shortcut: Story = {
|
|
78
|
+
render: ({ ...args }) => (
|
|
79
|
+
<Toolbar.Root>
|
|
80
|
+
<Toolbar shortcut hotkey="t">
|
|
81
|
+
<Toolbar.Section>
|
|
82
|
+
<Toolbar.Item>🐻❄️</Toolbar.Item>
|
|
83
|
+
</Toolbar.Section>
|
|
84
|
+
|
|
85
|
+
<Toolbar.Trigger>⇔</Toolbar.Trigger>
|
|
86
|
+
</Toolbar>
|
|
87
|
+
</Toolbar.Root>
|
|
88
|
+
),
|
|
89
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
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 ToolbarContext = createContext<IComponentAPI>(defaultComponentAPI);
|
|
10
|
+
export const useToolbar = () => useContext(ToolbarContext);
|
|
11
|
+
|
|
12
|
+
export const ToolbarProvider = ({ children }: IReactChildren): JSX.Element => {
|
|
13
|
+
const context = useToolbarProvider();
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<ToolbarContext.Provider value={context}>
|
|
17
|
+
{children}
|
|
18
|
+
</ToolbarContext.Provider>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function useToolbarProvider(): IComponentAPI {
|
|
23
|
+
const [expanded, setExpanded] = useState<boolean>(false);
|
|
24
|
+
const toolbarId = React.useId();
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
id: toolbarId,
|
|
28
|
+
states: {
|
|
29
|
+
expanded,
|
|
30
|
+
},
|
|
31
|
+
methods: {
|
|
32
|
+
toggleToolbar: (state: boolean) => setExpanded(state ?? !expanded),
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|