@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.
Files changed (104) hide show
  1. package/CHANGELOG.md +233 -0
  2. package/LICENSE +21 -0
  3. package/README.md +0 -0
  4. package/babel.config.js +12 -0
  5. package/dist/index.d.mts +1299 -0
  6. package/dist/index.d.ts +1299 -0
  7. package/dist/index.js +3701 -0
  8. package/dist/index.mjs +3586 -0
  9. package/package.json +44 -0
  10. package/src/__tests__/Accordion.test.tsx +106 -0
  11. package/src/__tests__/Avatar.test.tsx +89 -0
  12. package/src/__tests__/Badge.test.tsx +58 -0
  13. package/src/__tests__/Button.test.tsx +88 -0
  14. package/src/__tests__/Checkbox.test.tsx +106 -0
  15. package/src/__tests__/Collapsible.test.tsx +79 -0
  16. package/src/__tests__/Dialog.test.tsx +109 -0
  17. package/src/__tests__/Dropdown.test.tsx +159 -0
  18. package/src/__tests__/Field.test.tsx +100 -0
  19. package/src/__tests__/OTPField.test.tsx +199 -0
  20. package/src/__tests__/Overlay.test.tsx +70 -0
  21. package/src/__tests__/Page.test.tsx +98 -0
  22. package/src/__tests__/Portal.test.tsx +28 -0
  23. package/src/__tests__/Sheet.test.tsx +125 -0
  24. package/src/__tests__/Switch.test.tsx +90 -0
  25. package/src/__tests__/Tabs.test.tsx +129 -0
  26. package/src/__tests__/Toggle.test.tsx +67 -0
  27. package/src/__tests__/Toolbar.test.tsx +147 -0
  28. package/src/__tests__/Tooltip.test.tsx +88 -0
  29. package/src/accordion/Accordion.stories.tsx +89 -0
  30. package/src/accordion/hooks/index.tsx +39 -0
  31. package/src/accordion/index.tsx +170 -0
  32. package/src/avatar/Avatar.stories.tsx +62 -0
  33. package/src/avatar/index.tsx +90 -0
  34. package/src/avatar/styles/index.ts +79 -0
  35. package/src/badge/Badge.stories.tsx +60 -0
  36. package/src/badge/index.tsx +58 -0
  37. package/src/badge/styles/index.ts +109 -0
  38. package/src/button/Button.stories.tsx +47 -0
  39. package/src/button/index.tsx +79 -0
  40. package/src/button/styles/index.ts +180 -0
  41. package/src/checkbox/Checkbox.stories.tsx +100 -0
  42. package/src/checkbox/hooks/index.tsx +40 -0
  43. package/src/checkbox/index.tsx +147 -0
  44. package/src/checkbox/styles/index.ts +139 -0
  45. package/src/collapsible/Collapsible.stories.tsx +95 -0
  46. package/src/collapsible/hooks/index.tsx +50 -0
  47. package/src/collapsible/index.tsx +137 -0
  48. package/src/dialog/Dialog.stories.tsx +73 -0
  49. package/src/dialog/hooks/index.tsx +35 -0
  50. package/src/dialog/index.tsx +221 -0
  51. package/src/dialog/styles/index.ts +72 -0
  52. package/src/divider/index.ts +10 -0
  53. package/src/dropdown/Dropdown.stories.tsx +100 -0
  54. package/src/dropdown/hooks/index.tsx +64 -0
  55. package/src/dropdown/index.tsx +316 -0
  56. package/src/dropdown/styles/index.ts +90 -0
  57. package/src/field/Field.stories.tsx +146 -0
  58. package/src/field/hooks/index.tsx +28 -0
  59. package/src/field/index.tsx +183 -0
  60. package/src/field/styles/index.ts +166 -0
  61. package/src/index.ts +33 -0
  62. package/src/otp-field/OTPField.stories.tsx +50 -0
  63. package/src/otp-field/hooks/index.tsx +13 -0
  64. package/src/otp-field/index.tsx +234 -0
  65. package/src/otp-field/styles/index.ts +33 -0
  66. package/src/otp-field/types/index.ts +23 -0
  67. package/src/overlay/Overlay.stories.tsx +59 -0
  68. package/src/overlay/index.tsx +58 -0
  69. package/src/overlay/styles/index.ts +26 -0
  70. package/src/page/Page.stories.tsx +85 -0
  71. package/src/page/index.tsx +265 -0
  72. package/src/page/styles/index.ts +59 -0
  73. package/src/portal/Portal.stories.tsx +27 -0
  74. package/src/portal/index.tsx +36 -0
  75. package/src/scrollarea/Scrollarea.stories.tsx +99 -0
  76. package/src/scrollarea/index.tsx +27 -0
  77. package/src/scrollarea/styles/index.ts +71 -0
  78. package/src/sheet/Sheet.stories.tsx +86 -0
  79. package/src/sheet/hooks/index.tsx +47 -0
  80. package/src/sheet/index.tsx +190 -0
  81. package/src/sheet/styles/index.ts +69 -0
  82. package/src/switch/Switch.stories.tsx +96 -0
  83. package/src/switch/hooks/index.tsx +33 -0
  84. package/src/switch/index.tsx +122 -0
  85. package/src/switch/styles/index.ts +118 -0
  86. package/src/table/index.tsx +138 -0
  87. package/src/table/styles/index.ts +48 -0
  88. package/src/tabs/Tabs.stories.tsx +87 -0
  89. package/src/tabs/hooks/index.tsx +35 -0
  90. package/src/tabs/index.tsx +161 -0
  91. package/src/tabs/styles/index.ts +9 -0
  92. package/src/toggle/Toggle.stories.tsx +118 -0
  93. package/src/toggle/index.tsx +55 -0
  94. package/src/toggle/styles/index.ts +0 -0
  95. package/src/toolbar/Toolbar.stories.tsx +89 -0
  96. package/src/toolbar/hooks/index.tsx +35 -0
  97. package/src/toolbar/index.tsx +243 -0
  98. package/src/toolbar/styles/index.ts +129 -0
  99. package/src/tooltip/Tooltip.stories.tsx +60 -0
  100. package/src/tooltip/index.tsx +177 -0
  101. package/src/tooltip/styles/index.ts +38 -0
  102. package/src/utils/index.ts +2 -0
  103. package/tsconfig.json +18 -0
  104. 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
+ }