@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,454 @@
|
|
|
1
|
+
import { Meta, StoryContext } from '@storybook/react';
|
|
2
|
+
import { Modal, AccessibleModalProps } from './Modal';
|
|
3
|
+
import { Button } from './Button';
|
|
4
|
+
import { userEvent, within } from 'storybook/test';
|
|
5
|
+
import { expect } from 'storybook/test';
|
|
6
|
+
import { FC, useRef, useState } from 'react';
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
title: 'Components/Modal',
|
|
11
|
+
component: Modal,
|
|
12
|
+
parameters: {
|
|
13
|
+
layout: 'centered',
|
|
14
|
+
backgrounds: {
|
|
15
|
+
default: 'white',
|
|
16
|
+
values: [
|
|
17
|
+
{ name: 'white', value: '#ffffff' },
|
|
18
|
+
{ name: 'light', value: '#f0f0f0' },
|
|
19
|
+
],
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
argTypes: {
|
|
23
|
+
isOpen: { control: 'boolean' },
|
|
24
|
+
title: { control: 'text' },
|
|
25
|
+
},
|
|
26
|
+
args: {
|
|
27
|
+
isOpen: true,
|
|
28
|
+
onClose: () => {console.log('modal closed');},
|
|
29
|
+
title: 'Storybook Modal',
|
|
30
|
+
},
|
|
31
|
+
} as Meta<typeof Modal>;
|
|
32
|
+
|
|
33
|
+
/*
|
|
34
|
+
interface AccessibleModalProps {
|
|
35
|
+
isOpen: boolean; // Controls modal visibility
|
|
36
|
+
onClose: () => void; // Close handler
|
|
37
|
+
title: string; // Modal title for screen readers
|
|
38
|
+
children: React.ReactNode; // Modal content
|
|
39
|
+
}
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
// Define a story using an alternate method that contains state values
|
|
43
|
+
export const DefaultModal = () => {
|
|
44
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div className="w-full h-full p-8 border-2 border-blue-500">
|
|
48
|
+
<p>A modal dialog is a UI component that temporarily interrupts the user’s workflow to display critical
|
|
49
|
+
information or request input. Its primary benefits include:
|
|
50
|
+
</p>
|
|
51
|
+
|
|
52
|
+
<ul className="list-disc ms-5 mt-4">
|
|
53
|
+
<li>Focus: By dimming the background, it ensures the user focuses solely on the content or action presented.</li>
|
|
54
|
+
<li>Context Preservation: Users can interact with the dialog without leaving the current page, keeping their workflow intact.</li>
|
|
55
|
+
<li>Efficiency: It’s ideal for quick tasks like confirmations, alerts, or forms, minimizing navigation.</li>
|
|
56
|
+
<li>User Guidance: Helps guide users through essential decisions or processes without distractions.</li>
|
|
57
|
+
<li>Overall, modals improve usability by keeping tasks concise and contextually relevant.</li>
|
|
58
|
+
</ul>
|
|
59
|
+
|
|
60
|
+
<Button onClick={() => setIsOpen(true)} className="mt-8" variant='default'>Open Modal</Button>
|
|
61
|
+
|
|
62
|
+
<Modal isOpen={isOpen} onClose={() => setIsOpen(false)} title="Test Modal">
|
|
63
|
+
<p>This is a Modal dialog that can be used for many varying purposes, from informational messages
|
|
64
|
+
to taking user input, ideal for required quick tasks on a page.
|
|
65
|
+
</p>
|
|
66
|
+
</Modal>
|
|
67
|
+
</div>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Define a story using an alternate method that contains state values
|
|
72
|
+
export const DefaultClickOutside = () => {
|
|
73
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<div className="w-full h-full p-8 border-2 border-blue-500">
|
|
77
|
+
<p>A modal dialog is a UI component that temporarily interrupts the user’s workflow to display critical
|
|
78
|
+
information or request input. Its primary benefits include:
|
|
79
|
+
</p>
|
|
80
|
+
|
|
81
|
+
<ul className="list-disc ms-5 mt-4">
|
|
82
|
+
<li>Focus: By dimming the background, it ensures the user focuses solely on the content or action presented.</li>
|
|
83
|
+
<li>Context Preservation: Users can interact with the dialog without leaving the current page, keeping their workflow intact.</li>
|
|
84
|
+
<li>Efficiency: It’s ideal for quick tasks like confirmations, alerts, or forms, minimizing navigation.</li>
|
|
85
|
+
<li>User Guidance: Helps guide users through essential decisions or processes without distractions.</li>
|
|
86
|
+
<li>Overall, modals improve usability by keeping tasks concise and contextually relevant.</li>
|
|
87
|
+
</ul>
|
|
88
|
+
|
|
89
|
+
<Button onClick={() => setIsOpen(true)} className="mt-8" variant='default'>Open Modal</Button>
|
|
90
|
+
|
|
91
|
+
<Modal isOpen={isOpen} onClose={() => setIsOpen(false)} title="Test Modal" clickOutsideCloses>
|
|
92
|
+
<p>This is a Modal dialog that can be used for many varying purposes, from informational messages
|
|
93
|
+
to taking user input, ideal for required quick tasks on a page.
|
|
94
|
+
</p>
|
|
95
|
+
</Modal>
|
|
96
|
+
</div>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
// Play function for the DefaultClickOutside story
|
|
100
|
+
DefaultClickOutside.play = async ({ canvasElement }: StoryContext) => {
|
|
101
|
+
const canvas = within(canvasElement);
|
|
102
|
+
|
|
103
|
+
// Step 1: Open the modal by clicking the "Open Modal" button
|
|
104
|
+
const openButton = await canvas.getByRole('button', { name: 'Open Modal' });
|
|
105
|
+
await userEvent.click(openButton);
|
|
106
|
+
|
|
107
|
+
// Step 2: Assert that the modal dialog is now visible
|
|
108
|
+
const modal = await canvas.getByRole('dialog');
|
|
109
|
+
expect(modal).toBeInTheDocument();
|
|
110
|
+
|
|
111
|
+
// Step 3: Retrieve the modal backdrop and click on it
|
|
112
|
+
const backdrop = canvasElement.ownerDocument.getElementById('backdrop');
|
|
113
|
+
if (!backdrop) {
|
|
114
|
+
throw new Error('Backdrop element not found');
|
|
115
|
+
}
|
|
116
|
+
await userEvent.click(backdrop);
|
|
117
|
+
|
|
118
|
+
// Step 4: Assert that the modal is no longer visible
|
|
119
|
+
await expect(canvas.queryByRole('dialog', { name: 'Test Modal' })).not.toBeInTheDocument();
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
// Define a story using an alternate method that contains state values
|
|
124
|
+
export const CancelCloseButtonText = () => {
|
|
125
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
126
|
+
|
|
127
|
+
return (
|
|
128
|
+
<div className="w-full h-full p-8 border-2 border-blue-500">
|
|
129
|
+
<p>A modal dialog is a UI component that temporarily interrupts the user’s workflow to display critical
|
|
130
|
+
information or request input. Its primary benefits include:
|
|
131
|
+
</p>
|
|
132
|
+
|
|
133
|
+
<ul className="list-disc ms-5 mt-4">
|
|
134
|
+
<li>Focus: By dimming the background, it ensures the user focuses solely on the content or action presented.</li>
|
|
135
|
+
<li>Context Preservation: Users can interact with the dialog without leaving the current page, keeping their workflow intact.</li>
|
|
136
|
+
<li>Efficiency: It’s ideal for quick tasks like confirmations, alerts, or forms, minimizing navigation.</li>
|
|
137
|
+
<li>User Guidance: Helps guide users through essential decisions or processes without distractions.</li>
|
|
138
|
+
<li>Overall, modals improve usability by keeping tasks concise and contextually relevant.</li>
|
|
139
|
+
</ul>
|
|
140
|
+
|
|
141
|
+
<Button onClick={() => setIsOpen(true)} className="mt-8" variant='default'>Open Modal</Button>
|
|
142
|
+
|
|
143
|
+
<Modal isOpen={isOpen} onClose={() => setIsOpen(false)} title="Test Modal" closeButtonText='Cancel'>
|
|
144
|
+
<p>This is a Modal dialog that can be used for many varying purposes, from informational messages
|
|
145
|
+
to taking user input, ideal for required quick tasks on a page.
|
|
146
|
+
</p>
|
|
147
|
+
</Modal>
|
|
148
|
+
</div>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Define a story using an alternate method that contains state values
|
|
153
|
+
export const WithContinueButton = () => {
|
|
154
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
155
|
+
const [continueClicked, setContinueClicked] = useState(false);
|
|
156
|
+
|
|
157
|
+
return (
|
|
158
|
+
<div className="w-full h-full p-8 border-2 border-blue-500">
|
|
159
|
+
<p>A modal dialog is a UI component that temporarily interrupts the user’s workflow to display critical
|
|
160
|
+
information or request input. Its primary benefits include:
|
|
161
|
+
</p>
|
|
162
|
+
|
|
163
|
+
<ul className="list-disc ms-5 mt-4">
|
|
164
|
+
<li>Focus: By dimming the background, it ensures the user focuses solely on the content or action presented.</li>
|
|
165
|
+
<li>Context Preservation: Users can interact with the dialog without leaving the current page, keeping their workflow intact.</li>
|
|
166
|
+
<li>Efficiency: It’s ideal for quick tasks like confirmations, alerts, or forms, minimizing navigation.</li>
|
|
167
|
+
<li>User Guidance: Helps guide users through essential decisions or processes without distractions.</li>
|
|
168
|
+
<li>Overall, modals improve usability by keeping tasks concise and contextually relevant.</li>
|
|
169
|
+
</ul>
|
|
170
|
+
|
|
171
|
+
<Button onClick={() => setIsOpen(true)} className="mt-8" variant='default'>Open Modal</Button>
|
|
172
|
+
|
|
173
|
+
<Modal isOpen={isOpen} onClose={() => setIsOpen(false)} title="Test Modal" variant='default'
|
|
174
|
+
continueButton continueButtonHandler={() => setContinueClicked(!continueClicked)}
|
|
175
|
+
clickOutsideCloses
|
|
176
|
+
continueButtonText='Display Continue'
|
|
177
|
+
>
|
|
178
|
+
<p>This is a Modal dialog that can be used for many varying purposes, from informational messages
|
|
179
|
+
to taking user input, ideal for required quick tasks on a page.
|
|
180
|
+
</p>
|
|
181
|
+
</Modal>
|
|
182
|
+
{ continueClicked && <div className='mt-10 font-lg bg-gray-200 rounded-md border p-6 border-black text-center'>
|
|
183
|
+
Continue button has been clicked
|
|
184
|
+
</div>
|
|
185
|
+
}
|
|
186
|
+
</div>
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
// Define a story using an alternate method that contains state values
|
|
192
|
+
export const VariantDarker = () => {
|
|
193
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
194
|
+
const [continueClicked, setContinueClicked] = useState(false);
|
|
195
|
+
|
|
196
|
+
return (
|
|
197
|
+
<div className="w-full h-full p-8 border-2 border-blue-500">
|
|
198
|
+
<p>A modal dialog is a UI component that temporarily interrupts the user’s workflow to display critical
|
|
199
|
+
information or request input. Its primary benefits include:
|
|
200
|
+
</p>
|
|
201
|
+
|
|
202
|
+
<ul className="list-disc ms-5 mt-4">
|
|
203
|
+
<li>Focus: By dimming the background, it ensures the user focuses solely on the content or action presented.</li>
|
|
204
|
+
<li>Context Preservation: Users can interact with the dialog without leaving the current page, keeping their workflow intact.</li>
|
|
205
|
+
<li>Efficiency: It’s ideal for quick tasks like confirmations, alerts, or forms, minimizing navigation.</li>
|
|
206
|
+
<li>User Guidance: Helps guide users through essential decisions or processes without distractions.</li>
|
|
207
|
+
<li>Overall, modals improve usability by keeping tasks concise and contextually relevant.</li>
|
|
208
|
+
</ul>
|
|
209
|
+
|
|
210
|
+
<Button onClick={() => setIsOpen(true)} className="mt-8" variant='default'>Open Modal</Button>
|
|
211
|
+
|
|
212
|
+
<Modal isOpen={isOpen} onClose={() => setIsOpen(false)} title="Test Modal" variant='darker'
|
|
213
|
+
continueButton continueButtonHandler={() => setContinueClicked(!continueClicked)}
|
|
214
|
+
clickOutsideCloses
|
|
215
|
+
continueButtonText='Display Continue'
|
|
216
|
+
>
|
|
217
|
+
<p>This is a Modal dialog that can be used for many varying purposes, from informational messages
|
|
218
|
+
to taking user input, ideal for required quick tasks on a page.
|
|
219
|
+
</p>
|
|
220
|
+
</Modal>
|
|
221
|
+
{ continueClicked && <div className='mt-10 font-lg bg-gray-200 rounded-md border p-6 border-black text-center'>
|
|
222
|
+
Continue button has been clicked
|
|
223
|
+
</div>
|
|
224
|
+
}
|
|
225
|
+
</div>
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Define a story using an alternate method that contains state values
|
|
230
|
+
export const VariantDark = () => {
|
|
231
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
232
|
+
const [continueClicked, setContinueClicked] = useState(false);
|
|
233
|
+
|
|
234
|
+
return (
|
|
235
|
+
<div className="w-full h-full p-8 border-2 border-blue-500">
|
|
236
|
+
<p>A modal dialog is a UI component that temporarily interrupts the user’s workflow to display critical
|
|
237
|
+
information or request input. Its primary benefits include:
|
|
238
|
+
</p>
|
|
239
|
+
|
|
240
|
+
<ul className="list-disc ms-5 mt-4">
|
|
241
|
+
<li>Focus: By dimming the background, it ensures the user focuses solely on the content or action presented.</li>
|
|
242
|
+
<li>Context Preservation: Users can interact with the dialog without leaving the current page, keeping their workflow intact.</li>
|
|
243
|
+
<li>Efficiency: It’s ideal for quick tasks like confirmations, alerts, or forms, minimizing navigation.</li>
|
|
244
|
+
<li>User Guidance: Helps guide users through essential decisions or processes without distractions.</li>
|
|
245
|
+
<li>Overall, modals improve usability by keeping tasks concise and contextually relevant.</li>
|
|
246
|
+
</ul>
|
|
247
|
+
|
|
248
|
+
<Button onClick={() => setIsOpen(true)} className="mt-8" variant='default'>Open Modal</Button>
|
|
249
|
+
|
|
250
|
+
<Modal isOpen={isOpen} onClose={() => setIsOpen(false)} title="Test Modal" variant='dark'
|
|
251
|
+
continueButton continueButtonHandler={() => setContinueClicked(!continueClicked)}
|
|
252
|
+
clickOutsideCloses
|
|
253
|
+
continueButtonText='Display Continue'
|
|
254
|
+
>
|
|
255
|
+
<p>This is a Modal dialog that can be used for many varying purposes, from informational messages
|
|
256
|
+
to taking user input, ideal for required quick tasks on a page.
|
|
257
|
+
</p>
|
|
258
|
+
</Modal>
|
|
259
|
+
{ continueClicked && <div className='mt-10 font-lg bg-gray-200 rounded-md border p-6 border-black text-center'>
|
|
260
|
+
Continue button has been clicked
|
|
261
|
+
</div>
|
|
262
|
+
}
|
|
263
|
+
</div>
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
// Define a story using an alternate method that contains state values
|
|
270
|
+
export const VariantMedcard = () => {
|
|
271
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
272
|
+
const [continueClicked, setContinueClicked] = useState(false);
|
|
273
|
+
|
|
274
|
+
return (
|
|
275
|
+
<div className="w-full h-full p-8 border-2 border-blue-500">
|
|
276
|
+
<p>A modal dialog is a UI component that temporarily interrupts the user’s workflow to display critical
|
|
277
|
+
information or request input. Its primary benefits include:
|
|
278
|
+
</p>
|
|
279
|
+
|
|
280
|
+
<ul className="list-disc ms-5 mt-4">
|
|
281
|
+
<li>Focus: By dimming the background, it ensures the user focuses solely on the content or action presented.</li>
|
|
282
|
+
<li>Context Preservation: Users can interact with the dialog without leaving the current page, keeping their workflow intact.</li>
|
|
283
|
+
<li>Efficiency: It’s ideal for quick tasks like confirmations, alerts, or forms, minimizing navigation.</li>
|
|
284
|
+
<li>User Guidance: Helps guide users through essential decisions or processes without distractions.</li>
|
|
285
|
+
<li>Overall, modals improve usability by keeping tasks concise and contextually relevant.</li>
|
|
286
|
+
</ul>
|
|
287
|
+
|
|
288
|
+
<Button onClick={() => setIsOpen(true)} className="mt-8" variant='default'>Open Modal</Button>
|
|
289
|
+
|
|
290
|
+
<Modal isOpen={isOpen} onClose={() => setIsOpen(false)} title="Test Modal" variant='default'
|
|
291
|
+
continueButton continueButtonHandler={() => setContinueClicked(!continueClicked)}
|
|
292
|
+
clickOutsideCloses
|
|
293
|
+
continueButtonText='Display Continue'
|
|
294
|
+
>
|
|
295
|
+
<p>This is a Modal dialog that can be used for many varying purposes, from informational messages
|
|
296
|
+
to taking user input, ideal for required quick tasks on a page.
|
|
297
|
+
</p>
|
|
298
|
+
</Modal>
|
|
299
|
+
{ continueClicked && <div className='mt-10 font-lg bg-gray-200 rounded-md border p-6 border-black text-center'>
|
|
300
|
+
Continue button has been clicked
|
|
301
|
+
</div>
|
|
302
|
+
}
|
|
303
|
+
</div>
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
export const TrapFocus = () => {
|
|
309
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
310
|
+
|
|
311
|
+
return (
|
|
312
|
+
<div className="p-8">
|
|
313
|
+
<Button onClick={() => setIsOpen(true)}>Open Modal</Button>
|
|
314
|
+
<Modal isOpen={isOpen} onClose={() => setIsOpen(false)} title="Focus Trap Modal">
|
|
315
|
+
<p>Press Tab and Shift+Tab to test focus trapping.</p>
|
|
316
|
+
</Modal>
|
|
317
|
+
</div>
|
|
318
|
+
);
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
// Play function for testing focus trapping
|
|
322
|
+
TrapFocus.play = async ({ canvasElement }: StoryContext) => {
|
|
323
|
+
const canvas = within(canvasElement);
|
|
324
|
+
|
|
325
|
+
// Open the modal
|
|
326
|
+
const openButton = canvas.getByRole('button', { name: 'Open Modal' });
|
|
327
|
+
await userEvent.click(openButton);
|
|
328
|
+
|
|
329
|
+
// Assert that the modal is open
|
|
330
|
+
const modal = await canvas.getByRole('dialog');
|
|
331
|
+
expect(modal).toBeInTheDocument();
|
|
332
|
+
|
|
333
|
+
// Get focusable elements
|
|
334
|
+
const closeX = canvas.getByLabelText('Close modal');
|
|
335
|
+
const closeButton = canvas.getByText('Close');
|
|
336
|
+
|
|
337
|
+
await userEvent.tab();
|
|
338
|
+
expect(closeX).toHaveFocus();
|
|
339
|
+
|
|
340
|
+
// Simulate Tab key press (focus should move forward)
|
|
341
|
+
await userEvent.tab();
|
|
342
|
+
expect(closeButton).toHaveFocus();
|
|
343
|
+
|
|
344
|
+
await userEvent.tab();
|
|
345
|
+
expect(closeX).toHaveFocus();
|
|
346
|
+
|
|
347
|
+
await userEvent.tab();
|
|
348
|
+
expect(closeButton).toHaveFocus();
|
|
349
|
+
|
|
350
|
+
await userEvent.tab();
|
|
351
|
+
expect(closeX).toHaveFocus();
|
|
352
|
+
|
|
353
|
+
// Simulate Shift + Tab key press (focus should move backward)
|
|
354
|
+
await userEvent.keyboard("{Shift>}{Tab}{/Shift}");
|
|
355
|
+
expect(closeButton).toHaveFocus();
|
|
356
|
+
|
|
357
|
+
await userEvent.keyboard("{Shift>}{Tab}{/Shift}");
|
|
358
|
+
expect(closeX).toHaveFocus();
|
|
359
|
+
|
|
360
|
+
await userEvent.keyboard("{Shift>}{Tab}{/Shift}");
|
|
361
|
+
expect(closeButton).toHaveFocus();
|
|
362
|
+
|
|
363
|
+
await userEvent.keyboard("{Shift>}{Tab}{/Shift}");
|
|
364
|
+
expect(closeX).toHaveFocus();
|
|
365
|
+
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
export const ContinueButtonHandler = () => {
|
|
370
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
371
|
+
const [text, setText] = useState("initial text value");
|
|
372
|
+
|
|
373
|
+
return (
|
|
374
|
+
<div className="p-8">
|
|
375
|
+
<p aria-label="paragraph text">{text}</p>
|
|
376
|
+
<Button
|
|
377
|
+
onClick={() => setIsOpen(true)}
|
|
378
|
+
>Open Modal</Button>
|
|
379
|
+
<Modal
|
|
380
|
+
isOpen={isOpen}
|
|
381
|
+
onClose={() => setIsOpen(false)}
|
|
382
|
+
continueButton
|
|
383
|
+
continueButtonHandler={() => setText("text after continue button pressed")}
|
|
384
|
+
title="Focus Trap Modal">
|
|
385
|
+
<p>Press Tab and Shift+Tab to test focus trapping.</p>
|
|
386
|
+
</Modal>
|
|
387
|
+
</div>
|
|
388
|
+
);
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
// Play function for testing focus trapping
|
|
392
|
+
ContinueButtonHandler.play = async ({ canvasElement }: StoryContext) => {
|
|
393
|
+
const canvas = within(canvasElement);
|
|
394
|
+
|
|
395
|
+
// Open the modal
|
|
396
|
+
const openButton = canvas.getByRole('button', { name: 'Open Modal' });
|
|
397
|
+
await userEvent.click(openButton);
|
|
398
|
+
|
|
399
|
+
// Retrieve paragraph
|
|
400
|
+
const paragraph = canvas.getByLabelText('paragraph text');
|
|
401
|
+
expect(paragraph).toHaveTextContent('initial text value')
|
|
402
|
+
|
|
403
|
+
// Assert that the modal is open
|
|
404
|
+
const modal = await canvas.getByRole('dialog');
|
|
405
|
+
expect(modal).toBeInTheDocument();
|
|
406
|
+
|
|
407
|
+
// Click Continue button
|
|
408
|
+
const continueButton = canvas.getByText("Continue");
|
|
409
|
+
await userEvent.click(continueButton);
|
|
410
|
+
|
|
411
|
+
// Test that Continue button handler changed paragraph text
|
|
412
|
+
expect(paragraph).toHaveTextContent('text after continue button pressed')
|
|
413
|
+
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
export const EscapeKeyCloses = () => {
|
|
419
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
420
|
+
|
|
421
|
+
return (
|
|
422
|
+
<div className="p-8">
|
|
423
|
+
<Button
|
|
424
|
+
onClick={() => setIsOpen(true)}
|
|
425
|
+
>Open Modal</Button>
|
|
426
|
+
<Modal
|
|
427
|
+
isOpen={isOpen}
|
|
428
|
+
onClose={() => setIsOpen(false)}
|
|
429
|
+
title="Escape Key Closes">
|
|
430
|
+
<p>Press Escape to test closing the modal via an Escape key press.</p>
|
|
431
|
+
</Modal>
|
|
432
|
+
</div>
|
|
433
|
+
);
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
// Play function for testing focus trapping
|
|
437
|
+
EscapeKeyCloses.play = async ({ canvasElement }: StoryContext) => {
|
|
438
|
+
const canvas = within(canvasElement);
|
|
439
|
+
|
|
440
|
+
// Open the modal
|
|
441
|
+
const openButton = canvas.getByRole('button', { name: 'Open Modal' });
|
|
442
|
+
await userEvent.click(openButton);
|
|
443
|
+
|
|
444
|
+
// Assert that the modal is open
|
|
445
|
+
const modal = await canvas.getByRole('dialog');
|
|
446
|
+
expect(modal).toBeInTheDocument();
|
|
447
|
+
|
|
448
|
+
// Press escape key
|
|
449
|
+
await userEvent.keyboard('{Escape}');
|
|
450
|
+
|
|
451
|
+
// Ensure Dialog is no long present
|
|
452
|
+
await expect(canvas.queryByRole('dialog')).not.toBeInTheDocument();
|
|
453
|
+
|
|
454
|
+
};
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { render, screen, fireEvent } from "@testing-library/react";
|
|
2
|
+
import { userEvent } from "@testing-library/user-event";
|
|
3
|
+
import { axe } from "vitest-axe";
|
|
4
|
+
import { describe, it, expect, vi } from "vitest";
|
|
5
|
+
import { Modal } from "./Modal";
|
|
6
|
+
|
|
7
|
+
describe("Modal Component", () => {
|
|
8
|
+
const handleClose = vi.fn();
|
|
9
|
+
|
|
10
|
+
it("renders when open", () => {
|
|
11
|
+
render(
|
|
12
|
+
<Modal isOpen={true} onClose={handleClose} title="Test Modal">
|
|
13
|
+
<p>Modal Content</p>
|
|
14
|
+
</Modal>
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
expect(screen.getByRole("dialog")).toBeInTheDocument();
|
|
18
|
+
expect(screen.getByText("Modal Content")).toBeInTheDocument();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("does not render when closed", () => {
|
|
22
|
+
render(
|
|
23
|
+
<Modal isOpen={false} onClose={handleClose} title="Test Modal">
|
|
24
|
+
<p>Modal Content</p>
|
|
25
|
+
</Modal>
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
it("utilizes Continue button and hanlder", () => {
|
|
33
|
+
const handleContinue = vi.fn();
|
|
34
|
+
render(
|
|
35
|
+
<Modal isOpen={true} onClose={handleClose} title="Test Modal" continueButton continueButtonHandler={handleContinue}>
|
|
36
|
+
<p>Modal Content</p>
|
|
37
|
+
</Modal>
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
// capture and click on Continue button
|
|
41
|
+
const continueButton = screen.getByText('Continue');
|
|
42
|
+
fireEvent.click(continueButton);
|
|
43
|
+
|
|
44
|
+
// verify Continue button handler was executed
|
|
45
|
+
expect(handleClose).toHaveBeenCalledTimes(1);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
it("renders modal with a medium blur level and no close button, closes on Close button click", () => {
|
|
50
|
+
const handleClose = vi.fn();
|
|
51
|
+
render(
|
|
52
|
+
<Modal closeButton={false} blurLevel="md" isOpen={true} onClose={handleClose} title="Test Modal">
|
|
53
|
+
<p>Modal Content</p>
|
|
54
|
+
</Modal>
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const closeButton = screen.getByLabelText("Close modal");
|
|
58
|
+
fireEvent.click(closeButton);
|
|
59
|
+
|
|
60
|
+
expect(handleClose).toHaveBeenCalledTimes(1);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("click outside closes the modal", () => {
|
|
64
|
+
const handleClose = vi.fn();
|
|
65
|
+
render(
|
|
66
|
+
<Modal isOpen={true} onClose={handleClose} title="Test Modal" clickOutsideCloses>
|
|
67
|
+
<p>Modal Content</p>
|
|
68
|
+
</Modal>
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
// Simulate clicking outside the modal
|
|
72
|
+
fireEvent.mouseDown(document.body);
|
|
73
|
+
|
|
74
|
+
// Check if the onClose function was called
|
|
75
|
+
expect(handleClose).toHaveBeenCalledTimes(1);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("closes on Escape key press", () => {
|
|
79
|
+
const handleClose = vi.fn();
|
|
80
|
+
render(
|
|
81
|
+
<Modal isOpen={true} onClose={handleClose} title="Test Modal">
|
|
82
|
+
<p>Modal Content</p>
|
|
83
|
+
</Modal>
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
fireEvent.keyDown(document, { key: "Escape", code: "Escape" });
|
|
87
|
+
expect(handleClose).toHaveBeenCalledTimes(1);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe("Modal Accessibility Tests", () => {
|
|
92
|
+
const handleClose = vi.fn();
|
|
93
|
+
|
|
94
|
+
it("should have no accessibility violations", async () => {
|
|
95
|
+
const { container } = render(
|
|
96
|
+
<Modal isOpen={true} onClose={handleClose} title="Accessible Modal">
|
|
97
|
+
<p>Modal Content</p>
|
|
98
|
+
</Modal>
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const results = await axe(container);
|
|
102
|
+
expect(results).toHaveNoViolations();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("has a valid ARIA role and label", () => {
|
|
106
|
+
render(
|
|
107
|
+
<Modal isOpen={true} onClose={handleClose} title="Accessible Modal">
|
|
108
|
+
<p>Modal Content</p>
|
|
109
|
+
</Modal>
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
const dialog = screen.getByRole("dialog");
|
|
113
|
+
|
|
114
|
+
expect(dialog).toBeInTheDocument();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("allows tabbing through interactive elements within the modal, closes via enter key press", async () => {
|
|
118
|
+
const handleClose = vi.fn();
|
|
119
|
+
render(
|
|
120
|
+
<Modal isOpen={true} onClose={handleClose} title="Test Modal">
|
|
121
|
+
<p>I am a Modal dialog! Behold my GREATNESS!</p>
|
|
122
|
+
</Modal>
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const user = userEvent.setup();
|
|
126
|
+
|
|
127
|
+
// Get buttons inside the modal
|
|
128
|
+
const xButton = screen.getByLabelText("Close modal");
|
|
129
|
+
const closeButton = screen.getByText("Close");
|
|
130
|
+
|
|
131
|
+
// Initial focus should be on the first button
|
|
132
|
+
xButton.focus();
|
|
133
|
+
expect(document.activeElement).toBe(xButton);
|
|
134
|
+
|
|
135
|
+
// Press Tab to move to the second button
|
|
136
|
+
await user.tab();
|
|
137
|
+
expect(document.activeElement).toBe(closeButton);
|
|
138
|
+
|
|
139
|
+
// Press Tab to move to the second button
|
|
140
|
+
await user.tab();
|
|
141
|
+
expect(document.activeElement).toBe(xButton);
|
|
142
|
+
|
|
143
|
+
// Press Tab to move to the second button
|
|
144
|
+
await user.tab();
|
|
145
|
+
expect(document.activeElement).toBe(closeButton);
|
|
146
|
+
|
|
147
|
+
// Press Tab to move to the second button
|
|
148
|
+
await user.tab();
|
|
149
|
+
expect(document.activeElement).toBe(xButton);
|
|
150
|
+
|
|
151
|
+
// Press Tab to move to the second button
|
|
152
|
+
await user.tab();
|
|
153
|
+
expect(document.activeElement).toBe(closeButton);
|
|
154
|
+
|
|
155
|
+
// Simulate pressing Enter
|
|
156
|
+
await user.keyboard("{Enter}");
|
|
157
|
+
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it("allows tabbing in reverse w/ shift key through interactive elements within the modal, closes via enter key press", async () => {
|
|
161
|
+
const handleClose = vi.fn();
|
|
162
|
+
render(
|
|
163
|
+
<Modal isOpen={true} onClose={handleClose} title="Test Modal">
|
|
164
|
+
<p>I am a Modal dialog! Behold my GREATNESS!</p>
|
|
165
|
+
</Modal>
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
const user = userEvent.setup();
|
|
169
|
+
|
|
170
|
+
// Get buttons inside the modal
|
|
171
|
+
const xButton = screen.getByLabelText("Close modal");
|
|
172
|
+
const closeButton = screen.getByText("Close");
|
|
173
|
+
|
|
174
|
+
// Initial focus should be on the first button
|
|
175
|
+
xButton.focus();
|
|
176
|
+
expect(document.activeElement).toBe(xButton);
|
|
177
|
+
|
|
178
|
+
// Press Tab to move to the second button
|
|
179
|
+
await user.tab();
|
|
180
|
+
expect(document.activeElement).toBe(closeButton);
|
|
181
|
+
|
|
182
|
+
// Press Tab to move to the second button
|
|
183
|
+
await user.keyboard("{Shift>}{Tab}{/Shift}");
|
|
184
|
+
expect(document.activeElement).toBe(xButton);
|
|
185
|
+
|
|
186
|
+
// Press Tab to move to the second button
|
|
187
|
+
await user.keyboard("{Shift>}{Tab}{/Shift}");
|
|
188
|
+
expect(document.activeElement).toBe(closeButton);
|
|
189
|
+
|
|
190
|
+
// Press Tab to move to the second button
|
|
191
|
+
await user.keyboard("{Shift>}{Tab}{/Shift}");
|
|
192
|
+
expect(document.activeElement).toBe(xButton);
|
|
193
|
+
|
|
194
|
+
// Press Tab to move to the second button
|
|
195
|
+
await user.keyboard("{Shift>}{Tab}{/Shift}");
|
|
196
|
+
expect(document.activeElement).toBe(closeButton);
|
|
197
|
+
|
|
198
|
+
// Simulate pressing Enter
|
|
199
|
+
await user.keyboard("{Enter}");
|
|
200
|
+
|
|
201
|
+
});
|
|
202
|
+
});
|