@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,139 @@
1
+ import styled, { css } from "styled-components";
2
+
3
+ const CheckboxDefaultStyles = css`
4
+ position: relative;
5
+ display: flex;
6
+ align-items: center;
7
+ justify-content: center;
8
+ backdrop-filter: blur(var(--measurement-small-10));
9
+ transition: all ease-in-out 0.2s;
10
+ `;
11
+ const CheckboxVariantsStyles = css`
12
+ &[data-variant="primary"] {
13
+ background-color: var(--font-color-alpha-10);
14
+ border: var(--measurement-small-10) solid transparent;
15
+
16
+ &:hover,
17
+ &:focus {
18
+ border-color: var(--font-color-alpha-10);
19
+ }
20
+
21
+ &:active,
22
+ &[data-state="checked"] {
23
+ background-color: var(--font-color);
24
+ }
25
+
26
+ &[data-state="checked"] {
27
+ svg {
28
+ stroke: var(--body-color);
29
+ }
30
+ }
31
+ }
32
+
33
+ &[data-variant="border"] {
34
+ background-color: var(--body-color);
35
+ border: var(--measurement-small-10) solid var(--font-color-alpha-10);
36
+
37
+ &:hover,
38
+ &:focus,
39
+ &:active,
40
+ &[data-state="checked"] {
41
+ background-color: var(--font-color-alpha-10);
42
+ border-color: transparent;
43
+ }
44
+
45
+ &[data-state="checked"] {
46
+ svg {
47
+ stroke: var(--font-color);
48
+ }
49
+ }
50
+ }
51
+ &[data-variant="mono"] {
52
+ background-color: var(--font-color-alpha-10);
53
+ border: var(--measurement-small-10) solid transparent;
54
+
55
+ &:hover,
56
+ &:focus,
57
+ &:active,
58
+ &[data-state="checked"] {
59
+ border-color: var(--font-color-alpha-10);
60
+ }
61
+
62
+ &[data-state="checked"] {
63
+ svg {
64
+ stroke: var(--font-color);
65
+ }
66
+ }
67
+ }
68
+ &[data-variant="ghost"] {
69
+ border: var(--measurement-small-10) solid transparent;
70
+
71
+ &:hover,
72
+ &:focus,
73
+ &:active,
74
+ &[data-state="checked"] {
75
+ border-color: var(--font-color-alpha-10);
76
+
77
+ svg {
78
+ stroke: var(--font-color);
79
+ }
80
+ }
81
+ }
82
+ `;
83
+ const CheckboxSizeStyles = css`
84
+ &[data-size="small"] {
85
+ width: var(--measurement-medium-60);
86
+ height: var(--measurement-medium-60);
87
+ border-radius: var(--measurement-small-80);
88
+ }
89
+ &[data-size="medium"] {
90
+ width: var(--measurement-medium-70);
91
+ height: var(--measurement-medium-70);
92
+ border-radius: var(--measurement-medium-10);
93
+ }
94
+ &[data-size="large"] {
95
+ width: var(--measurement-large-10);
96
+ height: var(--measurement-large-10);
97
+ border-radius: var(--measurement-medium-20);
98
+ }
99
+ `;
100
+
101
+ export const CheckboxWrapper = styled.div`
102
+ cursor: pointer;
103
+
104
+ &[data-raw="false"] {
105
+ ${CheckboxDefaultStyles}
106
+ ${CheckboxVariantsStyles}
107
+ ${CheckboxSizeStyles}
108
+ }
109
+
110
+ &[data-disabled="true"] {
111
+ cursor: not-allowed;
112
+ opacity: 0.6;
113
+
114
+ svg {
115
+ stroke-opacity: 0.6;
116
+ }
117
+ }
118
+ `;
119
+ export const NativeInput = styled.input<any>`
120
+ &[data-raw="false"] {
121
+ appearance: none;
122
+ background: none;
123
+ border: none;
124
+ cursor: pointer;
125
+ height: 100%;
126
+ position: absolute;
127
+ left: 0;
128
+ top: 0;
129
+ width: 100%;
130
+
131
+ &:disabled {
132
+ cursor: not-allowed;
133
+ }
134
+ }
135
+ `;
136
+ export const Indicator = styled.span<any>`
137
+ line-height: 0;
138
+ pointer-events: none;
139
+ `;
@@ -0,0 +1,95 @@
1
+ import React from "react";
2
+ import type { Meta, StoryObj } from "@storybook/react";
3
+
4
+ import { Collapsible } from "..";
5
+ import { ComponentVariantEnum, ComponentSizeEnum } from "../../../../types";
6
+
7
+ const meta = {
8
+ title: "Components/Collapsible",
9
+ component: Collapsible,
10
+ tags: ["autodocs"],
11
+ decorators: [
12
+ (Story) => (
13
+ <div className="m-medium-30">
14
+ <Story />
15
+ </div>
16
+ ),
17
+ ],
18
+ } satisfies Meta<typeof Collapsible>;
19
+ export default meta;
20
+
21
+ type Story = StoryObj<typeof meta>;
22
+ export const Default: Story = {
23
+ args: {
24
+ raw: false,
25
+ defaultOpen: false,
26
+ showFirstChild: false,
27
+ },
28
+ argTypes: {
29
+ variant: {
30
+ options: [
31
+ ComponentVariantEnum.Primary,
32
+ ComponentVariantEnum.Secondary,
33
+ ComponentVariantEnum.Tertiary,
34
+ ComponentVariantEnum.Mono,
35
+ ComponentVariantEnum.Border,
36
+ ComponentVariantEnum.Ghost,
37
+ ],
38
+ control: { type: "radio" },
39
+ },
40
+ sizing: {
41
+ options: [
42
+ ComponentSizeEnum.Small,
43
+ ComponentSizeEnum.Medium,
44
+ ComponentSizeEnum.Large,
45
+ ],
46
+ control: { type: "radio" },
47
+ },
48
+ },
49
+ render: ({ ...args }) => (
50
+ <Collapsible.Root>
51
+ <Collapsible>
52
+ <Collapsible.Trigger>🐻‍❄️</Collapsible.Trigger>
53
+ <Collapsible.Content>🐻🐻‍❄️🦊🐱🐶</Collapsible.Content>
54
+ </Collapsible>
55
+ </Collapsible.Root>
56
+ ),
57
+ };
58
+ export const DefaultOpen: Story = {
59
+ render: ({ ...args }) => (
60
+ <Collapsible.Root>
61
+ <Collapsible>
62
+ <Collapsible.Trigger>🐻‍❄️</Collapsible.Trigger>
63
+ <Collapsible.Content defaultOpen>🐻🐻‍❄️🦊🐱🐶</Collapsible.Content>
64
+ </Collapsible>
65
+ </Collapsible.Root>
66
+ ),
67
+ };
68
+ export const ShowFirstChild: Story = {
69
+ render: ({ ...args }) => (
70
+ <Collapsible.Root>
71
+ <Collapsible>
72
+ <Collapsible.Trigger>🐻‍❄️</Collapsible.Trigger>
73
+ <Collapsible.Content showFirstChild>
74
+ {["🐻", "🐻‍❄️", "🦊", "🐱", "🐶"].map((item) => (
75
+ <p key={item}>{item}</p>
76
+ ))}
77
+ </Collapsible.Content>
78
+ </Collapsible>
79
+ </Collapsible.Root>
80
+ ),
81
+ };
82
+ export const Group: Story = {
83
+ render: ({ ...args }) => (
84
+ <div className="flex g-medium-30">
85
+ {["🐻", "🐻‍❄️", "🦊", "🐱", "🐶"].map((item) => (
86
+ <Collapsible.Root key={item}>
87
+ <Collapsible>
88
+ <Collapsible.Trigger>{item}</Collapsible.Trigger>
89
+ <Collapsible.Content>{item}</Collapsible.Content>
90
+ </Collapsible>
91
+ </Collapsible.Root>
92
+ ))}
93
+ </div>
94
+ ),
95
+ };
@@ -0,0 +1,50 @@
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 CollapsibleContext = createContext<IComponentAPI>(defaultComponentAPI);
10
+ export const useCollapsible = () => useContext(CollapsibleContext);
11
+
12
+ export const CollapsibleProvider = ({
13
+ children,
14
+ }: IReactChildren): JSX.Element => {
15
+ const context = useCollapsibleProvider();
16
+
17
+ return (
18
+ <CollapsibleContext.Provider value={context}>
19
+ {children}
20
+ </CollapsibleContext.Provider>
21
+ );
22
+ };
23
+
24
+ function useCollapsibleProvider(): IComponentAPI {
25
+ const [expanded, setExpanded] = useState<boolean>(false);
26
+ const [defaultOpen, setDefaultOpen] = useState<boolean>(false);
27
+ const collapsibleId = React.useId();
28
+
29
+ const toggleCollapsible = () => {
30
+ setExpanded(!expanded);
31
+ setDefaultOpen(false);
32
+ };
33
+
34
+ const applyDefaultOpen = () => {
35
+ setExpanded(!expanded);
36
+ setDefaultOpen(true);
37
+ };
38
+
39
+ return {
40
+ id: collapsibleId,
41
+ states: {
42
+ expanded,
43
+ defaultOpen,
44
+ },
45
+ methods: {
46
+ toggleCollapsible: () => toggleCollapsible(),
47
+ applyDefaultOpen: () => applyDefaultOpen(),
48
+ },
49
+ };
50
+ }
@@ -0,0 +1,137 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+
5
+ import { CollapsibleProvider, useCollapsible } from "./hooks";
6
+ import { Button, IButtonProperties } from "..";
7
+ import { applyDataState } from "../utils";
8
+ import { IReactChildren, ComponentVariantEnum } from "../../../../types";
9
+
10
+ export interface ICollapsibleComposition {
11
+ Root: typeof CollapsibleRoot;
12
+ Trigger: typeof CollapsibleTrigger;
13
+ Content: typeof CollapsibleContent;
14
+ }
15
+ export interface ICollapsibleProperties extends React.ComponentProps<"div"> {
16
+ defaultOpen?: boolean;
17
+ showFirstChild?: boolean;
18
+ }
19
+
20
+ /**
21
+ * Collapsible is a component that can be expanded or collapsed by its child trigger component.
22
+ *
23
+ * **Best practices:**
24
+ *
25
+ * - Use semantic HTML elements inside the collapsible content.
26
+ * - Ensure that the collapsible content is hidden from screen readers when it is collapsed.
27
+ * - Provide a clear and descriptive label for the trigger element that accurately conveys the content of the collapsible section.
28
+ *
29
+ * @returns {ReactElement} The Collapsible component.
30
+ */
31
+ const Collapsible = (props: ICollapsibleProperties) => {
32
+ const { children, ...restProps } = props;
33
+ const collapsibleContext = useCollapsible();
34
+
35
+ return (
36
+ <div
37
+ data-state={applyDataState(Boolean(collapsibleContext.states.expanded))}
38
+ {...restProps}
39
+ >
40
+ {children}
41
+ </div>
42
+ );
43
+ };
44
+ Collapsible.displayName = "Collapsible";
45
+
46
+ const CollapsibleRoot = ({ children }: IReactChildren) => {
47
+ return <CollapsibleProvider>{children}</CollapsibleProvider>;
48
+ };
49
+ CollapsibleRoot.displayName = "Collapsible.Root";
50
+
51
+ /**
52
+ * Collapsible.Trigger is used to triggers the expansion and collapse of the associated Collapsible.Content component.
53
+ *
54
+ * **Best practices:**
55
+ *
56
+ * - Use a clear and descriptive title for the trigger that accurately conveys the content of the associated Collapsible section.
57
+ * - Ensure that the trigger can be operated using only the keyboard.
58
+ * - Ensure that the focus is properly managed when the trigger is activated.
59
+ *
60
+ * @param {IButtonProperties} props - The props for the Collapsible.Trigger component.
61
+ * @returns {ReactElement} The Collapsible.Trigger component.
62
+ */
63
+ const CollapsibleTrigger = (props: IButtonProperties) => {
64
+ const { children, disabled, onClick, ...restProps } = props;
65
+ const { id, states, methods } = useCollapsible();
66
+ const { toggleCollapsible } = methods;
67
+
68
+ const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
69
+ if (toggleCollapsible) toggleCollapsible();
70
+ if (onClick) onClick(event);
71
+ };
72
+
73
+ return (
74
+ <Button
75
+ disabled={disabled}
76
+ aria-controls={id}
77
+ data-state={applyDataState(Boolean(states.expanded))}
78
+ data-expanded={states.expanded}
79
+ onClick={handleClick}
80
+ variant={props.variant ?? ComponentVariantEnum.Ghost}
81
+ {...restProps}
82
+ >
83
+ {children}
84
+ </Button>
85
+ );
86
+ };
87
+ CollapsibleTrigger.displayName = "Collapsible.Trigger";
88
+
89
+ /**
90
+ * Collapsible.Content is used to contains the content of the associated Collapsible.Trigger component.
91
+ *
92
+ * **Best practices:**
93
+ *
94
+ * - Ensure that the content is hidden when the associated Collapsible section is collapsed.
95
+ * - Ensure that the content is properly focused when the associated Collapsible section is expanded.
96
+ *
97
+ * @param {ICollapsibleProperties} props - The props for the Collapsible.Content component.components.
98
+ * @param {boolean} props.defaultOpen - The initial open state of the Collapsible content. Defaults to false.
99
+ * @param {boolean} props.showFirstChild - The props used to render the first child component whether the component is closed or not.
100
+ * @param {ReactNode} props.children - The content to be rendered inside the Collapsible.
101
+ * @returns {ReactElement} The Collapsible.Content component.
102
+ */
103
+ const CollapsibleContent = (props: ICollapsibleProperties) => {
104
+ const { defaultOpen = false, showFirstChild, children, ...restProps } = props;
105
+ const { id, states, methods } = useCollapsible();
106
+ const { applyDefaultOpen } = methods;
107
+
108
+ const childArray = React.Children.toArray(children);
109
+ const displayChildren = states.expanded ?? states.defaultOpen;
110
+
111
+ const displayFirstChild =
112
+ showFirstChild && childArray.length > 1 && !states.expanded;
113
+
114
+ React.useEffect(() => {
115
+ if (defaultOpen && applyDefaultOpen) applyDefaultOpen();
116
+ // eslint-disable-next-line react-hooks/exhaustive-deps
117
+ }, []);
118
+
119
+ return (
120
+ <div
121
+ id={id}
122
+ data-state={applyDataState(Boolean(states.expanded))}
123
+ role="region"
124
+ {...restProps}
125
+ >
126
+ {displayFirstChild && childArray[0]}
127
+ {displayChildren && children}
128
+ </div>
129
+ );
130
+ };
131
+ CollapsibleContent.displayName = "Collapsible.Content";
132
+
133
+ Collapsible.Root = CollapsibleRoot;
134
+ Collapsible.Trigger = CollapsibleTrigger;
135
+ Collapsible.Content = CollapsibleContent;
136
+
137
+ export { Collapsible, CollapsibleRoot, CollapsibleTrigger, CollapsibleContent };
@@ -0,0 +1,73 @@
1
+ import React from "react";
2
+ import styled from "styled-components";
3
+ import type { Meta, StoryObj } from "@storybook/react";
4
+
5
+ import { Dialog } from "..";
6
+ import { ComponentSizeEnum } from "../../../../types";
7
+
8
+ const Wrapper = styled.div``;
9
+ const meta = {
10
+ title: "Components/Dialog",
11
+ component: Dialog,
12
+ tags: ["autodocs"],
13
+ } satisfies Meta<typeof Dialog>;
14
+ export default meta;
15
+
16
+ type Story = StoryObj<typeof meta>;
17
+ export const Default: Story = {
18
+ args: {
19
+ closeOnInteract: false,
20
+ open: false,
21
+ raw: false,
22
+ },
23
+ argTypes: {
24
+ sizing: {
25
+ options: [
26
+ ComponentSizeEnum.Small,
27
+ ComponentSizeEnum.Medium,
28
+ ComponentSizeEnum.Large,
29
+ ],
30
+ control: { type: "radio" },
31
+ },
32
+ },
33
+ render: ({ ...args }) => (
34
+ <Dialog.Root>
35
+ <Dialog.Trigger>🐻‍❄️</Dialog.Trigger>
36
+ <Dialog>
37
+ 🐻🐻‍❄️🦊🐱🐶
38
+ <Dialog.Menu>
39
+ <Dialog.Control>🐻</Dialog.Control>
40
+ </Dialog.Menu>
41
+ </Dialog>
42
+ <Dialog.Overlay />
43
+ </Dialog.Root>
44
+ ),
45
+ };
46
+ export const DefaultOpen = {
47
+ render: ({ ...args }) => (
48
+ <Dialog.Root>
49
+ <Dialog.Trigger>🐻‍❄️</Dialog.Trigger>
50
+
51
+ <Dialog open>
52
+ 🐻🐻‍❄️🦊🐱🐶
53
+ <Dialog.Menu>
54
+ <Dialog.Control>🐻</Dialog.Control>
55
+ </Dialog.Menu>
56
+ </Dialog>
57
+ <Dialog.Overlay />
58
+ </Dialog.Root>
59
+ ),
60
+ };
61
+ export const NoOverlay = {
62
+ render: ({ ...args }) => (
63
+ <Dialog.Root>
64
+ <Dialog.Trigger>🐻‍❄️</Dialog.Trigger>
65
+ <Dialog open>
66
+ 🐻🐻‍❄️🦊🐱🐶
67
+ <Dialog.Menu>
68
+ <Dialog.Control>🐻</Dialog.Control>
69
+ </Dialog.Menu>
70
+ </Dialog>
71
+ </Dialog.Root>
72
+ ),
73
+ };
@@ -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 DialogContext = createContext<IComponentAPI>(defaultComponentAPI);
10
+ export const useDialog = () => useContext(DialogContext);
11
+
12
+ export const DialogProvider = ({ children }: IReactChildren): JSX.Element => {
13
+ const context = useDialogProvider();
14
+
15
+ return (
16
+ <DialogContext.Provider value={context}>{children}</DialogContext.Provider>
17
+ );
18
+ };
19
+
20
+ function useDialogProvider(): IComponentAPI {
21
+ const [open, setOpen] = useState<boolean>(false);
22
+ const dialogId = React.useId();
23
+
24
+ return {
25
+ id: dialogId,
26
+ states: {
27
+ open: open,
28
+ },
29
+ methods: {
30
+ toggleDialog: () => setOpen(!open),
31
+ getDialogId: (type: "trigger" | "dialog" | "inner-control"): string =>
32
+ `${dialogId}-${type}`,
33
+ },
34
+ };
35
+ }