@dhasdk/simple-ui 1.0.7 → 1.0.8
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/.babelrc +12 -0
- package/.storybook/main.ts +35 -0
- package/.storybook/preview.ts +4 -0
- package/BAKpostcss.config.jsBAK +15 -0
- package/BAKtailwind.config.mjsBAK +99 -0
- package/README.md +464 -16
- package/coverage/storybook/coverage-storybook.json +32411 -0
- package/coverage/storybook/lcov-report/Accordion.tsx.html +805 -0
- package/coverage/storybook/lcov-report/Badge.tsx.html +346 -0
- package/coverage/storybook/lcov-report/Breadcrumbs.tsx.html +742 -0
- package/coverage/storybook/lcov-report/Button.tsx.html +448 -0
- package/coverage/storybook/lcov-report/ButtonGroup.tsx.html +403 -0
- package/coverage/storybook/lcov-report/Card.tsx.html +292 -0
- package/coverage/storybook/lcov-report/CharacterCounter.tsx.html +253 -0
- package/coverage/storybook/lcov-report/CheckBox.tsx.html +1555 -0
- package/coverage/storybook/lcov-report/DatePicker.tsx.html +826 -0
- package/coverage/storybook/lcov-report/Input.tsx.html +1012 -0
- package/coverage/storybook/lcov-report/List.tsx.html +364 -0
- package/coverage/storybook/lcov-report/Modal.tsx.html +745 -0
- package/coverage/storybook/lcov-report/Pill.tsx.html +358 -0
- package/coverage/storybook/lcov-report/Search.tsx.html +997 -0
- package/coverage/storybook/lcov-report/SearchContent.tsx.html +235 -0
- package/coverage/storybook/lcov-report/SectionHeader.tsx.html +358 -0
- package/coverage/storybook/lcov-report/Select.tsx.html +1012 -0
- package/coverage/storybook/lcov-report/Shield.tsx.html +802 -0
- package/coverage/storybook/lcov-report/SideBarNav.tsx.html +490 -0
- package/coverage/storybook/lcov-report/Skeleton.tsx.html +394 -0
- package/coverage/storybook/lcov-report/Slider.tsx.html +385 -0
- package/coverage/storybook/lcov-report/Status.tsx.html +322 -0
- package/coverage/storybook/lcov-report/Tabs.tsx.html +610 -0
- package/coverage/storybook/lcov-report/Toggle.tsx.html +373 -0
- package/coverage/storybook/lcov-report/Tooltip.tsx.html +496 -0
- package/coverage/storybook/lcov-report/base.css +224 -0
- package/coverage/storybook/lcov-report/block-navigation.js +87 -0
- package/coverage/storybook/lcov-report/favicon.png +0 -0
- package/coverage/storybook/lcov-report/index.html +476 -0
- package/coverage/storybook/lcov-report/prettify.css +1 -0
- package/coverage/storybook/lcov-report/prettify.js +2 -0
- package/coverage/storybook/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/storybook/lcov-report/sorter.js +196 -0
- package/coverage/storybook/lcov.info +2312 -0
- package/dist/README.md +1815 -0
- package/eslint.config.mjs +13 -0
- package/package.json +6 -7
- package/project.json +11 -0
- package/src/assets/img/Frame.svg +5 -0
- package/src/assets/img/backArrowRight.svg +10 -0
- package/src/assets/img/bc-separator.png +0 -0
- package/src/assets/img/calendar.png +0 -0
- package/src/assets/img/calendar.svg +4 -0
- package/src/assets/img/check.svg +5 -0
- package/src/assets/img/check_box.svg +10 -0
- package/src/assets/img/check_box_empty.svg +10 -0
- package/src/assets/img/check_box_fill.svg +10 -0
- package/src/assets/img/check_box_fill_empty.svg +10 -0
- package/src/assets/img/chevron-down-white.svg +2 -0
- package/src/assets/img/chevron-down.svg +2 -0
- package/src/assets/img/chevron-left.svg +1 -0
- package/src/assets/img/chevron-right-light.svg +4 -0
- package/src/assets/img/chevron-right.svg +3 -0
- package/src/assets/img/chevron-up-white.svg +1 -0
- package/src/assets/img/chevron-up.svg +1 -0
- package/src/assets/img/clock.svg +6 -0
- package/src/assets/img/close.svg +1 -0
- package/src/assets/img/close2.svg +6 -0
- package/src/assets/img/closeModal.svg +10 -0
- package/src/assets/img/close_icon_dark.svg +10 -0
- package/src/assets/img/close_small.svg +3 -0
- package/src/assets/img/emergency_home.svg +10 -0
- package/src/assets/img/first-aid-kit.svg +7 -0
- package/src/assets/img/heartbeat.svg +4 -0
- package/src/assets/img/home-gray.svg +3 -0
- package/src/assets/img/home.svg +3 -0
- package/src/assets/img/hospital.jpg +0 -0
- package/src/assets/img/indeterminate_check_box.svg +10 -0
- package/src/assets/img/indeterminate_check_box_fill.svg +10 -0
- package/src/assets/img/info_24_ 1d4ed8.svg +3 -0
- package/src/assets/img/info_24_ 2c6441.svg +3 -0
- package/src/assets/img/marker_check_by_default.svg +10 -0
- package/src/assets/img/marker_check_by_default_fill.svg +10 -0
- package/src/assets/img/minus-accordion.svg +5 -0
- package/src/assets/img/minus.svg +3 -0
- package/src/assets/img/open.svg +1 -0
- package/src/assets/img/pill-white.svg +7 -0
- package/src/assets/img/pill.svg +5 -0
- package/src/assets/img/plus-accordion.svg +5 -0
- package/src/assets/img/plus.svg +4 -0
- package/src/assets/img/prescription.svg +6 -0
- package/src/assets/img/search.svg +10 -0
- package/src/assets/img/search_icon_light.svg +10 -0
- package/src/assets/img/separator.svg +3 -0
- package/src/assets/img/stethoscope-white.svg +8 -0
- package/src/assets/img/stethoscope.svg +8 -0
- package/src/assets/img/thumb_up.svg +10 -0
- package/src/assets/img/vector.svg +3 -0
- package/src/assets/img/warning-badge-disabled.svg +11 -0
- package/src/assets/img/warning-badge-green.svg +11 -0
- package/src/assets/img/warning-badge-red.svg +11 -0
- package/src/assets/img/warning-badge-yellow.svg +11 -0
- package/src/assets/img/warning.svg +10 -0
- package/src/global.d.ts +13 -0
- package/{index.d.ts → src/index.ts} +13 -5
- package/src/lib/Accordian--Accordian.stories.tsx +312 -0
- package/src/lib/Accordion.spec.tsx +384 -0
- package/src/lib/Accordion.tsx +240 -0
- package/src/lib/AppointmentPicker.spec.tsx +138 -0
- package/src/lib/AppointmentPicker.tsx +97 -0
- package/src/lib/Badge--Badge.stories.tsx +60 -0
- package/src/lib/Badge.spec.tsx +70 -0
- package/src/lib/Badge.tsx +87 -0
- package/src/lib/Breadcrumbs-Breadcrumbs.stories.tsx +114 -0
- package/src/lib/Breadcrumbs.spec.tsx +218 -0
- package/src/lib/Breadcrumbs.tsx +219 -0
- package/src/lib/Button--Button.stories.tsx +220 -0
- package/src/lib/Button.spec.tsx +241 -0
- package/src/lib/Button.tsx +121 -0
- package/src/lib/ButtonGroup--ButtonGroup.stories.tsx +129 -0
- package/src/lib/ButtonGroup.spec.tsx +89 -0
- package/src/lib/ButtonGroup.tsx +107 -0
- package/src/lib/Card--Card.stories.tsx +113 -0
- package/src/lib/Card.spec.tsx +112 -0
- package/src/lib/Card.tsx +69 -0
- package/src/lib/CharacterCounter--CharacterCounter.stories.tsx +169 -0
- package/src/lib/CharacterCounter.spec.tsx +123 -0
- package/src/lib/CharacterCounter.tsx +56 -0
- package/src/lib/CheckBox--CheckBox.stories.tsx +107 -0
- package/src/lib/CheckBox.spec.tsx +412 -0
- package/src/lib/CheckBox.tsx +491 -0
- package/src/lib/DatePicker--DatePicker.stories.tsx +228 -0
- package/src/lib/DatePicker.spec.tsx +424 -0
- package/src/lib/DatePicker.tsx +247 -0
- package/src/lib/Input--Input.stories.tsx +449 -0
- package/src/lib/Input.spec.tsx +281 -0
- package/src/lib/Input.tsx +309 -0
- package/src/lib/List--List.stories.tsx +157 -0
- package/src/lib/List.spec.tsx +211 -0
- package/src/lib/List.tsx +93 -0
- package/src/lib/Modal--Modal.stories.tsx +454 -0
- package/src/lib/Modal.spec.tsx +202 -0
- package/src/lib/Modal.tsx +220 -0
- package/src/lib/Pill--Pill.stories.tsx +98 -0
- package/src/lib/Pill.spec.tsx +103 -0
- package/src/lib/Pill.tsx +91 -0
- package/src/lib/ProgressBar.spec.tsx +106 -0
- package/src/lib/ProgressBar.tsx +112 -0
- package/src/lib/RadioGroup.spec.tsx +84 -0
- package/src/lib/RadioGroup.tsx +74 -0
- package/src/lib/RadioIcon.tsx +13 -0
- package/src/lib/Search--Search.stories.tsx +67 -0
- package/src/lib/Search.spec.tsx +182 -0
- package/src/lib/Search.tsx +304 -0
- package/src/lib/SearchContent.tsx +51 -0
- package/src/lib/SectionHeader--SectionHeader.stories.tsx +98 -0
- package/src/lib/SectionHeader.spec.tsx +60 -0
- package/src/lib/SectionHeader.tsx +91 -0
- package/src/lib/Select--Select.stories.tsx +387 -0
- package/src/lib/Select.spec.tsx +493 -0
- package/src/lib/Select.tsx +311 -0
- package/src/lib/Shield--Shield.stories.tsx +196 -0
- package/src/lib/Shield.spec.tsx +275 -0
- package/src/lib/Shield.tsx +239 -0
- package/src/lib/SideBarNav--SideBarNav.stories.tsx +136 -0
- package/src/lib/SideBarNav.spec.tsx +178 -0
- package/src/lib/SideBarNav.tsx +135 -0
- package/src/lib/Skeleton--Skeleton.stories.tsx +77 -0
- package/src/lib/Skeleton.module.css +16 -0
- package/src/lib/Skeleton.spec.tsx +83 -0
- package/src/lib/Skeleton.tsx +103 -0
- package/src/lib/SkipLink.spec.tsx +76 -0
- package/src/lib/SkipLink.tsx +48 -0
- package/src/lib/Slider--Slider.stories.tsx +108 -0
- package/src/lib/Slider.module.css +109 -0
- package/src/lib/Slider.spec.tsx +67 -0
- package/src/lib/Slider.tsx +101 -0
- package/src/lib/Status--Status.stories.tsx +93 -0
- package/src/lib/Status.spec.tsx +118 -0
- package/src/lib/Status.tsx +79 -0
- package/src/lib/Tabs--Tabs.stories.tsx +294 -0
- package/src/lib/Tabs.spec.tsx +249 -0
- package/src/lib/Tabs.tsx +188 -0
- package/src/lib/Tester.spec.tsx +17 -0
- package/src/lib/Toggle--Toggle.stories.tsx +162 -0
- package/src/lib/Toggle.spec.tsx +122 -0
- package/src/lib/Toggle.tsx +96 -0
- package/src/lib/Tooltip--Tooltip.stories.tsx +315 -0
- package/src/lib/Tooltip.spec.tsx +307 -0
- package/src/lib/Tooltip.tsx +137 -0
- package/src/lib/bak-simple-ui.stories.tsx-bak +24 -0
- package/src/styles.css +190 -0
- package/tsconfig.json +25 -0
- package/tsconfig.lib.json +42 -0
- package/tsconfig.spec.json +29 -0
- package/tsconfig.storybook.json +36 -0
- package/vite.config.mts +87 -0
- package/vitest.setup.ts +12 -0
- package/index.css +0 -1
- package/index.js +0 -35
- package/index.mjs +0 -4981
- package/lib/Accordion.d.ts +0 -36
- package/lib/AppointmentPicker.d.ts +0 -21
- package/lib/Badge.d.ts +0 -11
- package/lib/Breadcrumbs.d.ts +0 -13
- package/lib/Button.d.ts +0 -15
- package/lib/ButtonGroup.d.ts +0 -8
- package/lib/Card.d.ts +0 -11
- package/lib/CharacterCounter.d.ts +0 -11
- package/lib/CheckBox.d.ts +0 -30
- package/lib/DatePicker.d.ts +0 -7
- package/lib/Input.d.ts +0 -16
- package/lib/List.d.ts +0 -22
- package/lib/Modal.d.ts +0 -18
- package/lib/Pill.d.ts +0 -13
- package/lib/ProgressBar.d.ts +0 -19
- package/lib/RadioGroup.d.ts +0 -15
- package/lib/Search.d.ts +0 -26
- package/lib/SearchContent.d.ts +0 -6
- package/lib/SectionHeader.d.ts +0 -18
- package/lib/Select.d.ts +0 -19
- package/lib/Shield.d.ts +0 -12
- package/lib/SideBarNav.d.ts +0 -21
- package/lib/Skeleton.d.ts +0 -15
- package/lib/SkipLink.d.ts +0 -22
- package/lib/Slider.d.ts +0 -14
- package/lib/Status.d.ts +0 -10
- package/lib/Tabs.d.ts +0 -23
- package/lib/Toggle.d.ts +0 -11
- package/lib/Tooltip.d.ts +0 -14
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { Meta, StoryObj, StoryFn } from '@storybook/react';
|
|
2
|
+
import { expect, fn, userEvent, within } from 'storybook/test';
|
|
3
|
+
import React, { Component, ReactNode, useState } from 'react';
|
|
4
|
+
import { Tooltip, TooltipContent } from './Tooltip';
|
|
5
|
+
|
|
6
|
+
// reusable helper function to test that tooltip is and is not present as appropriate
|
|
7
|
+
async function defaultPlay(canvasElement: HTMLElement) {
|
|
8
|
+
const canvas = within(canvasElement);
|
|
9
|
+
|
|
10
|
+
// Find the Paragraph inside the Tooltip component
|
|
11
|
+
// NOTE: Keeping the explicit timeouts as per the original code
|
|
12
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
13
|
+
const paragraph = canvas.getByRole('status'); // Assuming 'status' is the correct role
|
|
14
|
+
|
|
15
|
+
// confirm text 'I am a tooltip' is not visible
|
|
16
|
+
expect(canvas.queryByText('I am a tooltip!')).toBeNull();
|
|
17
|
+
|
|
18
|
+
// Check initial paragraph text
|
|
19
|
+
// await new Promise((resolve) => setTimeout(resolve, 250));
|
|
20
|
+
expect(paragraph).toHaveTextContent("I am a paragraph");
|
|
21
|
+
|
|
22
|
+
// Hover over the paragraph
|
|
23
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
24
|
+
await userEvent.hover(paragraph);
|
|
25
|
+
|
|
26
|
+
expect(canvas.queryByText('I am a tooltip!')).not.toBeNull();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default {
|
|
30
|
+
title: 'Components/Tooltip',
|
|
31
|
+
component: Tooltip,
|
|
32
|
+
parameters: {
|
|
33
|
+
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
|
|
34
|
+
layout: 'centered',
|
|
35
|
+
},
|
|
36
|
+
argTypes: {
|
|
37
|
+
className: { control: 'text' },
|
|
38
|
+
thumbClassName: { control: 'text' },
|
|
39
|
+
defaultChecked: { control: 'boolean' },
|
|
40
|
+
disabled: { control: 'boolean' },
|
|
41
|
+
},
|
|
42
|
+
} as Meta<typeof Tooltip>;
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
export const Default: StoryFn = () => {
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<div className="grid mx-auto w-1/2 p-2 border-2 rounded-sm">
|
|
49
|
+
<Tooltip>
|
|
50
|
+
<p role="status">I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.
|
|
51
|
+
I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.</p>
|
|
52
|
+
<p>I'm another paragraph!</p>
|
|
53
|
+
<TooltipContent>I am a tooltip! <p>I'm a paragraph inside the tooltip!</p></TooltipContent>
|
|
54
|
+
</Tooltip>
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
Default.play = async ({ canvasElement }) => {
|
|
60
|
+
const canvas = within(canvasElement);
|
|
61
|
+
|
|
62
|
+
// Find the Paragraph inside the Tooltip component
|
|
63
|
+
// NOTE: Keeping the explicit timeouts as per the original code
|
|
64
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
65
|
+
const paragraph = canvas.getByRole('status'); // Assuming 'status' is the correct role
|
|
66
|
+
|
|
67
|
+
// confirm text 'I am a tooltip' is not visible
|
|
68
|
+
expect(canvas.queryByText('I am a tooltip!')).toBeNull();
|
|
69
|
+
|
|
70
|
+
// Check initial paragraph text
|
|
71
|
+
// await new Promise((resolve) => setTimeout(resolve, 250));
|
|
72
|
+
expect(paragraph).toHaveTextContent("I am a paragraph");
|
|
73
|
+
|
|
74
|
+
// Hover over the paragraph
|
|
75
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
76
|
+
await userEvent.hover(paragraph);
|
|
77
|
+
|
|
78
|
+
expect(canvas.queryByText('I am a tooltip!')).not.toBeNull();
|
|
79
|
+
|
|
80
|
+
// Move mouse out ...
|
|
81
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
82
|
+
await userEvent.unhover(paragraph);
|
|
83
|
+
expect(canvas.queryByText('I am a tooltip!')).toBeNull();
|
|
84
|
+
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
export const South: StoryFn = () => {
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<div className="grid mx-auto w-1/2 p-2 border-2 rounded-sm">
|
|
92
|
+
<Tooltip>
|
|
93
|
+
<p role="status">I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.
|
|
94
|
+
I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.</p>
|
|
95
|
+
<TooltipContent
|
|
96
|
+
position='s'
|
|
97
|
+
className='bg-blue-200 border-2 border-blue-500 text-blue-700'
|
|
98
|
+
>I am a tooltip!</TooltipContent>
|
|
99
|
+
</Tooltip>
|
|
100
|
+
</div>
|
|
101
|
+
);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
South.play = async ({ canvasElement }) => {
|
|
105
|
+
defaultPlay(canvasElement);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export const North: StoryFn = () => {
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<div className="grid mx-auto w-1/2 p-2 border-2 rounded-sm">
|
|
112
|
+
<Tooltip>
|
|
113
|
+
<p role="status">I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.
|
|
114
|
+
I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.</p>
|
|
115
|
+
<TooltipContent position='n'>I am a tooltip!</TooltipContent>
|
|
116
|
+
</Tooltip>
|
|
117
|
+
</div>
|
|
118
|
+
);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
North.play = async ({ canvasElement }) => {
|
|
122
|
+
defaultPlay(canvasElement);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
export const NorthWest: StoryFn = () => {
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<div className="grid mx-auto w-1/2 p-2 border-2 rounded-sm">
|
|
131
|
+
<Tooltip>
|
|
132
|
+
<p role="status">I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.
|
|
133
|
+
I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.</p>
|
|
134
|
+
<TooltipContent position='nw'>I am a tooltip!</TooltipContent>
|
|
135
|
+
</Tooltip>
|
|
136
|
+
</div>
|
|
137
|
+
);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
NorthWest.play = async ({ canvasElement }) => {
|
|
141
|
+
defaultPlay(canvasElement);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export const NorthEast: StoryFn = () => {
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<div className="grid mx-auto w-1/2 p-2 border-2 rounded-sm">
|
|
148
|
+
<Tooltip>
|
|
149
|
+
<p role="status">I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.
|
|
150
|
+
I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.</p>
|
|
151
|
+
<TooltipContent position='ne'>I am a tooltip!</TooltipContent>
|
|
152
|
+
</Tooltip>
|
|
153
|
+
</div>
|
|
154
|
+
);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
NorthEast.play = async ({ canvasElement }) => {
|
|
158
|
+
defaultPlay(canvasElement);
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
export const SouthEast: StoryFn = () => {
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<div className="grid mx-auto w-1/2 p-2 border-2 rounded-sm">
|
|
165
|
+
<Tooltip>
|
|
166
|
+
<p role="status">I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.
|
|
167
|
+
I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.</p>
|
|
168
|
+
<TooltipContent position='se'>I am a tooltip!</TooltipContent>
|
|
169
|
+
</Tooltip>
|
|
170
|
+
</div>
|
|
171
|
+
);
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
SouthEast.play = async ({ canvasElement }) => {
|
|
175
|
+
defaultPlay(canvasElement);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
export const West: StoryFn = () => {
|
|
179
|
+
|
|
180
|
+
return (
|
|
181
|
+
<div className="grid mx-auto w-1/2 p-2 border-2 rounded-sm">
|
|
182
|
+
<Tooltip>
|
|
183
|
+
<p role="status">I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.
|
|
184
|
+
I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.</p>
|
|
185
|
+
<TooltipContent position='w'>I am a tooltip!</TooltipContent>
|
|
186
|
+
</Tooltip>
|
|
187
|
+
</div>
|
|
188
|
+
);
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
West.play = async ({ canvasElement }) => {
|
|
192
|
+
defaultPlay(canvasElement);
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export const East: StoryFn = () => {
|
|
196
|
+
|
|
197
|
+
return (
|
|
198
|
+
<div className="grid mx-auto w-1/2 p-2 border-2 rounded-sm">
|
|
199
|
+
<Tooltip>
|
|
200
|
+
<p role="status">I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.
|
|
201
|
+
I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.</p>
|
|
202
|
+
<TooltipContent position='e'>I am a tooltip!</TooltipContent>
|
|
203
|
+
</Tooltip>
|
|
204
|
+
</div>
|
|
205
|
+
);
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
East.play = async ({ canvasElement }) => {
|
|
209
|
+
defaultPlay(canvasElement);
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
export const Center: StoryFn = () => {
|
|
213
|
+
|
|
214
|
+
return (
|
|
215
|
+
<div className="grid mx-auto w-1/2 p-2 border-2 rounded-sm">
|
|
216
|
+
<Tooltip>
|
|
217
|
+
<p role="status">I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.
|
|
218
|
+
I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.</p>
|
|
219
|
+
<TooltipContent position='c'>I am a tooltip!</TooltipContent>
|
|
220
|
+
</Tooltip>
|
|
221
|
+
</div>
|
|
222
|
+
);
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
Center.play = async ({ canvasElement }) => {
|
|
226
|
+
defaultPlay(canvasElement);
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
export const Content: StoryFn = () => {
|
|
231
|
+
|
|
232
|
+
return (
|
|
233
|
+
<div className="grid mx-auto w-1/2 p-2 border-2 rounded-sm">
|
|
234
|
+
<Tooltip>
|
|
235
|
+
<p role="status">I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.
|
|
236
|
+
I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.
|
|
237
|
+
</p>
|
|
238
|
+
I'm not a part of an element.
|
|
239
|
+
<TooltipContent>I am a tooltip! <p>I'm a paragraph inside the tooltip!</p></TooltipContent>
|
|
240
|
+
</Tooltip>
|
|
241
|
+
</div>
|
|
242
|
+
);
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
export const MultiContentElements: StoryFn = () => {
|
|
247
|
+
|
|
248
|
+
return (
|
|
249
|
+
<div className="grid mx-auto w-1/2 p-2 border-2 rounded-sm">
|
|
250
|
+
<Tooltip>
|
|
251
|
+
<>
|
|
252
|
+
<p role="status">I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.
|
|
253
|
+
I am a paragraph. I am a paragraph. I am a paragraph. I am a paragraph.
|
|
254
|
+
</p>
|
|
255
|
+
<p>I'm a 2nd paragraph inside the tooltip</p>
|
|
256
|
+
</>
|
|
257
|
+
<TooltipContent>I am a tooltip! <p>I'm a paragraph inside the tooltip!</p></TooltipContent>
|
|
258
|
+
</Tooltip>
|
|
259
|
+
</div>
|
|
260
|
+
);
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
export const TooltipContentError: StoryFn = () => {
|
|
265
|
+
|
|
266
|
+
return (
|
|
267
|
+
<ErrorBoundary>
|
|
268
|
+
<div className="grid mx-auto w-1/2 p-2 border-2 rounded-sm">
|
|
269
|
+
<TooltipContent>I am a tooltip! <p>I'm a paragraph inside the tooltip!</p></TooltipContent>
|
|
270
|
+
</div>
|
|
271
|
+
</ErrorBoundary>
|
|
272
|
+
);
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
// Error Boundary definition for Error Checking
|
|
281
|
+
|
|
282
|
+
interface ErrorBoundaryProps {
|
|
283
|
+
children: ReactNode;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
interface ErrorBoundaryState {
|
|
287
|
+
hasError: boolean;
|
|
288
|
+
error: Error | null;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
293
|
+
constructor(props: ErrorBoundaryProps) {
|
|
294
|
+
super(props);
|
|
295
|
+
this.state = { hasError: false, error: null };
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
static getDerivedStateFromError(error: Error) {
|
|
299
|
+
// Update state so the next render shows the fallback UI.
|
|
300
|
+
return { hasError: true, error };
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
componentDidCatch(error: Error, errorInfo: any) {
|
|
304
|
+
// You can log the error to an error reporting service here.
|
|
305
|
+
console.error("Error caught in ErrorBoundary:", error, errorInfo);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
render() {
|
|
309
|
+
if (this.state.hasError) {
|
|
310
|
+
return <div>Error: {this.state.error?.message}</div>;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return this.props.children;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
2
|
+
import { vi } from 'vitest';
|
|
3
|
+
// import '@testing-library/jest-dom';
|
|
4
|
+
import { axe } from "vitest-axe";
|
|
5
|
+
import { Tooltip, TooltipContent, TooltipProps, TooltipContentProps } from './Tooltip';
|
|
6
|
+
import { cp } from 'fs';
|
|
7
|
+
import { createRef } from 'react';
|
|
8
|
+
|
|
9
|
+
// getByText is synchronous
|
|
10
|
+
// findByText is asynchronous
|
|
11
|
+
|
|
12
|
+
describe('Tooltip Component', () => {
|
|
13
|
+
|
|
14
|
+
const renderComponent = (props: Partial<TooltipProps | TooltipContentProps> = {}) =>
|
|
15
|
+
render(
|
|
16
|
+
<Tooltip>
|
|
17
|
+
<button>Hover me</button>
|
|
18
|
+
<TooltipContent>Tooltip text</TooltipContent>
|
|
19
|
+
</Tooltip>
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
// PASSING
|
|
23
|
+
it('should render the trigger element', () => {
|
|
24
|
+
renderComponent();
|
|
25
|
+
|
|
26
|
+
expect(screen.getByText('Hover me')).toBeInTheDocument();
|
|
27
|
+
expect(screen.queryByText('Tooltip text')).not.toBeInTheDocument();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// PASSING
|
|
31
|
+
it('should have no accessibility violations when tooltip is not visible', async () => {
|
|
32
|
+
const { container } = renderComponent()
|
|
33
|
+
|
|
34
|
+
expect(screen.getByText('Hover me')).toBeInTheDocument();
|
|
35
|
+
expect(screen.queryByText('Tooltip text')).not.toBeInTheDocument();
|
|
36
|
+
|
|
37
|
+
const accessibilityResults = await axe(container);
|
|
38
|
+
expect(accessibilityResults).toHaveNoViolations();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// PASSING - USES A RE-RENDER TO FIND COMPONENT AND TEST
|
|
42
|
+
it('should show tooltip content on hover', async () => {
|
|
43
|
+
|
|
44
|
+
renderComponent();
|
|
45
|
+
const triggerButton = screen.getByText('Hover me');
|
|
46
|
+
const tooltipContainer = triggerButton.parentElement as HTMLElement;
|
|
47
|
+
|
|
48
|
+
fireEvent.mouseEnter(tooltipContainer);
|
|
49
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
50
|
+
expect(screen.getByText('Tooltip text')).toBeInTheDocument();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// PASSING
|
|
54
|
+
it('should show tooltip content after specified delay', async () => {
|
|
55
|
+
render(
|
|
56
|
+
<Tooltip delay={250}>
|
|
57
|
+
<button>Hover me</button>
|
|
58
|
+
<TooltipContent>Tooltip text</TooltipContent>
|
|
59
|
+
</Tooltip>
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const triggerButton = screen.getByText('Hover me');
|
|
63
|
+
const tooltipContainer = triggerButton.parentElement as HTMLElement;
|
|
64
|
+
|
|
65
|
+
fireEvent.mouseEnter(tooltipContainer);
|
|
66
|
+
|
|
67
|
+
const toolTipEl = await screen.findByText('Tooltip text', {}, {timeout: 300});
|
|
68
|
+
expect(toolTipEl).toBeInTheDocument();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// PASSING
|
|
72
|
+
it('should hide tooltip content on mouse leave', async () => {
|
|
73
|
+
renderComponent();
|
|
74
|
+
|
|
75
|
+
const tooltipContainer = screen.getByText('Hover me').parentElement as HTMLElement;
|
|
76
|
+
|
|
77
|
+
// Show tooltip
|
|
78
|
+
fireEvent.mouseEnter(tooltipContainer);
|
|
79
|
+
|
|
80
|
+
const toolTipEl = await screen.findByText('Tooltip text', {}, {timeout: 300});
|
|
81
|
+
expect(toolTipEl).toBeInTheDocument();
|
|
82
|
+
|
|
83
|
+
// Hide tooltip
|
|
84
|
+
fireEvent.mouseLeave(tooltipContainer);
|
|
85
|
+
|
|
86
|
+
expect(toolTipEl).not.toBeInTheDocument();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// PASSING
|
|
90
|
+
it('should show tooltip on focus and hide on blur for keyboard accessibility', async () => {
|
|
91
|
+
renderComponent();
|
|
92
|
+
|
|
93
|
+
const tooltipContainer = screen.getByText('Hover me').parentElement as HTMLElement;
|
|
94
|
+
|
|
95
|
+
// Show tooltip on focus
|
|
96
|
+
fireEvent.focus(tooltipContainer);
|
|
97
|
+
|
|
98
|
+
const toolTipEl = await screen.findByText('Tooltip text', {}, {timeout: 300});
|
|
99
|
+
expect(toolTipEl).toBeInTheDocument();
|
|
100
|
+
|
|
101
|
+
// Hide tooltip on blur
|
|
102
|
+
fireEvent.blur(tooltipContainer);
|
|
103
|
+
|
|
104
|
+
expect(screen.queryByText('Tooltip text')).not.toBeInTheDocument();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// PASSING
|
|
108
|
+
it('should apply custom className to Tooltip wrapper', () => {
|
|
109
|
+
render(
|
|
110
|
+
<Tooltip className="custom-tooltip-class">
|
|
111
|
+
<button>Hover me</button>
|
|
112
|
+
<TooltipContent>Tooltip text</TooltipContent>
|
|
113
|
+
</Tooltip>
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const tooltipContainer = screen.getByText('Hover me').parentElement as HTMLElement;
|
|
117
|
+
expect(tooltipContainer).toHaveClass('custom-tooltip-class');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('renders a tooltip with invalid children', () => {
|
|
121
|
+
expect(() => render(
|
|
122
|
+
<>
|
|
123
|
+
<TooltipContent/>
|
|
124
|
+
<Tooltip children={false} className="custom-tooltip-class"/>
|
|
125
|
+
</>
|
|
126
|
+
)).toThrowError();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// PASSING
|
|
130
|
+
it('should pass accessibility audit when open', async () => {
|
|
131
|
+
const { container } = renderComponent()
|
|
132
|
+
|
|
133
|
+
const triggerButton = screen.getByText('Hover me');
|
|
134
|
+
const tooltipContainer = triggerButton.parentElement as HTMLElement;
|
|
135
|
+
|
|
136
|
+
fireEvent.focus(triggerButton);
|
|
137
|
+
fireEvent.mouseEnter(tooltipContainer);
|
|
138
|
+
|
|
139
|
+
const toolTipEl = await screen.findByText('Tooltip text', {}, {timeout: 300});
|
|
140
|
+
expect(toolTipEl).toBeInTheDocument();
|
|
141
|
+
|
|
142
|
+
expect(screen.getByText('Tooltip text')).toBeInTheDocument();
|
|
143
|
+
|
|
144
|
+
const results = await axe(container);
|
|
145
|
+
expect(results).toHaveNoViolations();
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
it('should handle multiple children correctly', async () => {
|
|
150
|
+
render(
|
|
151
|
+
<Tooltip>
|
|
152
|
+
<div>
|
|
153
|
+
<button>Hover me</button>
|
|
154
|
+
<span>Extra content</span>
|
|
155
|
+
</div>
|
|
156
|
+
<TooltipContent>Tooltip text</TooltipContent>
|
|
157
|
+
</Tooltip>
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
expect(screen.getByText('Hover me')).toBeInTheDocument();
|
|
161
|
+
expect(screen.getByText('Extra content')).toBeInTheDocument();
|
|
162
|
+
expect(screen.queryByText('Tooltip text')).not.toBeInTheDocument();
|
|
163
|
+
|
|
164
|
+
fireEvent.mouseEnter(screen.getByText('Hover me').closest('div')?.parentElement as HTMLElement);
|
|
165
|
+
|
|
166
|
+
const toolTipEl = await screen.findByText('Tooltip text', {}, {timeout: 300});
|
|
167
|
+
expect(toolTipEl).toBeInTheDocument();
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
/*
|
|
173
|
+
const toolTipEl = await screen.findByText('Tooltip text', {}, {timeout: 300});
|
|
174
|
+
expect(toolTipEl).toBeInTheDocument();
|
|
175
|
+
|
|
176
|
+
expect(screen.getByText('Tooltip text')).toBeInTheDocument();
|
|
177
|
+
|
|
178
|
+
const results = await axe(container);
|
|
179
|
+
expect(results).toHaveNoViolations();
|
|
180
|
+
*/
|
|
181
|
+
|
|
182
|
+
describe('TooltipContent Component', () => {
|
|
183
|
+
|
|
184
|
+
it('should apply position classes based on position prop', async () => {
|
|
185
|
+
const { rerender } = render(<Tooltip><p>Hover me</p><TooltipContent position="n">North tooltip</TooltipContent></Tooltip>);
|
|
186
|
+
|
|
187
|
+
// Test Northern position
|
|
188
|
+
const triggerButton = screen.getByText('Hover me');
|
|
189
|
+
const tooltipContainer = triggerButton.parentElement as HTMLElement;
|
|
190
|
+
|
|
191
|
+
fireEvent.focus(triggerButton);
|
|
192
|
+
fireEvent.mouseEnter(tooltipContainer);
|
|
193
|
+
|
|
194
|
+
let toolTipEl = await screen.findByText('North tooltip', {}, {timeout: 300});
|
|
195
|
+
expect(screen.getByText('North tooltip')).toHaveClass('left-1/2');
|
|
196
|
+
expect(screen.getByText('North tooltip')).toHaveClass('-translate-y-full');
|
|
197
|
+
|
|
198
|
+
// Test Southern position
|
|
199
|
+
rerender(<Tooltip><p>Hover me</p><TooltipContent position="s">South tooltip</TooltipContent></Tooltip>);
|
|
200
|
+
|
|
201
|
+
fireEvent.focus(triggerButton);
|
|
202
|
+
fireEvent.mouseEnter(tooltipContainer);
|
|
203
|
+
|
|
204
|
+
toolTipEl = await screen.findByText('South tooltip', {}, {timeout: 300});
|
|
205
|
+
expect(screen.getByText('South tooltip')).toHaveClass('top-full');
|
|
206
|
+
expect(screen.getByText('South tooltip')).toHaveClass('-translate-x-1/2');
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
// Test East position
|
|
210
|
+
rerender(<Tooltip><p>Hover me</p><TooltipContent position="e">East tooltip</TooltipContent></Tooltip>);
|
|
211
|
+
|
|
212
|
+
fireEvent.focus(triggerButton);
|
|
213
|
+
fireEvent.mouseEnter(tooltipContainer);
|
|
214
|
+
|
|
215
|
+
toolTipEl = await screen.findByText('East tooltip', {}, {timeout: 300});
|
|
216
|
+
expect(screen.getByText('East tooltip')).toHaveClass('-right-2');
|
|
217
|
+
expect(screen.getByText('East tooltip')).toHaveClass('translate-x-full');
|
|
218
|
+
|
|
219
|
+
// Test West position
|
|
220
|
+
rerender(<Tooltip><p>Hover me</p><TooltipContent position="w">West tooltip</TooltipContent></Tooltip>);
|
|
221
|
+
|
|
222
|
+
fireEvent.focus(triggerButton);
|
|
223
|
+
fireEvent.mouseEnter(tooltipContainer);
|
|
224
|
+
|
|
225
|
+
toolTipEl = await screen.findByText('West tooltip', {}, {timeout: 300});
|
|
226
|
+
expect(screen.getByText('West tooltip')).toHaveClass('-translate-x-full');
|
|
227
|
+
expect(screen.getByText('West tooltip')).toHaveClass('-left-2');
|
|
228
|
+
|
|
229
|
+
// Test NW Position
|
|
230
|
+
rerender(<Tooltip><p>Hover me</p><TooltipContent position="nw">NW tooltip</TooltipContent></Tooltip>);
|
|
231
|
+
|
|
232
|
+
fireEvent.focus(triggerButton);
|
|
233
|
+
fireEvent.mouseEnter(tooltipContainer);
|
|
234
|
+
|
|
235
|
+
toolTipEl = await screen.findByText('NW tooltip', {}, {timeout: 300});
|
|
236
|
+
expect(screen.getByText('NW tooltip')).toHaveClass('left-0');
|
|
237
|
+
expect(screen.getByText('NW tooltip')).toHaveClass('-translate-y-full');
|
|
238
|
+
|
|
239
|
+
// Test SE Position
|
|
240
|
+
rerender(<Tooltip><p>Hover me</p><TooltipContent position="se">SE tooltip</TooltipContent></Tooltip>);
|
|
241
|
+
|
|
242
|
+
fireEvent.focus(triggerButton);
|
|
243
|
+
fireEvent.mouseEnter(tooltipContainer);
|
|
244
|
+
|
|
245
|
+
toolTipEl = await screen.findByText('SE tooltip', {}, {timeout: 300});
|
|
246
|
+
expect(screen.getByText('SE tooltip')).toHaveClass('right-0');
|
|
247
|
+
expect(screen.getByText('SE tooltip')).toHaveClass('top-full');
|
|
248
|
+
|
|
249
|
+
// Test NE Position
|
|
250
|
+
rerender(<Tooltip><p>Hover me</p><TooltipContent position="ne">NE tooltip</TooltipContent></Tooltip>);
|
|
251
|
+
|
|
252
|
+
fireEvent.focus(triggerButton);
|
|
253
|
+
fireEvent.mouseEnter(tooltipContainer);
|
|
254
|
+
|
|
255
|
+
toolTipEl = await screen.findByText('NE tooltip', {}, {timeout: 300});
|
|
256
|
+
expect(screen.getByText('NE tooltip')).toHaveClass('right-0');
|
|
257
|
+
expect(screen.getByText('NE tooltip')).toHaveClass('-translate-y-full');
|
|
258
|
+
|
|
259
|
+
// Test Center Position
|
|
260
|
+
rerender(<Tooltip><p>Hover me</p><TooltipContent position="c">Center tooltip</TooltipContent></Tooltip>);
|
|
261
|
+
|
|
262
|
+
fireEvent.focus(triggerButton);
|
|
263
|
+
fireEvent.mouseEnter(tooltipContainer);
|
|
264
|
+
|
|
265
|
+
toolTipEl = await screen.findByText('Center tooltip', {}, {timeout: 300});
|
|
266
|
+
expect(screen.getByText('Center tooltip')).toHaveClass('left-1/2');
|
|
267
|
+
expect(screen.getByText('Center tooltip')).toHaveClass('top-1/2');
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('should apply custom className to TooltipContent', async () => {
|
|
271
|
+
render(
|
|
272
|
+
<Tooltip><p>Hover me</p><TooltipContent className="custom-content-class">Tooltip content</TooltipContent></Tooltip>
|
|
273
|
+
);
|
|
274
|
+
fireEvent.mouseEnter(screen.getByText('Hover me').closest('p')?.parentElement as HTMLElement);
|
|
275
|
+
const toolTipEl = await screen.findByText('Tooltip content', {}, {timeout: 300});
|
|
276
|
+
expect(toolTipEl).toHaveClass('custom-content-class');
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
// PASSING
|
|
280
|
+
it('should have proper ARIA attributes for accessibility', async () => {
|
|
281
|
+
render(<Tooltip><p>Hover me</p><TooltipContent>Accessible tooltip</TooltipContent></Tooltip>);
|
|
282
|
+
|
|
283
|
+
// hover over paragraph
|
|
284
|
+
fireEvent.mouseEnter(screen.getByText('Hover me').closest('p')?.parentElement as HTMLElement);
|
|
285
|
+
|
|
286
|
+
const tooltip = await screen.findByRole('tooltip');
|
|
287
|
+
expect(tooltip).toBeInTheDocument();
|
|
288
|
+
expect(tooltip).toHaveTextContent('Accessible tooltip');
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it('should pass accessibility audit', async () => {
|
|
292
|
+
const { container } = render(
|
|
293
|
+
<Tooltip><p>Hover me</p><TooltipContent>Tooltip content</TooltipContent></Tooltip>
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
const triggerButton = screen.getByText('Hover me');
|
|
297
|
+
const tooltipContainer = triggerButton.parentElement as HTMLElement;
|
|
298
|
+
|
|
299
|
+
const p = await screen.findByText('Hover me', {}, {timeout: 300});
|
|
300
|
+
expect(p).toBeInTheDocument();
|
|
301
|
+
|
|
302
|
+
const results = await axe(container);
|
|
303
|
+
expect(results).toHaveNoViolations();
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
});
|
|
307
|
+
|