@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,304 @@
|
|
|
1
|
+
import { ChangeEvent, forwardRef, InputHTMLAttributes, KeyboardEvent, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import SearchIconLg from '../assets/img/search_icon_light.svg';
|
|
3
|
+
import SearchIcon from '../assets/img/search.svg';
|
|
4
|
+
import CloseIcon from '../assets/img/close_icon_dark.svg';
|
|
5
|
+
import { twMerge } from 'tailwind-merge';
|
|
6
|
+
// import { useNavigate } from 'react-router-dom';
|
|
7
|
+
|
|
8
|
+
// TODO: UX Question re no results
|
|
9
|
+
// NOTE: UX (Sam) noted that a results page will be required for some cases. We talked, and we will
|
|
10
|
+
// return an object or set a callback that supplies an object of results as they are presented
|
|
11
|
+
// in the type-ahead results list at the point the user clicks the button
|
|
12
|
+
// NOTE: UX (Sam) indicated that the 'X' clears the search content, does NOT shrink it. That should
|
|
13
|
+
// probably be a state var like 'initial = icon', user then clicks to expand
|
|
14
|
+
|
|
15
|
+
// Searchable Data must conform to an array of this interface
|
|
16
|
+
export interface SearchDataItem {
|
|
17
|
+
path: string;
|
|
18
|
+
title?: string;
|
|
19
|
+
content: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Interface of search results - can use index to obtain path
|
|
23
|
+
export interface DataSearchResults {
|
|
24
|
+
input: string;
|
|
25
|
+
pages: {
|
|
26
|
+
title?: string;
|
|
27
|
+
path?: string;
|
|
28
|
+
results: {
|
|
29
|
+
characters: string;
|
|
30
|
+
index: number;
|
|
31
|
+
}[]
|
|
32
|
+
}[]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface SearchProps
|
|
36
|
+
extends InputHTMLAttributes<HTMLInputElement> {
|
|
37
|
+
className?: string;
|
|
38
|
+
searchableData: SearchDataItem[];
|
|
39
|
+
ariaLabel?: string;
|
|
40
|
+
iconLink?: boolean;
|
|
41
|
+
setSearchResults?: (res: DataSearchResults) => void;
|
|
42
|
+
mobileOnly?: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const Search = forwardRef<HTMLInputElement, SearchProps>(
|
|
46
|
+
(
|
|
47
|
+
{
|
|
48
|
+
className,
|
|
49
|
+
ariaLabel = "Search",
|
|
50
|
+
iconLink = false,
|
|
51
|
+
searchableData,
|
|
52
|
+
setSearchResults,
|
|
53
|
+
mobileOnly = false,
|
|
54
|
+
...props
|
|
55
|
+
},
|
|
56
|
+
ref
|
|
57
|
+
) => {
|
|
58
|
+
const inputRef = useRef<HTMLInputElement | null>(null);
|
|
59
|
+
const resultsRef = useRef<HTMLDivElement>(null); // TODO: necessary?
|
|
60
|
+
const [value, setValue] = useState('');
|
|
61
|
+
const [resultsList, setResultsList] = useState<DataSearchResults>();
|
|
62
|
+
const [iconOnly, setIconOnly] = useState<boolean>(iconLink);
|
|
63
|
+
// const [groupedResults, setGroupedResults] = useState();
|
|
64
|
+
// const [navigatePath, setNavigatePath] = useState<string>();
|
|
65
|
+
// const navigate = useNavigate();
|
|
66
|
+
|
|
67
|
+
// useEffect (() => {
|
|
68
|
+
// if (navigatePath) {
|
|
69
|
+
// navigate(navigatePath);
|
|
70
|
+
// }
|
|
71
|
+
// }, [navigate, navigatePath]);
|
|
72
|
+
|
|
73
|
+
const handleEnter = (e: KeyboardEvent<HTMLInputElement>) => {
|
|
74
|
+
// if returning results list:
|
|
75
|
+
if (e.key === 'Enter') {
|
|
76
|
+
if (setSearchResults) {
|
|
77
|
+
// we are returning results - do that
|
|
78
|
+
handleSearchClick();
|
|
79
|
+
} else {
|
|
80
|
+
// execute first result of real-time list
|
|
81
|
+
if (resultsList && resultsList.pages[0].path) {
|
|
82
|
+
// console.log('resultsList[0]: ' + resultsList.pages[0].path);
|
|
83
|
+
window.location.href=resultsList.pages[0].path;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const selectX = () => {
|
|
90
|
+
setValue(''); // if xClears, onClick clear content
|
|
91
|
+
setResultsList(undefined);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
useEffect (() => {
|
|
95
|
+
setIconOnly(iconLink);
|
|
96
|
+
}, [iconLink]);
|
|
97
|
+
|
|
98
|
+
// Search Function string input
|
|
99
|
+
// returns 15 characters following searched term (add term plus return characters string)
|
|
100
|
+
// as well as array index (from which we can retrieve the path value)
|
|
101
|
+
function searchFilter(searchText: string): DataSearchResults {
|
|
102
|
+
const lower = searchText.toLowerCase();
|
|
103
|
+
const pages: DataSearchResults["pages"] = [];
|
|
104
|
+
|
|
105
|
+
searchableData.forEach((page, pageIndex) => {
|
|
106
|
+
const pageResults: { characters: string; index: number }[] = [];
|
|
107
|
+
let start = page.content.toLowerCase().indexOf(lower);
|
|
108
|
+
|
|
109
|
+
while (start !== -1) {
|
|
110
|
+
const snippet = page.content.substring(
|
|
111
|
+
start + lower.length,
|
|
112
|
+
start + lower.length + 15
|
|
113
|
+
);
|
|
114
|
+
pageResults.push({ characters: snippet, index: pageIndex });
|
|
115
|
+
start = page.content.toLowerCase().indexOf(lower, start + 1);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// only emit a page entry if we found at least one match
|
|
119
|
+
if (pageResults.length) {
|
|
120
|
+
pages.push({
|
|
121
|
+
title: page.title,
|
|
122
|
+
path: page.path,
|
|
123
|
+
results: pageResults,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
return { input: searchText, pages };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Call searchFilter() function w/ input data if appropriate
|
|
132
|
+
const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
133
|
+
const newValue = event.target.value;
|
|
134
|
+
setValue(newValue);
|
|
135
|
+
|
|
136
|
+
if (!newValue) {
|
|
137
|
+
// clear out search results when input is empty
|
|
138
|
+
// setSearchResults?.({ input: "", pages: [] });
|
|
139
|
+
setResultsList(undefined);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const results = searchFilter(newValue);
|
|
144
|
+
// setSearchResults?.(results); // call-back for use in storybook (temp?)
|
|
145
|
+
setResultsList(results); // local results
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
const handleSearchClick = () => {
|
|
150
|
+
const newValue = inputRef.current?.value ?? '';
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
if (setSearchResults) {
|
|
154
|
+
if (newValue.length > 0) {
|
|
155
|
+
const results = searchFilter(newValue);
|
|
156
|
+
setSearchResults?.(results);
|
|
157
|
+
} else {
|
|
158
|
+
setSearchResults({input: '', pages: [{results: []}]});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// mobile - w: 309 h: 48 border: 0.5
|
|
164
|
+
// input h-32px p: 8x8
|
|
165
|
+
// tablet - w: 334 h: 50 border: 0.5
|
|
166
|
+
// input h-34px p: 8x8
|
|
167
|
+
// desk - w: 350 h: 56
|
|
168
|
+
// input h: 56 p: 0
|
|
169
|
+
|
|
170
|
+
const inputClasses = `grow appearance-none h-8 md:h-[32px] lg:h-14 py-2 lg:ps-[19px] rounded-tl rounded-bl
|
|
171
|
+
rounded-br-none rounded-tr-none lg:border border-[#07192d]
|
|
172
|
+
font-['Arial'] bg-white text-[#333234] text-base lg:text-lg
|
|
173
|
+
hover:border-[#5992fa] focus:border-[#5992fa] outline-hidden `;
|
|
174
|
+
|
|
175
|
+
// TODO: Border Color for FOCUS
|
|
176
|
+
return (
|
|
177
|
+
iconOnly ?
|
|
178
|
+
// Display solo search icon button to expand search component
|
|
179
|
+
<span className='w-[52px] h-[50px] p-2 rounded-sm border border-[#6a686b]
|
|
180
|
+
inline-flex flex-col justify-center items-center bg-white'>
|
|
181
|
+
<button className="appearance-none p-0 m-0 border-0 flex items-center justify-center align-middle"
|
|
182
|
+
onClick={() => setIconOnly(false)} >
|
|
183
|
+
<img className='' src={SearchIcon} alt='search icon' />
|
|
184
|
+
</button>
|
|
185
|
+
</span>
|
|
186
|
+
:
|
|
187
|
+
|
|
188
|
+
// Container including input + output list box
|
|
189
|
+
<span className={`h-12 md:h-[50px] lg:h-14 flex items-center relative ${iconOnly && 'hidden'}`}>
|
|
190
|
+
|
|
191
|
+
{/* container for input + icon(s), displays border up to md only */}
|
|
192
|
+
<span className={`
|
|
193
|
+
border-[#6a686b] w-[309px] md:w-[334px] lg:w-[350px]
|
|
194
|
+
inline-flex bg-white items-center
|
|
195
|
+
${resultsList ?
|
|
196
|
+
' border-t border-l border-r rounded-tl rounded-tr lg:border-none ' : // results, round top corners only
|
|
197
|
+
' border lg:border-0 rounded-sm ' // no results, box only rounded
|
|
198
|
+
}
|
|
199
|
+
`}>
|
|
200
|
+
{/* padding 12px */}
|
|
201
|
+
{/* left search icon (small & medium only */}
|
|
202
|
+
<button onClick={handleSearchClick}>
|
|
203
|
+
<span className='lg:hidden rounded-tl px-2 rounded-bl '>
|
|
204
|
+
<img className='' src={SearchIcon} alt='search icon' />
|
|
205
|
+
</span>
|
|
206
|
+
</button>
|
|
207
|
+
<input
|
|
208
|
+
className={twMerge(inputClasses, className)}
|
|
209
|
+
aria-label={ariaLabel}
|
|
210
|
+
value={value}
|
|
211
|
+
onChange={handleInputChange}
|
|
212
|
+
placeholder='Search result'
|
|
213
|
+
onKeyDown={(e) => handleEnter(e)}
|
|
214
|
+
// onKeyDown={(e) => {
|
|
215
|
+
// if (e.key === 'Enter') {
|
|
216
|
+
// handleSearchClick();
|
|
217
|
+
// }
|
|
218
|
+
// }}
|
|
219
|
+
// disabled={disabled}
|
|
220
|
+
// className={cn(inputVariants({variant, inputSize, className}))}
|
|
221
|
+
ref={(node) => {
|
|
222
|
+
if (typeof ref === 'function') ref(node);
|
|
223
|
+
else if (ref) ref.current = node;
|
|
224
|
+
inputRef.current = node; // Maintain local reference
|
|
225
|
+
}}
|
|
226
|
+
{...props}
|
|
227
|
+
/>
|
|
228
|
+
{/* p-[17px] vs p-4 due to the 1px border on the input */}
|
|
229
|
+
{/* right search icon (large only) */}
|
|
230
|
+
<button onClick={handleSearchClick}>
|
|
231
|
+
<span className='hidden lg:flex items-center size-14 p-[17px] bg-[#07192d]
|
|
232
|
+
rounded-tr rounded-br '>
|
|
233
|
+
<img className='' src={SearchIconLg} alt='search icon' />
|
|
234
|
+
</span>
|
|
235
|
+
</button>
|
|
236
|
+
<span className='lg:hidden items-center p-3'>{/* padding 12px? */}
|
|
237
|
+
{/* button --> onClick handler for search */}
|
|
238
|
+
<button className="appearance-none p-0 m-0 border-0 flex items-center justify-center align-middle"
|
|
239
|
+
onClick={ () => selectX() } >
|
|
240
|
+
<img className='' src={CloseIcon} alt='search icon' />
|
|
241
|
+
</button>
|
|
242
|
+
</span>
|
|
243
|
+
</span>
|
|
244
|
+
{/* <div>setSearchResults: {setSearchResults ? 'defined' : 'undefined'}</div> */}
|
|
245
|
+
{ (resultsList && !setSearchResults) && (
|
|
246
|
+
<>
|
|
247
|
+
{/* Pads between input and results - allows bottom border of input to be displayed and not covered */}
|
|
248
|
+
<div
|
|
249
|
+
className={`hidden lg:absolute w-[309px] md:w-[334px] lg:w-[293px] top-full -mt-1 pt-1
|
|
250
|
+
focus:outline-hidden -z-10 ms overflow-hidden h-8
|
|
251
|
+
bg-white lg:shadow-[0px_4px_4px_0px_rgba(0,0,0,0.25)]
|
|
252
|
+
border-[#6a686b] border-l border-r lg:border-none
|
|
253
|
+
`
|
|
254
|
+
}
|
|
255
|
+
></div>
|
|
256
|
+
|
|
257
|
+
<div
|
|
258
|
+
role="listbox"
|
|
259
|
+
ref={resultsRef}
|
|
260
|
+
aria-label="Select option"
|
|
261
|
+
// onKeyDown={handleMenuKeyDown}
|
|
262
|
+
className={`absolute w-[309px] md:w-[334px] lg:w-[293px] top-[calc(100%+4px)] -mt-1 pt-1
|
|
263
|
+
focus:outline-hidden z-10 ms overflow-hidden
|
|
264
|
+
bg-white lg:shadow-[0px_4px_4px_0px_rgba(0,0,0,0.25)]
|
|
265
|
+
border-[#6a686b] border-l border-b border-r lg:border-none
|
|
266
|
+
`
|
|
267
|
+
|
|
268
|
+
// 350-56 - 294
|
|
269
|
+
// inline-flex flex-col justify-start items-start">
|
|
270
|
+
|
|
271
|
+
}
|
|
272
|
+
>
|
|
273
|
+
<hr className="mb-1 -mt-1 mx-2 border-b-0 border-[#A1A6A8] lg:border-none" />
|
|
274
|
+
{/* item.index inside map denotes array index, can use to call out path and title for that item */}
|
|
275
|
+
{resultsList.pages.map((page, index) => (
|
|
276
|
+
|
|
277
|
+
<div key={index} className="ms-4">
|
|
278
|
+
<div className="font-bold text-sm">
|
|
279
|
+
<a role='option' href={page.path} className="text-blue-700 underline">
|
|
280
|
+
{/* */}{page.title && page.title}
|
|
281
|
+
</a>
|
|
282
|
+
</div>
|
|
283
|
+
{page.results.map((result, index) => (
|
|
284
|
+
<div className="ms-4">
|
|
285
|
+
<span className="text-[#1c1d1f]">{resultsList.input}</span>
|
|
286
|
+
<span className="text-[#A1A6A8] lg:text-[#4E4E4E]">{result.characters}</span>
|
|
287
|
+
</div>
|
|
288
|
+
))}
|
|
289
|
+
</div>
|
|
290
|
+
))}
|
|
291
|
+
|
|
292
|
+
{ resultsList?.pages?.length < 1 &&
|
|
293
|
+
<div className='ms-4 mb-1 text-[#1c1d1f]' >no search results</div>
|
|
294
|
+
}
|
|
295
|
+
</div>
|
|
296
|
+
</>
|
|
297
|
+
)}
|
|
298
|
+
</span>
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
Search.displayName = 'Search';
|
|
304
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export interface SearchDataItem {
|
|
2
|
+
path: string;
|
|
3
|
+
title?: string;
|
|
4
|
+
content: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export const SearchableData: SearchDataItem[] = [
|
|
9
|
+
{
|
|
10
|
+
path: 'http://localhost:4200/mobile_apps/sdk-component-demo/',
|
|
11
|
+
title: 'SDK Component Demo Site',
|
|
12
|
+
content: `The SDK will act as a single source of truth for components. Developers, UX designers, and other stakeholders can view and interact with components without needing to set up the full application, improving feedback loops and collaboration.
|
|
13
|
+
If you have feedback on this demo site or any of the DHA SDK components, please email us at: b04eb4d0.chenega.onmicrosoft.com@amer.teams.ms
|
|
14
|
+
For installation instructions for the simple-ui package, please visit install instructions`
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
path: 'http://localhost:4200/mobile_apps/sdk-component-demo/buttons',
|
|
18
|
+
title: 'Button Component',
|
|
19
|
+
content: `Buttons allow users to interact and make choices within an app with a simple touch. Our Button comes with several variants: default, outlined, and text.
|
|
20
|
+
The button component as built takes in various props in addition to any other html attributes a normal html button would use, for example an aria-label tag.
|
|
21
|
+
A ref can also be created and assigned to the button component, and the component will point the reference to the html button.
|
|
22
|
+
The className prop takes a list of alternate CSS classes the developer would like applied to the component. These are applied using the tailwind twMerge function, and will safely overwrite any conflicting classes ensuring proper styling.
|
|
23
|
+
If you would like the button to display a toggled or selected status as the Usage, Code, and Docs buttons above (changing background color when clicked), the selected and optionally the classNameSelected props can be used, explained below.
|
|
24
|
+
`,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
path: 'http://localhost:4200/mobile_apps/sdk-component-demo/input',
|
|
28
|
+
title: 'Input Component',
|
|
29
|
+
content: `The input component as built takes seven optional props (className, classNameLabel, required, label, labelBaseColor, labelInputcolor, mask, and textShadow), in addition to any other html attributes a normal html form input would use, for example an aria tag.
|
|
30
|
+
The mask prop allows the developer to specify an input mask prop such as (###) ###-### that gaurantees formatting for input data. See usage examples in the drop-down, usage examples, as well as notes in the documentation. Note that the mask is not a placeholder, that is a separate mechanism built into html input elements.
|
|
31
|
+
A reference can also be created and passed to the input component, and the component will point the reference to the input
|
|
32
|
+
The input component as built takes seven optional props in addition to any other html attributes a normal html form input would use, for example an aria tag.
|
|
33
|
+
A reference can also be created and passed to the input component, and the component will point the reference to the input.
|
|
34
|
+
`,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
path: 'http://localhost:4200/mobile_apps/sdk-component-demo/select',
|
|
38
|
+
title: 'Select Component',
|
|
39
|
+
content: `Select components or drop-downs allow a user to make a single selection from multiple choices while preserving space on the form. Our Select component comes with several variants: default, fill, and outline.
|
|
40
|
+
The Select component takes two required props (options and setSelectedOption) as well as multiple optional props in addition to any other html attributes a normal html element would use, for example an aria-tag.
|
|
41
|
+
`,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
path: 'http://localhost:4200/mobile_apps/sdk-component-demo/toggle',
|
|
45
|
+
title: 'Toggle Component',
|
|
46
|
+
content: `A Toggle is an element that allows the user to make a choice between two mutually exclusive states. Our Toggle comes with two variants: default and outlined
|
|
47
|
+
The Toggle component takes a variant prop used to indicate pre-defined styles, an optional click handler, and various other optional props described below and uses those to display a Toggle button. The variant prop currently takes one of two values, those possible values currently being 'default' and 'outlined'.
|
|
48
|
+
As with the button component, Toggle takes any other additional html attributes and passes them to the parent <button> tag. This div is styled using the tailwind twMerge() utility, so custom classes can be added via the classNames prop as and applied as well.
|
|
49
|
+
`,
|
|
50
|
+
}
|
|
51
|
+
]
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Badge.stories.tsx
|
|
2
|
+
|
|
3
|
+
// import { Meta, StoryFn} from '@storybook/react';
|
|
4
|
+
import { SectionHeader } from './SectionHeader';
|
|
5
|
+
import { Meta, StoryContext, StoryFn, StoryObj } from '@storybook/react';
|
|
6
|
+
import { Input, InputProps } from './Input';
|
|
7
|
+
import { Button } from './Button';
|
|
8
|
+
import { CharacterCounter, CharacterCounterProps } from './CharacterCounter';
|
|
9
|
+
import { userEvent, within } from 'storybook/test';
|
|
10
|
+
import { expect } from 'storybook/test';
|
|
11
|
+
import { FC, useRef, useState } from 'react';
|
|
12
|
+
import frame from '../assets/img/Frame.svg';
|
|
13
|
+
import check from '../assets/img/check.svg';
|
|
14
|
+
import chevronRight from '../assets/img/chevron-right.svg';
|
|
15
|
+
|
|
16
|
+
// Import your images
|
|
17
|
+
import firstAidKit from '../assets/img/first-aid-kit.svg';
|
|
18
|
+
import heartbeat from '../assets/img/heartbeat.svg';
|
|
19
|
+
import pill from '../assets/img/pill.svg';
|
|
20
|
+
import prescription from '../assets/img/prescription.svg';
|
|
21
|
+
import stethoscope from '../assets/img/stethoscope.svg';
|
|
22
|
+
// import { useState } from 'react';
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
export default {
|
|
26
|
+
title: 'Components/SectionHeader',
|
|
27
|
+
component: SectionHeader,
|
|
28
|
+
args: {
|
|
29
|
+
|
|
30
|
+
},
|
|
31
|
+
parameters: {
|
|
32
|
+
layout: 'centered',
|
|
33
|
+
backgrounds: { default: 'light' },
|
|
34
|
+
},
|
|
35
|
+
} as Meta<typeof SectionHeader>;
|
|
36
|
+
|
|
37
|
+
/*
|
|
38
|
+
className?: string;
|
|
39
|
+
leftIcon?: ReactNode; // displays left icon if present
|
|
40
|
+
rightIcon?: ReactNode; // displays right icon if present
|
|
41
|
+
underline?: boolean; // display or not the underline
|
|
42
|
+
subHeader?: string; // if present, displays subHeader below primary Header line
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
// DefaultBadge story
|
|
46
|
+
export const DefaultSectionHeader = {
|
|
47
|
+
args: {
|
|
48
|
+
className: 'w-[600px]',
|
|
49
|
+
children: "I'm a Header!",
|
|
50
|
+
iconRight: <img src={frame} alt='left icon' className='size-10' />,
|
|
51
|
+
iconLeft: <img src={check} alt='right icon' className='size-8' />,
|
|
52
|
+
underline: true,
|
|
53
|
+
subHeader: "Subheader Here",
|
|
54
|
+
childButton: <Button variant='transparent' className='h-10'
|
|
55
|
+
icon={<img src={chevronRight} alt='right chevron' />}
|
|
56
|
+
iconPosition='right' >Click Me</Button>
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// DefaultBadge story
|
|
61
|
+
export const NoUnderline = {
|
|
62
|
+
args: {
|
|
63
|
+
className: 'w-[600px]',
|
|
64
|
+
children: "I'm a Header!",
|
|
65
|
+
iconLeft: <img src={frame} alt='left icon' className='size-10' />,
|
|
66
|
+
iconRight: <img src={check} alt='right icon' className='size-8' />,
|
|
67
|
+
subHeader: "Subheader Here",
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// DefaultBadge story
|
|
72
|
+
export const NoSubHeaderLeftIconOnly = {
|
|
73
|
+
args: {
|
|
74
|
+
className: 'w-[600px]',
|
|
75
|
+
children: "I'm a Header!",
|
|
76
|
+
iconLeft: <img src={frame} alt='left icon' className='size-10' />,
|
|
77
|
+
underline: true,
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// DefaultBadge story
|
|
82
|
+
export const NoLeftIconNoSubHeader = {
|
|
83
|
+
args: {
|
|
84
|
+
className: 'w-[600px]',
|
|
85
|
+
children: "I'm a Header!",
|
|
86
|
+
iconRight: <img src={check} alt='right icon' className='size-8' />,
|
|
87
|
+
underline: true,
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const NoLeftIconNoSubHeaderNoUnderline = {
|
|
92
|
+
args: {
|
|
93
|
+
className: 'w-[600px]',
|
|
94
|
+
children: "I'm a Header!",
|
|
95
|
+
iconLeft: <img src={frame} alt='left icon' className='size-10' />,
|
|
96
|
+
iconRight: <img src={check} alt='right icon' className='size-8' />,
|
|
97
|
+
}
|
|
98
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { SectionHeader } from './SectionHeader';
|
|
4
|
+
|
|
5
|
+
describe('SectionHeader Component', () => {
|
|
6
|
+
it('renders the main header text', () => {
|
|
7
|
+
render(<SectionHeader>Test Header</SectionHeader>);
|
|
8
|
+
expect(screen.getByText('Test Header')).toBeInTheDocument();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('merges default classes with custom className', () => {
|
|
12
|
+
const customClass = 'custom-class';
|
|
13
|
+
render(<SectionHeader className={customClass}>Test Header</SectionHeader>);
|
|
14
|
+
// The outer div should include the custom class along with default classes.
|
|
15
|
+
const outerDiv = screen.getByText('Test Header').parentElement?.parentElement?.parentElement;
|
|
16
|
+
expect(outerDiv).toHaveClass('custom-class');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('renders a section header with a button, type = section and fill = true', () => {
|
|
20
|
+
render(<SectionHeader button fill type='section'>Test Header</SectionHeader>);
|
|
21
|
+
expect(screen.getByText('Test Header')).toBeInTheDocument();;
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('renders a section header of type subsection, applies underline classes when underline prop is true', () => {
|
|
25
|
+
render(<SectionHeader type='subsection' underline>Test Header</SectionHeader>);
|
|
26
|
+
const outerDiv = screen.getByText('Test Header').parentElement?.parentElement?.parentElement;
|
|
27
|
+
expect(outerDiv).toHaveClass("border-b-2 border-[#07192D]");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('renders a subHeader when provided', () => {
|
|
31
|
+
render(
|
|
32
|
+
<SectionHeader subHeader="Sub Header">
|
|
33
|
+
Test Header
|
|
34
|
+
</SectionHeader>
|
|
35
|
+
);
|
|
36
|
+
expect(screen.getByText('Sub Header')).toBeInTheDocument();
|
|
37
|
+
// Check for one of the classes applied to subHeader text.
|
|
38
|
+
expect(screen.getByText('Sub Header')).toHaveClass(/text-xl/);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('renders iconLeft when provided', () => {
|
|
42
|
+
render(
|
|
43
|
+
<SectionHeader iconLeft={<span data-testid="icon-left">IconLeft</span>}>
|
|
44
|
+
Test Header
|
|
45
|
+
</SectionHeader>
|
|
46
|
+
);
|
|
47
|
+
expect(screen.getByTestId('icon-left')).toBeInTheDocument();
|
|
48
|
+
expect(screen.getByTestId('icon-left')).toHaveTextContent('IconLeft');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('renders iconRight when provided', () => {
|
|
52
|
+
render(
|
|
53
|
+
<SectionHeader iconRight={<span data-testid="icon-right">IconRight</span>}>
|
|
54
|
+
Test Header
|
|
55
|
+
</SectionHeader>
|
|
56
|
+
);
|
|
57
|
+
expect(screen.getByTestId('icon-right')).toBeInTheDocument();
|
|
58
|
+
expect(screen.getByTestId('icon-right')).toHaveTextContent('IconRight');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { forwardRef, HTMLAttributes, ReactNode, useEffect, useState } from 'react';
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
import { Button } from './Button';
|
|
4
|
+
|
|
5
|
+
import chevronRight from '../assets/img/chevron-right.svg';
|
|
6
|
+
import chevronRightLight from '../assets/img/chevron-right-light.svg';
|
|
7
|
+
|
|
8
|
+
export interface SectionHeaderProps extends HTMLAttributes<HTMLDivElement> {
|
|
9
|
+
className?: string;
|
|
10
|
+
classNameChildren?: string;
|
|
11
|
+
classNameSubHeader?: string;
|
|
12
|
+
iconLeft?: ReactNode | undefined; // displays left icon if present
|
|
13
|
+
iconRight?: ReactNode | undefined; // displays right icon if present
|
|
14
|
+
underline?: boolean; // display or not the underline
|
|
15
|
+
subHeader?: string; // if present, displays subHeader below primary Header line
|
|
16
|
+
fill?: boolean;
|
|
17
|
+
button?: boolean;
|
|
18
|
+
type?: 'page' | 'section' | 'subsection';
|
|
19
|
+
buttonOnClick?: () => void;
|
|
20
|
+
buttonContent?: string;
|
|
21
|
+
padLeft?: boolean;
|
|
22
|
+
padRight?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const SectionHeader = forwardRef<HTMLDivElement, SectionHeaderProps>(
|
|
26
|
+
({ className = '', classNameChildren = '', classNameSubHeader = '', iconLeft, iconRight,
|
|
27
|
+
underline = false, subHeader = false, fill = false, type = 'page', padLeft = true,
|
|
28
|
+
padRight = true, button, buttonOnClick, buttonContent = 'Click Me',
|
|
29
|
+
children, ...props }, ref) => {
|
|
30
|
+
|
|
31
|
+
const [outerClasses, setOuterClasses] = useState<string>('');
|
|
32
|
+
const [headerClasses, setHeaderClasses] = useState<string>('');
|
|
33
|
+
const [subHeaderClasses, setSubHeaderClasses] = useState<string>('');
|
|
34
|
+
// top & bottom padding different for type === page
|
|
35
|
+
const defaultClasses = `${type === 'page' ? 'pt-4 pb-2' : 'py-2'} flex pl-6 pr-2 justify-start items-center gap-4 inline-flex w-full`;
|
|
36
|
+
|
|
37
|
+
// dark text - text-[#07192d]
|
|
38
|
+
// light text - text-[#f0f0f0]
|
|
39
|
+
|
|
40
|
+
// build default css classes w/ twMerge
|
|
41
|
+
useEffect (() => {
|
|
42
|
+
const classUnderLine = underline ? 'border-b-2 border-[#07192D]' : '';
|
|
43
|
+
const classFill = fill ? 'bg-[#092068] text-[#f0f0f0]' : 'bg-transparent text-[#07192d]';
|
|
44
|
+
const padding = padLeft && padRight ? 'mx-4 ' : padLeft ? 'ms-4' : padRight ? 'me-4' : '';
|
|
45
|
+
setOuterClasses(twMerge(defaultClasses, classUnderLine, classFill, padding, className));
|
|
46
|
+
}, [className, underline, fill, defaultClasses, padLeft, padRight]);
|
|
47
|
+
|
|
48
|
+
// console.log('outerClasses: ', outerClasses);
|
|
49
|
+
|
|
50
|
+
useEffect (() => {
|
|
51
|
+
setHeaderClasses(twMerge(`self-stretch ${ type === 'page' ? 'text-[40px]' : type === 'section' ? ' text-[32px]' : 'text-2xl'} font-normal font-["Arial"] leading-[48px]`, classNameChildren));
|
|
52
|
+
}, [classNameChildren, type]);
|
|
53
|
+
|
|
54
|
+
useEffect (() => {
|
|
55
|
+
setSubHeaderClasses(twMerge(`${type === 'page' ? 'text-xl' : 'text-lg'} font-normal font-["Arial"] leading-[30px]`, classNameSubHeader));
|
|
56
|
+
}, [classNameSubHeader, type]);
|
|
57
|
+
|
|
58
|
+
// type?: 'page' | 'section' | 'subsection';
|
|
59
|
+
// page - icon 40x40px, text 40px, sub-header 30px
|
|
60
|
+
// section - icon 24x24px, text 32px, sub-header text-lg(18px)
|
|
61
|
+
// subsection - icon 24x24px, text 2xl(24px), sub-header text-lg(18px)
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div className={twMerge(outerClasses, className)}>
|
|
65
|
+
{/* justify-story --> start at left side, items-center --> vertical middle of flex row */}
|
|
66
|
+
<div className="grow shrink basis-0 justify-start items-center gap-4 flex flex-row">
|
|
67
|
+
|
|
68
|
+
{iconLeft && iconLeft }
|
|
69
|
+
|
|
70
|
+
<div className="flex-col justify-start items-start inline-flex w-full">
|
|
71
|
+
<div className={headerClasses}
|
|
72
|
+
>{children}</div>
|
|
73
|
+
{subHeader && <div className={subHeaderClasses}
|
|
74
|
+
>{subHeader}</div>}
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
{ iconRight && iconRight }
|
|
78
|
+
|
|
79
|
+
{ button &&
|
|
80
|
+
|
|
81
|
+
// text color and icon correctly set based on fill value
|
|
82
|
+
<Button variant='transparent' className={`h-[48px] text-black ${fill && 'text-[#f0f0f0] active:bg-blue-700 hover:bg-[#092068]'}
|
|
83
|
+
${ type === 'page' ? 'text-base' : 'text-sm'} }`}
|
|
84
|
+
icon={<img src={fill ? chevronRightLight : chevronRight} alt='right chevron' />}
|
|
85
|
+
iconPosition='right' onClick={buttonOnClick} >{buttonContent}</Button>
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
});
|