@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,157 @@
|
|
|
1
|
+
import { Meta } from '@storybook/react';
|
|
2
|
+
import { List, ListProps, ListItem } from './List';
|
|
3
|
+
import { FC } from 'react';
|
|
4
|
+
import { ArrowDown, ArrowDownLeft, ArrowDownRight, ArrowUp, ArrowUpRight, ArrowUpLeft } from 'lucide-react';
|
|
5
|
+
|
|
6
|
+
// Meta object - defines basic storybook options for this story
|
|
7
|
+
export default {
|
|
8
|
+
title: 'Components/List',
|
|
9
|
+
component: List,
|
|
10
|
+
argTypes: {
|
|
11
|
+
},
|
|
12
|
+
parameters: {
|
|
13
|
+
layout: 'centered', // options are 'centered', 'fullscreen', and 'padded' (default value)
|
|
14
|
+
backgrounds: { default: 'light' }, // options are light, medium, or dark
|
|
15
|
+
},
|
|
16
|
+
} as Meta<ListProps>;
|
|
17
|
+
|
|
18
|
+
// Define "Default" story
|
|
19
|
+
export const Default = {
|
|
20
|
+
args: {
|
|
21
|
+
size: 'default',
|
|
22
|
+
items:[{
|
|
23
|
+
children: 'asdf',
|
|
24
|
+
}, {
|
|
25
|
+
children: 'asdf2'
|
|
26
|
+
}, {
|
|
27
|
+
children: 'asdf3'
|
|
28
|
+
}, {
|
|
29
|
+
children: 'asdf4'
|
|
30
|
+
}, {
|
|
31
|
+
children: 'asdf5'
|
|
32
|
+
}]
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const IconList = {
|
|
37
|
+
args: {
|
|
38
|
+
size: 'default',
|
|
39
|
+
items: [{
|
|
40
|
+
children:
|
|
41
|
+
<>
|
|
42
|
+
<p className='inline'>1</p>
|
|
43
|
+
<ArrowUp className='inline pb-1'/>
|
|
44
|
+
</>
|
|
45
|
+
}, {
|
|
46
|
+
children:
|
|
47
|
+
<>
|
|
48
|
+
<p className='inline'>2</p>
|
|
49
|
+
<ArrowUpRight className='inline pb-1'/>
|
|
50
|
+
</>
|
|
51
|
+
}, {
|
|
52
|
+
children:
|
|
53
|
+
<>
|
|
54
|
+
<p className='inline'>3</p>
|
|
55
|
+
<ArrowDownRight className='inline pb-1'/>
|
|
56
|
+
</>
|
|
57
|
+
}, {
|
|
58
|
+
children:
|
|
59
|
+
<>
|
|
60
|
+
<p className='inline'>4</p>
|
|
61
|
+
<ArrowDown className='inline pb-1'/>
|
|
62
|
+
</>
|
|
63
|
+
}, {
|
|
64
|
+
children:
|
|
65
|
+
<>
|
|
66
|
+
<p className='inline'>5</p>
|
|
67
|
+
<ArrowDownLeft className='inline pb-1'/>
|
|
68
|
+
</>
|
|
69
|
+
}, {
|
|
70
|
+
children:
|
|
71
|
+
<>
|
|
72
|
+
<p className='inline'>6</p>
|
|
73
|
+
<ArrowUpLeft className='inline pb-1'/>
|
|
74
|
+
</>
|
|
75
|
+
}, {
|
|
76
|
+
children:
|
|
77
|
+
<>
|
|
78
|
+
<img src='src/assets/img/hospital.jpg' alt='hospital' className='max-h-[2em] max-w-[2em] pr-1 inline pb-1'></img>
|
|
79
|
+
<p className='inline'>big image --resized</p>
|
|
80
|
+
</>
|
|
81
|
+
}
|
|
82
|
+
, {
|
|
83
|
+
children:
|
|
84
|
+
<>
|
|
85
|
+
<img src='src/assets/img/first-aid-kit.svg' alt='first aid kit' className='max-h-[2em] max-w-[2em] pr-1 inline pb-2'></img>
|
|
86
|
+
<p className='inline'>icon</p>
|
|
87
|
+
</>
|
|
88
|
+
}]
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
//Controls won't work on this story because the ListItems are built at runtime
|
|
93
|
+
// the list items are specified directly in the story below instead of in the component file via an array, similar to first 2 stories
|
|
94
|
+
export const FullComponentArray: FC = () => {
|
|
95
|
+
const listItems = [
|
|
96
|
+
{
|
|
97
|
+
children:
|
|
98
|
+
<>
|
|
99
|
+
<img src='src/assets/img/first-aid-kit.svg' alt='first aid kit' className='max-h-[2em] max-w-[2em] pr-1 pb-2 inline'></img>
|
|
100
|
+
<p className='inline'>icon</p>
|
|
101
|
+
</>
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
children:
|
|
105
|
+
<>
|
|
106
|
+
<img src='src/assets/img/heartbeat.svg' alt='heartbeat' className='max-h-[2em] max-w-[2em] pr-1 pb-1 inline'></img>
|
|
107
|
+
<p className='inline'>icon</p>
|
|
108
|
+
</>
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
children:
|
|
112
|
+
<>
|
|
113
|
+
<img src='src/assets/img/pill.svg' alt='pill' className='max-h-[2em] max-w-[2em] pr-1 pb-2 inline'></img>
|
|
114
|
+
<p className='inline'>icon</p>
|
|
115
|
+
</>
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
children:
|
|
119
|
+
<>
|
|
120
|
+
<img src='src/assets/img/prescription.svg' alt='prescription' className='max-h-[2em] max-w-[2em] pr-1 pb-2 inline'></img>
|
|
121
|
+
<p className='inline'>icon</p>
|
|
122
|
+
</>
|
|
123
|
+
},
|
|
124
|
+
]
|
|
125
|
+
return (
|
|
126
|
+
<div>
|
|
127
|
+
<p>This is an example header (user implemented)</p>
|
|
128
|
+
<List items={listItems} isDecimal={true} withDividers={true}>
|
|
129
|
+
</List>
|
|
130
|
+
</div>
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
//Controls won't work on this story because the ListItems are built at runtime
|
|
135
|
+
// the list items are specified directly in the story below instead of in the component file via an array, similar to first 2 stories
|
|
136
|
+
export const FullComponentChildren: FC = () => {
|
|
137
|
+
return (
|
|
138
|
+
<List isDecimal={true} withDividers={true} classNameDividerColor='red-400'>
|
|
139
|
+
<ListItem>
|
|
140
|
+
<img src='src/assets/img/first-aid-kit.svg' alt='first aid kit' className='max-h-[2em] max-w-[2em] pr-1 inline'></img>
|
|
141
|
+
<p className='inline'>icon</p>
|
|
142
|
+
</ListItem>
|
|
143
|
+
<ListItem>
|
|
144
|
+
<img src='src/assets/img/first-aid-kit.svg' alt='first aid kit' className='max-h-[2em] max-w-[2em] pr-1 inline'></img>
|
|
145
|
+
<p className='inline'>icon</p>
|
|
146
|
+
</ListItem>
|
|
147
|
+
<ListItem>
|
|
148
|
+
<img src='src/assets/img/first-aid-kit.svg' alt='first aid kit' className='max-h-[2em] max-w-[2em] pr-1 inline'></img>
|
|
149
|
+
<p className='inline'>icon</p>
|
|
150
|
+
</ListItem>
|
|
151
|
+
<ListItem>
|
|
152
|
+
<img src='src/assets/img/first-aid-kit.svg' alt='first aid kit' className='max-h-[2em] max-w-[2em] pr-1 inline'></img>
|
|
153
|
+
<p className='inline'>icon</p>
|
|
154
|
+
</ListItem>
|
|
155
|
+
</List>
|
|
156
|
+
)
|
|
157
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { axe } from "vitest-axe";
|
|
4
|
+
import { describe, it, expect, vi } from "vitest"; // required for ".toHaveNoViolations"
|
|
5
|
+
import { List, ListItem, ListItemProps } from './List';
|
|
6
|
+
|
|
7
|
+
describe('List Component', () => {
|
|
8
|
+
// it('renders an empty list without crashing', () => {
|
|
9
|
+
// render(<List />);
|
|
10
|
+
// const list = screen.getByRole('list');
|
|
11
|
+
// expect(list).toBeInTheDocument();
|
|
12
|
+
// expect(list.children).toHaveLength(0);
|
|
13
|
+
// });
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
// describe('isRomanNumeral prop', () => {
|
|
17
|
+
it('renders roman numeral labels for list items when isRomanNumeral is true', () => {
|
|
18
|
+
const items = [
|
|
19
|
+
{ children: 'Item One' },
|
|
20
|
+
{ children: 'Item Two' },
|
|
21
|
+
{ children: 'Item Three' },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
render(<List items={items} isRomanNumeral />);
|
|
25
|
+
|
|
26
|
+
// For the items mapping, the roman numeral is generated by:
|
|
27
|
+
// String.fromCharCode(8560 + index) followed by a dot and a space.
|
|
28
|
+
// For index 0, it should be "ⅰ. ", for index 1 "ⅱ. ", etc.
|
|
29
|
+
expect(screen.getByText('ⅰ.')).toBeInTheDocument();
|
|
30
|
+
expect(screen.getByText('ⅱ.')).toBeInTheDocument();
|
|
31
|
+
expect(screen.getByText('ⅲ.')).toBeInTheDocument();
|
|
32
|
+
});
|
|
33
|
+
// });
|
|
34
|
+
|
|
35
|
+
it("covers the React.Children.map(...) roman-numeral branch", () => {
|
|
36
|
+
render(
|
|
37
|
+
<List isRomanNumeral>
|
|
38
|
+
<ListItem>Alpha</ListItem>
|
|
39
|
+
<ListItem>Bravo</ListItem>
|
|
40
|
+
</List>
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
// now the children-mapping branch fires
|
|
44
|
+
expect(screen.getByText("ⅰ.")).toBeInTheDocument(); // for <span className='w-6'>
|
|
45
|
+
expect(screen.getByText("Alpha")).toBeInTheDocument(); // still renders the child
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// describe('isAlphabetical prop', () => {
|
|
49
|
+
it('renders alphabetical labels for list items when isAlphabetical is true', () => {
|
|
50
|
+
const items = [
|
|
51
|
+
{ children: 'First Item' },
|
|
52
|
+
{ children: 'Second Item' },
|
|
53
|
+
{ children: 'Third Item' },
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
render(<List isInline withDividers classNameItem='border-b' classNameDividerColor='red-500' items={items} isAlphabetical />);
|
|
57
|
+
|
|
58
|
+
// In the items mapping, the alphabetical label uses uppercase letters:
|
|
59
|
+
// String.fromCharCode(65 + index) followed by a dot and a space.
|
|
60
|
+
expect(screen.getByText('a.')).toBeInTheDocument();
|
|
61
|
+
expect(screen.getByText('b.')).toBeInTheDocument();
|
|
62
|
+
expect(screen.getByText('c.')).toBeInTheDocument();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('renders alphabetical labels for children elements when isAlphabetical is true', () => {
|
|
66
|
+
render(
|
|
67
|
+
<List isInline withDividers classNameItem='border-b' classNameDividerColor='red-500' isAlphabetical>
|
|
68
|
+
<ListItem>First Child</ListItem>
|
|
69
|
+
<ListItem>Second Child</ListItem>
|
|
70
|
+
<ListItem>Third Child</ListItem>
|
|
71
|
+
</List>
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
// In the children mapping, the alphabetical label uses lowercase letters:
|
|
75
|
+
// String.fromCharCode(97 + index) followed by a dot and a space.
|
|
76
|
+
expect(screen.getByText('a.')).toBeInTheDocument();
|
|
77
|
+
expect(screen.getByText('b.')).toBeInTheDocument();
|
|
78
|
+
expect(screen.getByText('c.')).toBeInTheDocument();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('renders list items passed as `items` prop', () => {
|
|
82
|
+
const items = [
|
|
83
|
+
{ children: 'Item 1' },
|
|
84
|
+
{ children: 'Item 2' },
|
|
85
|
+
{ children: 'Item 3' },
|
|
86
|
+
];
|
|
87
|
+
render(<List items={items} />);
|
|
88
|
+
const listItems = screen.getAllByRole('listitem');
|
|
89
|
+
expect(listItems).toHaveLength(items.length);
|
|
90
|
+
expect(listItems[0]).toHaveTextContent('Item 1');
|
|
91
|
+
expect(listItems[1]).toHaveTextContent('Item 2');
|
|
92
|
+
expect(listItems[2]).toHaveTextContent('Item 3');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('renders child nodes passed as children', () => {
|
|
96
|
+
render(
|
|
97
|
+
<List>
|
|
98
|
+
<ListItem>Child 1</ListItem>
|
|
99
|
+
<ListItem>Child 2</ListItem>
|
|
100
|
+
</List>
|
|
101
|
+
);
|
|
102
|
+
const listItems = screen.getAllByRole('listitem');
|
|
103
|
+
expect(listItems).toHaveLength(2);
|
|
104
|
+
expect(listItems[0]).toHaveTextContent('Child 1');
|
|
105
|
+
expect(listItems[1]).toHaveTextContent('Child 2');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('applies custom class names to the list', () => {
|
|
109
|
+
render(<List className="custom-class" />);
|
|
110
|
+
const list = screen.getByRole('list');
|
|
111
|
+
expect(list).toHaveClass('custom-class');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('renders with dividers between items when `withDividers` is true', () => {
|
|
115
|
+
const items = [
|
|
116
|
+
{ children: 'Item 1' },
|
|
117
|
+
{ children: 'Item 2' },
|
|
118
|
+
];
|
|
119
|
+
render(<List items={items} withDividers classNameDividerColor="border-red-500" />);
|
|
120
|
+
const listItems = screen.getAllByRole('listitem');
|
|
121
|
+
expect(listItems[0]).toHaveClass('border-b', 'border-red-500');
|
|
122
|
+
expect(listItems[1]).not.toHaveClass('border-b');
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('uses `list-decimal` class when `isDecimal` is true', () => {
|
|
126
|
+
render(<List isDecimal />);
|
|
127
|
+
const list = screen.getByRole('list');
|
|
128
|
+
expect(list).toHaveClass('list-decimal');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('uses `list-disc` class when `isDisc` is true', () => {
|
|
132
|
+
render(<List isDisc />);
|
|
133
|
+
const list = screen.getByRole('list');
|
|
134
|
+
expect(list).toHaveClass('list-disc');
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// it('renders list items with custom class names from `classNameItem`', () => {
|
|
138
|
+
// const items = [
|
|
139
|
+
// { children: 'Item 1', className: 'custom-item-class' },
|
|
140
|
+
// ];
|
|
141
|
+
// render(<List items={items} />);
|
|
142
|
+
// const listItem = screen.getByText('Item 1');
|
|
143
|
+
// expect(listItem).toHaveClass('custom-item-class');
|
|
144
|
+
// });
|
|
145
|
+
|
|
146
|
+
it('renders non-React element children without modification', () => {
|
|
147
|
+
render(
|
|
148
|
+
<List>
|
|
149
|
+
Text Child
|
|
150
|
+
<ListItem>React Child 1</ListItem>
|
|
151
|
+
<ListItem>React Child 2</ListItem>
|
|
152
|
+
</List>
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
const listItems = screen.getAllByRole('listitem');
|
|
156
|
+
expect(listItems).toHaveLength(2);
|
|
157
|
+
|
|
158
|
+
// Check the first child (non-React element)
|
|
159
|
+
expect(listItems[0]).toHaveTextContent('React Child 1');
|
|
160
|
+
|
|
161
|
+
// Check the second child (React element)
|
|
162
|
+
expect(listItems[1]).toHaveTextContent('React Child 2');
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('does not apply a divider to the last item when withDividers is true', () => {
|
|
168
|
+
render(
|
|
169
|
+
<List withDividers classNameDividerColor="border-red-500">
|
|
170
|
+
<ListItem>Item 1</ListItem>
|
|
171
|
+
<ListItem>Item 2</ListItem>
|
|
172
|
+
</List>
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
const listItems = screen.getAllByRole('listitem');
|
|
176
|
+
expect(listItems).toHaveLength(2);
|
|
177
|
+
|
|
178
|
+
// First item should have a divider
|
|
179
|
+
expect(listItems[0]).toHaveClass('border-b', 'border-red-500');
|
|
180
|
+
|
|
181
|
+
// Last item should NOT have a divider
|
|
182
|
+
expect(listItems[1]).not.toHaveClass('border-b');
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
describe('List Component Accessibility', () => {
|
|
187
|
+
|
|
188
|
+
it('should render list with proper role and structure', () => {
|
|
189
|
+
render(<List items={[{ children: 'Item 1' }, { children: 'Item 2' }]} />);
|
|
190
|
+
const list = screen.getByRole('list');
|
|
191
|
+
const listItems = screen.getAllByRole('listitem');
|
|
192
|
+
|
|
193
|
+
expect(list).toBeInTheDocument();
|
|
194
|
+
expect(listItems).toHaveLength(2);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('should apply proper ARIA attributes for accessibility', () => {
|
|
198
|
+
render(
|
|
199
|
+
<List>
|
|
200
|
+
<ListItem>Accessible Item 1</ListItem>
|
|
201
|
+
<ListItem>Accessible Item 2</ListItem>
|
|
202
|
+
</List>
|
|
203
|
+
);
|
|
204
|
+
const list = screen.getByRole('list');
|
|
205
|
+
const listItems = screen.getAllByRole('listitem');
|
|
206
|
+
|
|
207
|
+
expect(list).toBeInTheDocument();
|
|
208
|
+
expect(listItems).toHaveLength(2);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
});
|
package/src/lib/List.tsx
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import {twMerge } from 'tailwind-merge';
|
|
3
|
+
|
|
4
|
+
export interface ListItemProps {
|
|
5
|
+
className?: string,
|
|
6
|
+
children: React.ReactNode,
|
|
7
|
+
target?: string,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ListProps {
|
|
11
|
+
items?: ListItemProps[],
|
|
12
|
+
header?: string,
|
|
13
|
+
children?: React.ReactNode,
|
|
14
|
+
className?: string,
|
|
15
|
+
withDividers?: boolean,
|
|
16
|
+
classNameDividerColor?: string,
|
|
17
|
+
classNameItem?: string,
|
|
18
|
+
isDecimal?: boolean,
|
|
19
|
+
isDisc?: boolean,
|
|
20
|
+
isAlphabetical?: boolean,
|
|
21
|
+
isRomanNumeral?: boolean,
|
|
22
|
+
isInline?: boolean,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const List = ({
|
|
26
|
+
items,
|
|
27
|
+
header,
|
|
28
|
+
className = '',
|
|
29
|
+
classNameItem = '',
|
|
30
|
+
children,
|
|
31
|
+
withDividers = false,
|
|
32
|
+
classNameDividerColor = '',
|
|
33
|
+
isDecimal = false,
|
|
34
|
+
isDisc = false,
|
|
35
|
+
isAlphabetical = false,
|
|
36
|
+
isRomanNumeral = false,
|
|
37
|
+
isInline = false,
|
|
38
|
+
}: ListProps) => {
|
|
39
|
+
return (
|
|
40
|
+
<div className='p-0 m-0'>
|
|
41
|
+
<p>{header}</p>
|
|
42
|
+
<ul className={twMerge(`pl-6 list-none w-full`, isDecimal ? 'list-decimal' : '', isDisc ? 'list-disc' : '', className)}>
|
|
43
|
+
{items && items.map((item, index) => (
|
|
44
|
+
<ListItem
|
|
45
|
+
key={index}
|
|
46
|
+
className={twMerge(`w-full text-base md:text:lg py-2`, withDividers && (isInline ? index !== items.length : index !== items.length - 1) ? 'border-b' : '',
|
|
47
|
+
classNameDividerColor!== '' && (isInline ? index !== items.length : index !== items.length - 1) ? classNameDividerColor : '',
|
|
48
|
+
isInline && 'inline mr-2', classNameItem )}
|
|
49
|
+
>
|
|
50
|
+
{isRomanNumeral && <span className='flex flex-col w-6'>{String.fromCharCode(8560 + index)}. </span>}
|
|
51
|
+
{isAlphabetical && <span>{String.fromCharCode(97 + index)}. </span>}
|
|
52
|
+
{isRomanNumeral ? <span className='flex flex-col w-6'>{item.children}</span> : item.children}
|
|
53
|
+
</ListItem>
|
|
54
|
+
))}
|
|
55
|
+
{children &&
|
|
56
|
+
React.Children.map(children, (child, index) =>
|
|
57
|
+
React.isValidElement<ListItemProps>(child) ?
|
|
58
|
+
React.cloneElement(child, {
|
|
59
|
+
className: twMerge(
|
|
60
|
+
isInline && 'inline mr-2',
|
|
61
|
+
classNameItem,
|
|
62
|
+
child.props.className,
|
|
63
|
+
`w-full`,
|
|
64
|
+
withDividers && (isInline ? index !== React.Children.count(children) : index !== React.Children.count(children) - 1) ? 'border-b' : '',
|
|
65
|
+
classNameDividerColor!== '' && (isInline ? index !== React.Children.count(children) : index !== React.Children.count(children) - 1) ? classNameDividerColor : '',
|
|
66
|
+
),
|
|
67
|
+
children: (
|
|
68
|
+
<>
|
|
69
|
+
{isRomanNumeral &&
|
|
70
|
+
<div className='flex flex-row'>
|
|
71
|
+
<span className='w-6'>{String.fromCharCode(8560 + index)}. </span>
|
|
72
|
+
{child.props.children}
|
|
73
|
+
</div>
|
|
74
|
+
}
|
|
75
|
+
{isAlphabetical && <span>{String.fromCharCode(97 + index)}. </span>}
|
|
76
|
+
{!isRomanNumeral && child.props.children}
|
|
77
|
+
</>
|
|
78
|
+
)
|
|
79
|
+
})
|
|
80
|
+
: child
|
|
81
|
+
)}
|
|
82
|
+
</ul>
|
|
83
|
+
</div>
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export const ListItem = ({ className, children}: ListItemProps) => {
|
|
88
|
+
return (
|
|
89
|
+
<li className={twMerge('py-2 text-base md:text:lg', className )}>
|
|
90
|
+
{children}
|
|
91
|
+
</li>
|
|
92
|
+
);
|
|
93
|
+
};
|