@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,159 @@
1
+ import React from "react";
2
+
3
+ import { test, vi, afterEach, describe, expect } from "vitest";
4
+ import {
5
+ screen,
6
+ render,
7
+ cleanup,
8
+ waitFor,
9
+ fireEvent,
10
+ } from "@testing-library/react";
11
+ import { axe, toHaveNoViolations } from "jest-axe";
12
+
13
+ import { DropdownMenu } from "../../src/dropdown";
14
+
15
+ afterEach(async () => {
16
+ vi.clearAllMocks();
17
+ vi.resetModules();
18
+ cleanup();
19
+ });
20
+
21
+ const onClickCallback = vi.fn();
22
+ const DropdownDefault = (args: { defaultOpen?: boolean }) => {
23
+ return (
24
+ <DropdownMenu.Root>
25
+ <DropdownMenu.Trigger onClick={onClickCallback}>
26
+ Trigger
27
+ </DropdownMenu.Trigger>
28
+ <DropdownMenu>
29
+ <DropdownMenu.Content
30
+ defaultOpen={args.defaultOpen}
31
+ aria-label="test-menu"
32
+ >
33
+ <DropdownMenu.Item aria-label="toggle-item" onClick={onClickCallback}>
34
+ Toggle Item
35
+ </DropdownMenu.Item>
36
+ <DropdownMenu.Item
37
+ radio
38
+ aria-label="static-item"
39
+ onClick={onClickCallback}
40
+ >
41
+ Static Item
42
+ </DropdownMenu.Item>
43
+ </DropdownMenu.Content>
44
+ </DropdownMenu>
45
+ </DropdownMenu.Root>
46
+ );
47
+ };
48
+
49
+ expect.extend(toHaveNoViolations);
50
+ describe("Dropdown", () => {
51
+ test("Renders without accessibility violation", async () => {
52
+ const { container } = render(<DropdownDefault defaultOpen />);
53
+ const ComponentContainer = await axe(container);
54
+ expect(ComponentContainer).toHaveNoViolations();
55
+ });
56
+ test("Renders with accessibility definition", async () => {
57
+ render(<DropdownDefault />);
58
+ const Trigger = screen.getByRole("button");
59
+
60
+ expect(Trigger.getAttribute("data-state")).toBe("closed");
61
+ expect(Trigger.getAttribute("aria-haspopup")).toBe("menu");
62
+ expect(Trigger.getAttribute("id")).toBeDefined();
63
+
64
+ fireEvent.click(Trigger);
65
+ await waitFor(() => {
66
+ const Content = screen.getByLabelText("test-menu");
67
+
68
+ expect(Content.getAttribute("data-state")).toBe("open");
69
+ expect(Content.getAttribute("data-side")).toBeDefined();
70
+ expect(Content.getAttribute("data-align")).toBeDefined();
71
+ expect(Content.getAttribute("aria-labelledby")).toBeDefined();
72
+ });
73
+ });
74
+ test("Fires the defined callback function and toggle the content when the trigger is clicked", async () => {
75
+ render(<DropdownDefault />);
76
+
77
+ fireEvent.click(screen.getByRole("button"));
78
+ await waitFor(() => {
79
+ expect(onClickCallback).toHaveBeenCalled();
80
+ expect(screen.getByLabelText("test-menu")).toBeDefined();
81
+ });
82
+ });
83
+ test("Fires the defined callback function and toggle the content when the item is clicked", async () => {
84
+ render(<DropdownDefault />);
85
+
86
+ fireEvent.click(screen.getByRole("button"));
87
+ await waitFor(() => {
88
+ expect(onClickCallback).toHaveBeenCalled();
89
+ expect(screen.getByLabelText("test-menu")).toBeDefined();
90
+ expect(screen.getByLabelText("toggle-item")).toBeDefined();
91
+ expect(screen.getByLabelText("static-item")).toBeDefined();
92
+ });
93
+
94
+ fireEvent.click(screen.getByLabelText("toggle-item"));
95
+ await waitFor(() => {
96
+ expect(() => screen.getByLabelText("test-menu")).toThrow();
97
+ });
98
+ });
99
+ test("Fires the defined callback function without toggling the content when the item is clicked", async () => {
100
+ render(<DropdownDefault defaultOpen />);
101
+
102
+ await waitFor(() =>
103
+ expect(screen.getByLabelText("test-menu")).toBeDefined()
104
+ );
105
+
106
+ fireEvent.click(screen.getByLabelText("static-item"));
107
+ await waitFor(() => {
108
+ expect(onClickCallback).toHaveBeenCalled();
109
+ expect(screen.getByLabelText("test-menu")).toBeDefined();
110
+ });
111
+ });
112
+ test("Fires the defined callback function if an inner item is focused and a keypress is detected", async () => {
113
+ render(<DropdownDefault defaultOpen />);
114
+ await waitFor(() =>
115
+ expect(screen.getByLabelText("test-menu")).toBeDefined()
116
+ );
117
+
118
+ screen.getByLabelText("toggle-item").focus();
119
+ fireEvent.keyDown(screen.getByLabelText("toggle-item"), {
120
+ key: "Enter",
121
+ code: "Enter",
122
+ });
123
+ await waitFor(() => {
124
+ expect(onClickCallback).toHaveBeenCalled();
125
+ expect(() => screen.getByLabelText("toggle-item")).toThrow();
126
+ });
127
+
128
+ fireEvent.click(screen.getByRole("button"));
129
+ await waitFor(() =>
130
+ expect(screen.getByLabelText("test-menu")).toBeDefined()
131
+ );
132
+ screen.getByLabelText("toggle-item").focus();
133
+ fireEvent.keyDown(screen.getByLabelText("static-item"), {
134
+ key: "Space",
135
+ code: "Space",
136
+ });
137
+ await waitFor(() => {
138
+ expect(onClickCallback).toHaveBeenCalled();
139
+ expect(screen.getByLabelText("static-item")).toBeDefined();
140
+ });
141
+ });
142
+ test("Renders the component by default if open is defined", async () => {
143
+ render(<DropdownDefault defaultOpen />);
144
+ await waitFor(() =>
145
+ expect(screen.getByLabelText("test-menu")).toBeDefined()
146
+ );
147
+ });
148
+ test("Close the component on click outside", async () => {
149
+ render(<DropdownDefault defaultOpen />);
150
+ await waitFor(() =>
151
+ expect(screen.getByLabelText("test-menu")).toBeDefined()
152
+ );
153
+
154
+ fireEvent.mouseDown(document.body);
155
+ await waitFor(() => {
156
+ expect(() => screen.getByLabelText("toggle-item")).toThrow();
157
+ });
158
+ });
159
+ });
@@ -0,0 +1,100 @@
1
+ import React from "react";
2
+
3
+ import { test, vi, afterEach, describe, expect } from "vitest";
4
+ import {
5
+ screen,
6
+ render,
7
+ cleanup,
8
+ waitFor,
9
+ fireEvent,
10
+ } from "@testing-library/react";
11
+ import { axe, toHaveNoViolations } from "jest-axe";
12
+
13
+ import { Field } from "../../src/field";
14
+
15
+ afterEach(async () => {
16
+ vi.clearAllMocks();
17
+ vi.resetModules();
18
+ cleanup();
19
+ });
20
+
21
+ const onClickCallback = vi.fn();
22
+ const onChangeCallback = vi.fn();
23
+ const FieldDefault = (args: { error?: string; hint?: string }) => {
24
+ return (
25
+ <Field.Root>
26
+ <Field.Wrapper>
27
+ <Field.Label>Test Input</Field.Label>
28
+ <Field
29
+ name="test"
30
+ value="test"
31
+ placeholder="test-placeholder"
32
+ onChange={onChangeCallback}
33
+ onClick={onClickCallback}
34
+ {...args}
35
+ />
36
+ </Field.Wrapper>
37
+ </Field.Root>
38
+ );
39
+ };
40
+
41
+ expect.extend(toHaveNoViolations);
42
+ describe("Field", () => {
43
+ test("Renders without accessibility violation", async () => {
44
+ const { container } = render(<FieldDefault />);
45
+ const ComponentContainer = await axe(container);
46
+ expect(ComponentContainer).toHaveNoViolations();
47
+ });
48
+ test("Renders with accessibility definition", async () => {
49
+ render(<FieldDefault />);
50
+ const FieldComponent = screen.getByPlaceholderText("test-placeholder");
51
+
52
+ expect(FieldComponent.getAttribute("aria-invalid")).toBe("false");
53
+ expect(FieldComponent.getAttribute("aria-describedby")).toBeDefined();
54
+ expect(FieldComponent.getAttribute("aria-errormessage")).toBe(null);
55
+ expect(FieldComponent.getAttribute("data-error")).toBe("false");
56
+ });
57
+ test("Update the content on change and fires the defined callback function", async () => {
58
+ render(<FieldDefault />);
59
+ const FieldComponent = screen.getByPlaceholderText("test-placeholder");
60
+
61
+ fireEvent.click(FieldComponent);
62
+ fireEvent.change(FieldComponent, { target: { value: "updated" } });
63
+ await waitFor(() => {
64
+ expect(onClickCallback).toHaveBeenCalled();
65
+ expect(onChangeCallback).toHaveBeenCalled();
66
+ });
67
+ });
68
+ test("Renders a meta component on error", async () => {
69
+ render(<FieldDefault error="error-message" />);
70
+ const FieldComponent = screen.getByPlaceholderText("test-placeholder");
71
+
72
+ await waitFor(() => {
73
+ expect(screen.getByText("error-message")).toBeDefined();
74
+ expect(FieldComponent.getAttribute("aria-invalid")).toBe("true");
75
+ expect(FieldComponent.getAttribute("aria-errormessage")).toBe(
76
+ "error-message"
77
+ );
78
+ expect(FieldComponent.getAttribute("data-error")).toBe("true");
79
+ });
80
+ });
81
+ test("Renders a meta component as hint", async () => {
82
+ render(<FieldDefault hint="hint-message" />);
83
+ const FieldComponent = screen.getByPlaceholderText("test-placeholder");
84
+
85
+ await waitFor(() => {
86
+ expect(screen.getByText("hint-message")).toBeDefined();
87
+ expect(FieldComponent.getAttribute("aria-invalid")).toBe("false");
88
+ expect(FieldComponent.getAttribute("aria-errormessage")).toBe(null);
89
+ expect(FieldComponent.getAttribute("data-error")).toBe("false");
90
+ });
91
+ });
92
+ test("Hides the hint component to display the error when they're both defined at the same time", async () => {
93
+ render(<FieldDefault error="error-message" hint="hint-message" />);
94
+
95
+ await waitFor(() => {
96
+ expect(screen.getByText("error-message")).toBeDefined();
97
+ expect(() => screen.getByText("hint-message")).toThrow();
98
+ });
99
+ });
100
+ });
@@ -0,0 +1,199 @@
1
+ import React from "react";
2
+ import { expect, test, vi, beforeEach, afterEach, describe } from "vitest";
3
+ import {
4
+ render,
5
+ screen,
6
+ cleanup,
7
+ fireEvent,
8
+ waitFor,
9
+ } from "@testing-library/react";
10
+
11
+ import { OTPField } from "../";
12
+ import { axe, toHaveNoViolations } from "jest-axe";
13
+
14
+ beforeEach(async () => {
15
+ vi.clearAllMocks();
16
+ });
17
+
18
+ afterEach(async () => {
19
+ vi.clearAllMocks();
20
+ vi.resetModules();
21
+ cleanup();
22
+ });
23
+
24
+ const Component = ({
25
+ length,
26
+ onComplete,
27
+ }: {
28
+ length?: number;
29
+ onComplete?: (value: string) => void;
30
+ }) => {
31
+ return (
32
+ <OTPField length={length} onComplete={onComplete}>
33
+ <OTPField.Group aria-label="otp-field-group">
34
+ {Array.from({ length: length ?? 6 }).map((_, index) => (
35
+ <OTPField.Slot key={index} index={index} />
36
+ ))}
37
+ </OTPField.Group>
38
+ </OTPField>
39
+ );
40
+ };
41
+
42
+ expect.extend(toHaveNoViolations);
43
+ describe("One Tiime Password Field Component", () => {
44
+ test("Renders without accessibility violation", async () => {
45
+ const { container } = render(<Component />);
46
+
47
+ const ComponentContainer = await axe(container);
48
+ expect(ComponentContainer).toHaveNoViolations();
49
+ });
50
+ test("Render OTP Field components", async () => {
51
+ render(<Component length={1} />);
52
+
53
+ expect(
54
+ screen.getByTestId("otp-field-slot").getAttribute("autoComplete")
55
+ ).toEqual("one-time-code");
56
+ });
57
+ test("Does not render OTP Field Slot if OTP Field context isn't set", async () => {
58
+ render(
59
+ <OTPField.Group aria-label="otp-field-group">
60
+ <OTPField.Slot index={0} />
61
+ </OTPField.Group>
62
+ );
63
+
64
+ expect(() => screen.getByTestId("otp-field-slot")).toThrow();
65
+ });
66
+ test("Render OTP Slots based on length", async () => {
67
+ render(<Component length={10} />);
68
+
69
+ expect(screen.getAllByTestId("otp-field-slot").length).toEqual(10);
70
+ });
71
+ test("Render OTP Field with 6 Slots if length is not defined", async () => {
72
+ render(<Component />);
73
+
74
+ expect(screen.getAllByTestId("otp-field-slot").length).toEqual(6);
75
+ });
76
+ test("Update slot value onChange", async () => {
77
+ render(<Component length={1} />);
78
+
79
+ const field = screen.getByTestId("otp-field-slot");
80
+ fireEvent.change(field, { target: { value: "1" } });
81
+
82
+ expect(field.getAttribute("value")).toEqual("1");
83
+ });
84
+ test("Fire onComplete when every slots are filled", async () => {
85
+ const onComplete = vi.fn();
86
+ render(<Component length={1} onComplete={onComplete} />);
87
+
88
+ fireEvent.change(screen.getByTestId("otp-field-slot"), {
89
+ target: { value: "1" },
90
+ });
91
+ expect(onComplete).toHaveBeenCalled();
92
+ });
93
+ test("Does not focus next slot when current slot is not filled", async () => {
94
+ render(<Component length={2} />);
95
+
96
+ fireEvent.focus(screen.getAllByTestId("otp-field-slot")[0]!);
97
+ fireEvent.keyDown(screen.getAllByTestId("otp-field-slot")[0]!, {
98
+ key: "Tab",
99
+ });
100
+
101
+ expect(
102
+ screen.getAllByTestId("otp-field-slot")[1]!.getAttribute("data-active")
103
+ ).toEqual("false");
104
+ });
105
+ test("Focus next slot when current slot is filled", async () => {
106
+ render(<Component length={2} />);
107
+
108
+ fireEvent.focus(screen.getAllByTestId("otp-field-slot")[0]!);
109
+ fireEvent.change(screen.getAllByTestId("otp-field-slot")[0]!, {
110
+ target: { value: "1" },
111
+ });
112
+
113
+ await waitFor(() => {
114
+ expect(
115
+ screen.getAllByTestId("otp-field-slot")[1]!.getAttribute("data-active")
116
+ ).toEqual("true");
117
+ });
118
+ });
119
+ test("Disable behavior when ArrowLeft || ArrowRight || Home || End key is pressed", async () => {
120
+ render(<Component length={2} />);
121
+ const slot1 = screen.getAllByTestId("otp-field-slot")[0]!;
122
+ const slot2 = screen.getAllByTestId("otp-field-slot")[1]!;
123
+
124
+ fireEvent.focus(slot1);
125
+ fireEvent.keyDown(slot1, {
126
+ key: "ArrowRight",
127
+ });
128
+ expect(slot2.getAttribute("data-active")).toEqual("false");
129
+ fireEvent.keyDown(slot1, {
130
+ key: "End",
131
+ });
132
+ expect(slot2.getAttribute("data-active")).toEqual("false");
133
+
134
+ fireEvent.change(slot1, {
135
+ target: { value: "1" },
136
+ });
137
+ fireEvent.keyDown(slot1, {
138
+ key: "ArrowLeft",
139
+ });
140
+ expect(slot1.getAttribute("data-active")).toEqual("false");
141
+ fireEvent.keyDown(slot1, {
142
+ key: "Home",
143
+ });
144
+ expect(slot1.getAttribute("data-active")).toEqual("false");
145
+ });
146
+ test("Remove value from current slot and focus previous slot when Backspace || Delete key is pressed", async () => {
147
+ render(<Component length={3} />);
148
+
149
+ fireEvent.focus(screen.getAllByTestId("otp-field-slot")[0]!);
150
+ fireEvent.change(screen.getAllByTestId("otp-field-slot")[0]!, {
151
+ target: { value: "1" },
152
+ });
153
+
154
+ fireEvent.change(screen.getAllByTestId("otp-field-slot")[1]!, {
155
+ target: { value: "2" },
156
+ });
157
+ fireEvent.keyDown(screen.getAllByTestId("otp-field-slot")[1]!, {
158
+ key: "Backspace",
159
+ });
160
+ fireEvent.keyDown(screen.getAllByTestId("otp-field-slot")[1]!, {
161
+ key: "Delete",
162
+ });
163
+
164
+ await waitFor(() => {
165
+ expect(
166
+ screen.getAllByTestId("otp-field-slot")[0]!.getAttribute("data-active")
167
+ ).toEqual("true");
168
+ });
169
+ });
170
+ test("Fill every Slots when a value is pasted", async () => {
171
+ render(<Component length={2} />);
172
+
173
+ fireEvent.focus(screen.getAllByTestId("otp-field-slot")[0]!);
174
+ fireEvent.paste(screen.getAllByTestId("otp-field-slot")[0]!, {
175
+ clipboardData: {
176
+ getData: () => "123456",
177
+ },
178
+ });
179
+
180
+ expect(
181
+ screen.getAllByTestId("otp-field-slot")[0]!.getAttribute("value")
182
+ ).toEqual("1");
183
+ expect(
184
+ screen.getAllByTestId("otp-field-slot")[1]!.getAttribute("value")
185
+ ).toEqual("2");
186
+ });
187
+ test("Focus the next slot to fill on click", async () => {
188
+ render(<Component length={3} />);
189
+ const slot1 = screen.getAllByTestId("otp-field-slot")[0]!;
190
+ const slot2 = screen.getAllByTestId("otp-field-slot")[1]!;
191
+ const slot3 = screen.getAllByTestId("otp-field-slot")[2]!;
192
+
193
+ fireEvent.change(slot1, { target: { value: "1" } });
194
+ fireEvent.click(slot3);
195
+ fireEvent.mouseDown(slot3);
196
+
197
+ expect(slot2.getAttribute("data-active")).toEqual("true");
198
+ });
199
+ });
@@ -0,0 +1,70 @@
1
+ import React from "react";
2
+
3
+ import { test, vi, afterEach, describe, expect } from "vitest";
4
+ import {
5
+ screen,
6
+ render,
7
+ cleanup,
8
+ waitFor,
9
+ fireEvent,
10
+ } from "@testing-library/react";
11
+ import { axe, toHaveNoViolations } from "jest-axe";
12
+
13
+ import { Overlay } from "../../src/overlay";
14
+
15
+ afterEach(async () => {
16
+ vi.clearAllMocks();
17
+ vi.resetModules();
18
+ cleanup();
19
+ });
20
+
21
+ const onClickCallback = vi.fn();
22
+ const OverlayDefault = (args: {
23
+ visible?: boolean;
24
+ closeOnInteract?: boolean;
25
+ }) => {
26
+ return (
27
+ <Overlay
28
+ visible={args.visible}
29
+ closeOnInteract={Boolean(args.closeOnInteract)}
30
+ onClick={onClickCallback}
31
+ aria-label="test-overlay"
32
+ >
33
+ overlay
34
+ </Overlay>
35
+ );
36
+ };
37
+
38
+ expect.extend(toHaveNoViolations);
39
+ describe("Overlay", () => {
40
+ test("Renders without accessibility violation", async () => {
41
+ const { container } = render(<OverlayDefault visible />);
42
+ const ComponentContainer = await axe(container);
43
+
44
+ expect(ComponentContainer).toHaveNoViolations();
45
+ });
46
+ test("Renders with accessibility definition", async () => {
47
+ render(<OverlayDefault visible />);
48
+ const OverlayComponent = screen.getByLabelText("test-overlay");
49
+
50
+ expect(OverlayComponent.getAttribute("tabIndex")).toBe("-1");
51
+ expect(OverlayComponent.getAttribute("aria-hidden")).toBe("true");
52
+ });
53
+ test("Does not render by default is visible is falsy", async () => {
54
+ render(<OverlayDefault visible={false} />);
55
+ expect(() => screen.getByLabelText("test-overlay")).toThrow();
56
+ });
57
+ test("Update the component state on click and fires the defined callback function", async () => {
58
+ render(<OverlayDefault visible closeOnInteract />);
59
+ const OverlayComponent = screen.getByLabelText("test-overlay");
60
+
61
+ expect(OverlayComponent).toBeDefined();
62
+ fireEvent.click(OverlayComponent);
63
+
64
+ await waitFor(() => {
65
+ expect(() => screen.getByLabelText("test-overlay")).toThrow();
66
+ expect(onClickCallback).toHaveBeenCalled();
67
+ expect(onClickCallback).toHaveBeenCalledTimes(1);
68
+ });
69
+ });
70
+ });
@@ -0,0 +1,98 @@
1
+ import React from "react";
2
+
3
+ import { test, vi, afterEach, describe, expect } from "vitest";
4
+ import {
5
+ screen,
6
+ render,
7
+ cleanup,
8
+ waitFor,
9
+ fireEvent,
10
+ } from "@testing-library/react";
11
+ import { axe, toHaveNoViolations } from "jest-axe";
12
+
13
+ import { Page } from "../../src/page";
14
+
15
+ afterEach(async () => {
16
+ vi.clearAllMocks();
17
+ vi.resetModules();
18
+ cleanup();
19
+ });
20
+
21
+ const onClickCallback = vi.fn();
22
+ const PageDefault = () => {
23
+ return (
24
+ <Page>
25
+ <Page.Tools
26
+ aria-label="page-tools"
27
+ shortcut
28
+ hotkey="a"
29
+ side="left"
30
+ sizing="small"
31
+ onClick={onClickCallback}
32
+ >
33
+ tool item
34
+ </Page.Tools>
35
+ <Page.Navigation aria-label="page-nav">nav item</Page.Navigation>
36
+ <Page.Menu aria-label="page-menu">menu item</Page.Menu>
37
+
38
+ <Page.Content aria-label="page-content">content item</Page.Content>
39
+
40
+ <Page.Panel
41
+ shortcut
42
+ hotkey="b"
43
+ side="bottom"
44
+ sizing="large"
45
+ aria-label="page-panel"
46
+ onClick={onClickCallback}
47
+ >
48
+ panel item
49
+ </Page.Panel>
50
+ </Page>
51
+ );
52
+ };
53
+
54
+ expect.extend(toHaveNoViolations);
55
+ describe("Page", () => {
56
+ test("Renders without accessibility violation", async () => {
57
+ const { container } = render(<PageDefault />);
58
+ const ComponentContainer = await axe(container);
59
+
60
+ expect(ComponentContainer).toHaveNoViolations();
61
+ });
62
+ test("Render every compound components", async () => {
63
+ render(<PageDefault />);
64
+ const ToolComponent = screen.getByLabelText("page-tools");
65
+ const PanelComponent = screen.getByLabelText("page-panel");
66
+ const NavComponent = screen.getByLabelText("page-nav");
67
+ const MenuComponent = screen.getByLabelText("page-menu");
68
+ const ContentComponent = screen.getByLabelText("page-content");
69
+
70
+ // Accesibility criterias are tested in the components used page Page [Toolbar]
71
+ expect(ToolComponent).toBeDefined();
72
+ expect(PanelComponent).toBeDefined();
73
+ expect(NavComponent).toBeDefined();
74
+ expect(MenuComponent).toBeDefined();
75
+ expect(ContentComponent).toBeDefined();
76
+ });
77
+ test("Open tool and panel components on click and when the shortcuts are triggered", async () => {
78
+ const { container } = render(<PageDefault />);
79
+
80
+ expect(() => screen.getByText("tool item")).toThrow();
81
+ expect(() => screen.getByText("panel item")).toThrow();
82
+
83
+ fireEvent.keyDown(container, { key: "b", code: "KeyB", ctrlKey: true });
84
+ fireEvent.keyDown(container, { key: "a", code: "KeyA", ctrlKey: true });
85
+ await waitFor(() => {
86
+ expect(screen.getByText("tool item")).toBeDefined();
87
+ expect(screen.getByText("panel item")).toBeDefined();
88
+ });
89
+
90
+ fireEvent.click(screen.getByTitle("ctrl + a"));
91
+ fireEvent.click(screen.getByTitle("ctrl + b"));
92
+ await waitFor(() => {
93
+ expect(() => screen.getByText("tool item")).toThrow();
94
+ expect(() => screen.getByText("panel item")).toThrow();
95
+ expect(onClickCallback).toHaveBeenCalled();
96
+ });
97
+ });
98
+ });
@@ -0,0 +1,28 @@
1
+ import React from "react";
2
+
3
+ import { test, vi, afterEach, describe, expect } from "vitest";
4
+ import { screen, render, cleanup } from "@testing-library/react";
5
+ import { Portal } from "../../src/portal";
6
+
7
+ afterEach(async () => {
8
+ vi.clearAllMocks();
9
+ vi.resetModules();
10
+ cleanup();
11
+ });
12
+
13
+ const PortalDefault = () => {
14
+ return (
15
+ <React.Fragment>
16
+ <Portal container="portal">portal-content</Portal>
17
+ <div aria-label="test-portal" id="portal" />
18
+ </React.Fragment>
19
+ );
20
+ };
21
+
22
+ describe("Portal", () => {
23
+ test("Renders in the dedicated container", async () => {
24
+ render(<PortalDefault />);
25
+ expect(screen.getByLabelText("test-portal")).toBeDefined();
26
+ expect(screen.getByText("portal-content")).toBeDefined();
27
+ });
28
+ });