@bloom-housing/ui-components 9.0.0-alpha.1 → 9.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/actions/ExpandableContent.test.js +1 -1
- package/dist/__tests__/actions/ExpandableContent.test.js.map +1 -1
- package/dist/__tests__/page_components/ContentAccordion.test.js +2 -2
- package/dist/__tests__/page_components/ContentAccordion.test.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/src/actions/Button.d.ts +1 -1
- package/dist/src/actions/Button.js +1 -1
- package/dist/src/actions/Button.js.map +1 -1
- package/dist/src/actions/LinkButton.js +2 -2
- package/dist/src/actions/LinkButton.js.map +1 -1
- package/dist/src/blocks/DashBlock.js +1 -1
- package/dist/src/blocks/DashBlock.js.map +1 -1
- package/dist/src/blocks/ImageCard.d.ts +3 -0
- package/dist/src/blocks/ImageCard.js +31 -17
- package/dist/src/blocks/ImageCard.js.map +1 -1
- package/dist/src/blocks/ImageCard.stories.d.ts +1 -0
- package/dist/src/blocks/ImageCard.stories.js +17 -0
- package/dist/src/blocks/ImageCard.stories.js.map +1 -1
- package/dist/src/blocks/InfoCard.d.ts +1 -1
- package/dist/src/blocks/InfoCard.js +1 -1
- package/dist/src/blocks/InfoCard.stories.d.ts +1 -0
- package/dist/src/blocks/InfoCard.stories.js +3 -1
- package/dist/src/blocks/InfoCard.stories.js.map +1 -1
- package/dist/src/blocks/Tooltip.d.ts +13 -0
- package/dist/src/blocks/Tooltip.js +28 -0
- package/dist/src/blocks/Tooltip.js.map +1 -0
- package/dist/src/blocks/ViewItem.js +2 -2
- package/dist/src/blocks/ViewItem.js.map +1 -1
- package/dist/src/forms/Dropzone.js +1 -1
- package/dist/src/forms/Dropzone.js.map +1 -1
- package/dist/src/forms/Field.js +1 -1
- package/dist/src/forms/Field.js.map +1 -1
- package/dist/src/forms/FieldGroup.js +8 -8
- package/dist/src/forms/FieldGroup.js.map +1 -1
- package/dist/src/forms/HouseholdMemberForm.js +1 -1
- package/dist/src/forms/HouseholdMemberForm.js.map +1 -1
- package/dist/src/forms/MultiSelectField.js +1 -1
- package/dist/src/forms/MultiSelectField.js.map +1 -1
- package/dist/src/forms/PhoneField.js +2 -2
- package/dist/src/forms/PhoneField.js.map +1 -1
- package/dist/src/forms/Select.js +2 -2
- package/dist/src/forms/Select.js.map +1 -1
- package/dist/src/forms/Textarea.js +1 -1
- package/dist/src/forms/Textarea.js.map +1 -1
- package/dist/src/headers/Hero.js +2 -2
- package/dist/src/headers/Hero.js.map +1 -1
- package/dist/src/headers/PageHeader.js +1 -1
- package/dist/src/headers/PageHeader.js.map +1 -1
- package/dist/src/headers/SiteHeader.js +3 -3
- package/dist/src/headers/SiteHeader.js.map +1 -1
- package/dist/src/icons/Icon.js +2 -2
- package/dist/src/icons/Icon.js.map +1 -1
- package/dist/src/notifications/AlertBox.js +1 -1
- package/dist/src/notifications/AlertBox.js.map +1 -1
- package/dist/src/notifications/ErrorMessage.js +1 -1
- package/dist/src/notifications/ErrorMessage.js.map +1 -1
- package/dist/src/overlays/LoadingOverlay.js +1 -1
- package/dist/src/overlays/LoadingOverlay.js.map +1 -1
- package/dist/src/overlays/Modal.d.ts +2 -1
- package/dist/src/overlays/Modal.js +2 -2
- package/dist/src/overlays/Modal.js.map +1 -1
- package/dist/src/overlays/Modal.stories.js +4 -4
- package/dist/src/overlays/Modal.stories.js.map +1 -1
- package/dist/src/page_components/listing/AdditionalFees.stories.d.ts +1 -0
- package/dist/src/page_components/listing/AdditionalFees.stories.js +3 -0
- package/dist/src/page_components/listing/AdditionalFees.stories.js.map +1 -1
- package/dist/src/page_components/listing/ContentAccordion.js +1 -1
- package/dist/src/page_components/listing/ContentAccordion.js.map +1 -1
- package/dist/src/page_components/listing/ListingCard.js +1 -1
- package/dist/src/page_components/listing/ListingCard.js.map +1 -1
- package/dist/src/page_components/listing/listing_sidebar/GetApplication.js +2 -2
- package/dist/src/page_components/listing/listing_sidebar/GetApplication.js.map +1 -1
- package/dist/src/page_components/sign-in/FormSignIn.js +1 -1
- package/dist/src/page_components/sign-in/FormSignIn.js.map +1 -1
- package/dist/src/page_components/sign-in/FormSignInAddPhone.js +1 -1
- package/dist/src/page_components/sign-in/FormSignInAddPhone.js.map +1 -1
- package/dist/src/page_components/sign-in/FormSignInMFACode.js +1 -1
- package/dist/src/page_components/sign-in/FormSignInMFACode.js.map +1 -1
- package/dist/src/page_components/sign-in/FormSignInMFAType.js +2 -2
- package/dist/src/page_components/sign-in/FormSignInMFAType.js.map +1 -1
- package/dist/src/page_components/sign-in/FormTerms.js +1 -1
- package/dist/src/page_components/sign-in/FormTerms.js.map +1 -1
- package/dist/src/sections/InfoCardGrid.js +1 -1
- package/dist/src/sections/InfoCardGrid.js.map +1 -1
- package/dist/src/tables/AgPagination.js +4 -4
- package/dist/src/tables/AgPagination.js.map +1 -1
- package/dist/src/text/Tag.d.ts +1 -0
- package/dist/src/text/Tag.js +1 -1
- package/dist/src/text/Tag.js.map +1 -1
- package/index.ts +1 -0
- package/package.json +24 -25
- package/src/actions/Button.tsx +2 -2
- package/src/actions/LinkButton.tsx +2 -2
- package/src/blocks/DashBlock.tsx +1 -1
- package/src/blocks/ImageCard.scss +27 -1
- package/src/blocks/ImageCard.stories.tsx +27 -1
- package/src/blocks/ImageCard.tsx +49 -38
- package/src/blocks/InfoCard.scss +18 -0
- package/src/blocks/InfoCard.stories.tsx +12 -0
- package/src/blocks/InfoCard.tsx +2 -2
- package/src/blocks/Tooltip.scss +43 -0
- package/src/blocks/Tooltip.tsx +65 -0
- package/src/blocks/ViewItem.tsx +2 -2
- package/src/forms/Dropzone.tsx +1 -1
- package/src/forms/Field.tsx +1 -1
- package/src/forms/FieldGroup.tsx +10 -10
- package/src/forms/HouseholdMemberForm.tsx +1 -1
- package/src/forms/MultiSelectField.tsx +1 -1
- package/src/forms/PhoneField.tsx +2 -2
- package/src/forms/Select.tsx +3 -3
- package/src/forms/Textarea.tsx +1 -1
- package/src/global/tokens/sizes.scss +1 -1
- package/src/headers/Hero.tsx +2 -2
- package/src/headers/PageHeader.tsx +1 -1
- package/src/headers/SiteHeader.tsx +3 -3
- package/src/icons/Icon.tsx +2 -2
- package/src/notifications/AlertBox.tsx +1 -1
- package/src/notifications/ErrorMessage.tsx +1 -1
- package/src/overlays/LoadingOverlay.tsx +1 -1
- package/src/overlays/Modal.scss +28 -11
- package/src/overlays/Modal.stories.tsx +4 -4
- package/src/overlays/Modal.tsx +4 -3
- package/src/page_components/listing/AdditionalFees.stories.tsx +4 -0
- package/src/page_components/listing/ContentAccordion.tsx +1 -1
- package/src/page_components/listing/ListingCard.tsx +1 -1
- package/src/page_components/listing/listing_sidebar/GetApplication.tsx +2 -2
- package/src/page_components/sign-in/FormSignIn.tsx +1 -1
- package/src/page_components/sign-in/FormSignInAddPhone.tsx +1 -1
- package/src/page_components/sign-in/FormSignInMFACode.tsx +1 -1
- package/src/page_components/sign-in/FormSignInMFAType.tsx +2 -2
- package/src/page_components/sign-in/FormTerms.tsx +1 -1
- package/src/sections/InfoCardGrid.scss +12 -16
- package/src/sections/InfoCardGrid.tsx +1 -1
- package/src/tables/AgPagination.tsx +4 -4
- package/src/text/Tag.tsx +6 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
@import "../global/mixins.scss";
|
|
2
|
+
@import "../global/accessibility.scss";
|
|
2
3
|
|
|
3
4
|
.image-card {
|
|
4
5
|
/* Component Variables */
|
|
@@ -18,6 +19,11 @@
|
|
|
18
19
|
background-color: var(--default-background-color);
|
|
19
20
|
border-radius: var(--border-radius);
|
|
20
21
|
|
|
22
|
+
button:focus {
|
|
23
|
+
outline: none;
|
|
24
|
+
box-shadow: 0 0 3px 4px var(--bloom-color-accent-cool);
|
|
25
|
+
}
|
|
26
|
+
|
|
21
27
|
img {
|
|
22
28
|
border-radius: var(--border-radius);
|
|
23
29
|
width: 100%;
|
|
@@ -98,7 +104,8 @@
|
|
|
98
104
|
flex-direction: column;
|
|
99
105
|
align-items: center;
|
|
100
106
|
justify-content: center;
|
|
101
|
-
|
|
107
|
+
color: var(--bloom-color-white);
|
|
108
|
+
background: rgba(0, 0, 0, 0.6);
|
|
102
109
|
@media (max-width: $screen-sm) {
|
|
103
110
|
font-size: var(--bloom-font-size-xs);
|
|
104
111
|
line-height: var(--bloom-line-height-none);
|
|
@@ -119,6 +126,7 @@
|
|
|
119
126
|
justify-content: var(--tags-justify);
|
|
120
127
|
position: absolute;
|
|
121
128
|
top: 0;
|
|
129
|
+
z-index: 10;
|
|
122
130
|
width: 100%;
|
|
123
131
|
margin-block-start: var(--bloom-s1);
|
|
124
132
|
padding-inline: var(--bloom-s4);
|
|
@@ -157,4 +165,22 @@
|
|
|
157
165
|
--footer-justify: center;
|
|
158
166
|
--modal-border: none;
|
|
159
167
|
--modal-shadow: none;
|
|
168
|
+
@media (min-width: $screen-md) {
|
|
169
|
+
--scroll-max-height: calc(80vh - 200px);
|
|
170
|
+
max-width: var(--bloom-width-5xl);
|
|
171
|
+
}
|
|
172
|
+
section {
|
|
173
|
+
display: flex;
|
|
174
|
+
flex-direction: column;
|
|
175
|
+
align-items: center;
|
|
176
|
+
}
|
|
177
|
+
button {
|
|
178
|
+
outline: none;
|
|
179
|
+
}
|
|
180
|
+
svg {
|
|
181
|
+
@extend .sr-only;
|
|
182
|
+
}
|
|
183
|
+
footer button:focus {
|
|
184
|
+
box-shadow: 0 0 3px 4px var(--bloom-color-accent-cool);
|
|
185
|
+
}
|
|
160
186
|
}
|
|
@@ -3,7 +3,7 @@ import { BADGES } from "../../.storybook/constants"
|
|
|
3
3
|
import { ImageCard } from "./ImageCard"
|
|
4
4
|
import { t } from "../helpers/translator"
|
|
5
5
|
import { ApplicationStatusType } from "../global/ApplicationStatusType"
|
|
6
|
-
import { IconFillColors } from "../icons/Icon"
|
|
6
|
+
import { IconFillColors, UniversalIconType } from "../icons/Icon"
|
|
7
7
|
import ImageCardDocumentation from "./ImageCard.docs.mdx"
|
|
8
8
|
|
|
9
9
|
export default {
|
|
@@ -103,6 +103,32 @@ export const withMultipleTags = () => (
|
|
|
103
103
|
/>
|
|
104
104
|
)
|
|
105
105
|
|
|
106
|
+
export const withTooltip = () => (
|
|
107
|
+
<div style={{ margin: "5rem" }}>
|
|
108
|
+
<ImageCard
|
|
109
|
+
href="/listings"
|
|
110
|
+
imageUrl="/images/listing.jpg"
|
|
111
|
+
tags={[
|
|
112
|
+
{
|
|
113
|
+
text: "Label",
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
text: "Label2",
|
|
117
|
+
iconType: "globe" as UniversalIconType,
|
|
118
|
+
iconColor: IconFillColors.white,
|
|
119
|
+
tooltip: {
|
|
120
|
+
id: "tooltip",
|
|
121
|
+
text: "Here is some helpful tooltip content. Here is even more helpful tooltip content.",
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
]}
|
|
125
|
+
statuses={[
|
|
126
|
+
{ status: ApplicationStatusType.Closed, content: t("listings.applicationsClosed") },
|
|
127
|
+
]}
|
|
128
|
+
/>
|
|
129
|
+
</div>
|
|
130
|
+
)
|
|
131
|
+
|
|
106
132
|
export const withLongTagsAndIcons = () => (
|
|
107
133
|
<ImageCard
|
|
108
134
|
href="/listings"
|
package/src/blocks/ImageCard.tsx
CHANGED
|
@@ -3,6 +3,7 @@ import { LocalizedLink } from "../actions/LocalizedLink"
|
|
|
3
3
|
import { ApplicationStatus } from "../notifications/ApplicationStatus"
|
|
4
4
|
import "./ImageCard.scss"
|
|
5
5
|
import { Tag } from "../text/Tag"
|
|
6
|
+
import { TooltipProps, Tooltip } from "./Tooltip"
|
|
6
7
|
import { ApplicationStatusType } from "../global/ApplicationStatusType"
|
|
7
8
|
import { AppearanceSizeType, AppearanceStyleType } from "../global/AppearanceTypes"
|
|
8
9
|
import { Icon, IconFillColors, UniversalIconType } from "../icons/Icon"
|
|
@@ -18,11 +19,14 @@ export interface StatusBarType {
|
|
|
18
19
|
iconType?: UniversalIconType
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
export type ImageTagTooltip = Pick<TooltipProps, "id" | "text">
|
|
23
|
+
|
|
21
24
|
export interface ImageTag {
|
|
22
25
|
text?: string
|
|
23
26
|
iconType?: UniversalIconType
|
|
24
27
|
iconColor?: string
|
|
25
28
|
styleType?: AppearanceStyleType
|
|
29
|
+
tooltip?: ImageTagTooltip
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
export interface ImageItem {
|
|
@@ -80,11 +84,7 @@ const ImageCard = (props: ImageCardProps) => {
|
|
|
80
84
|
/>
|
|
81
85
|
)
|
|
82
86
|
})
|
|
83
|
-
return
|
|
84
|
-
<aside className="image-card__status" aria-label={`${props.description || ""} Statuses`}>
|
|
85
|
-
{statuses}
|
|
86
|
-
</aside>
|
|
87
|
-
)
|
|
87
|
+
return <aside aria-label={`${props.description || ""} Statuses`}>{statuses}</aside>
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
const innerClasses = ["image-card__inner"]
|
|
@@ -147,7 +147,7 @@ const ImageCard = (props: ImageCardProps) => {
|
|
|
147
147
|
? `${props.images.length - 2} ${props.moreImagesDescription}`
|
|
148
148
|
: "More Images"
|
|
149
149
|
}
|
|
150
|
-
data-
|
|
150
|
+
data-test-id="open-modal-button"
|
|
151
151
|
onClick={() => {
|
|
152
152
|
setShowModal(true)
|
|
153
153
|
}}
|
|
@@ -158,20 +158,34 @@ const ImageCard = (props: ImageCardProps) => {
|
|
|
158
158
|
{getStatuses()}
|
|
159
159
|
<div className="image-card-tag__wrapper">
|
|
160
160
|
{props.tags?.map((tag, index) => {
|
|
161
|
-
|
|
162
|
-
<
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
161
|
+
const tagContent = (
|
|
162
|
+
<Tag
|
|
163
|
+
styleType={tag.styleType || AppearanceStyleType.warning}
|
|
164
|
+
ariaLabel={
|
|
165
|
+
tag.tooltip ? `${tag.text || ""} - ${tag.tooltip?.text || ""}` : undefined
|
|
166
|
+
}
|
|
167
|
+
>
|
|
168
|
+
{tag.iconType && (
|
|
169
|
+
<Icon
|
|
170
|
+
size={"medium"}
|
|
171
|
+
symbol={tag.iconType}
|
|
172
|
+
fill={tag.iconColor ?? IconFillColors.primary}
|
|
173
|
+
className={"mr-2"}
|
|
174
|
+
/>
|
|
175
|
+
)}
|
|
176
|
+
{tag.text}
|
|
177
|
+
</Tag>
|
|
174
178
|
)
|
|
179
|
+
|
|
180
|
+
if (tag.tooltip) {
|
|
181
|
+
return (
|
|
182
|
+
<Tooltip key={index} className="mt-3" {...tag.tooltip}>
|
|
183
|
+
{tagContent}
|
|
184
|
+
</Tooltip>
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return <React.Fragment key={index}>{tagContent}</React.Fragment>
|
|
175
189
|
})}
|
|
176
190
|
</div>
|
|
177
191
|
</div>
|
|
@@ -179,7 +193,7 @@ const ImageCard = (props: ImageCardProps) => {
|
|
|
179
193
|
<Modal
|
|
180
194
|
open={showModal}
|
|
181
195
|
title={props.modalAriaTitle || "Images"}
|
|
182
|
-
|
|
196
|
+
scrollableModal={true}
|
|
183
197
|
onClose={() => setShowModal(!showModal)}
|
|
184
198
|
className="image-card__overlay"
|
|
185
199
|
modalClassNames="image-card__gallery-modal"
|
|
@@ -191,24 +205,21 @@ const ImageCard = (props: ImageCardProps) => {
|
|
|
191
205
|
</Button>,
|
|
192
206
|
]}
|
|
193
207
|
>
|
|
194
|
-
{props.images
|
|
195
|
-
|
|
196
|
-
<
|
|
197
|
-
<
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
</picture>
|
|
210
|
-
</p>
|
|
211
|
-
))}
|
|
208
|
+
{props.images?.map((image, index) => (
|
|
209
|
+
<p key={index} className="mb-7">
|
|
210
|
+
<picture>
|
|
211
|
+
{image.mobileUrl && <source media="(max-width: 767px)" srcSet={image.mobileUrl} />}
|
|
212
|
+
<img
|
|
213
|
+
src={image.url}
|
|
214
|
+
alt={
|
|
215
|
+
image.description
|
|
216
|
+
? image.description
|
|
217
|
+
: `${props.description || ""} - photo ${index + 1}`
|
|
218
|
+
}
|
|
219
|
+
/>
|
|
220
|
+
</picture>
|
|
221
|
+
</p>
|
|
222
|
+
))}
|
|
212
223
|
</Modal>
|
|
213
224
|
)}
|
|
214
225
|
</>
|
package/src/blocks/InfoCard.scss
CHANGED
|
@@ -46,3 +46,21 @@
|
|
|
46
46
|
margin-bottom: var(--bloom-s4);
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
+
|
|
50
|
+
.info-card__columns {
|
|
51
|
+
display: flex;
|
|
52
|
+
flex-wrap: wrap;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.info-card__column {
|
|
56
|
+
flex: 1 1 0%;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.info-card__column-2 {
|
|
60
|
+
flex: 1 1 100%;
|
|
61
|
+
margin-top: var(--bloom-s4);
|
|
62
|
+
margin-right: var(--bloom-s4);
|
|
63
|
+
@media (min-width: 440px) {
|
|
64
|
+
flex: 1 1 45%;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -20,6 +20,7 @@ export const Default = () => (
|
|
|
20
20
|
<>
|
|
21
21
|
<InfoCard
|
|
22
22
|
title="My Card"
|
|
23
|
+
subtitle="Subtitle"
|
|
23
24
|
externalHref="http://google.com"
|
|
24
25
|
className="is-normal-primary-lighter"
|
|
25
26
|
>
|
|
@@ -34,6 +35,17 @@ More content
|
|
|
34
35
|
</>
|
|
35
36
|
)
|
|
36
37
|
|
|
38
|
+
export const NoChildren = () => (
|
|
39
|
+
<>
|
|
40
|
+
<InfoCard
|
|
41
|
+
title="My Card"
|
|
42
|
+
subtitle="Subtitle"
|
|
43
|
+
externalHref="http://google.com"
|
|
44
|
+
className="is-normal-primary-lighter"
|
|
45
|
+
/>
|
|
46
|
+
</>
|
|
47
|
+
)
|
|
48
|
+
|
|
37
49
|
export const WithMarkdown = () => (
|
|
38
50
|
<InfoCard title="My Card" externalHref="http://google.com" className="is-normal-primary-lighter">
|
|
39
51
|
{`
|
package/src/blocks/InfoCard.tsx
CHANGED
|
@@ -7,7 +7,7 @@ export interface InfoCardProps {
|
|
|
7
7
|
subtitle?: string
|
|
8
8
|
externalHref?: string
|
|
9
9
|
className?: string
|
|
10
|
-
children
|
|
10
|
+
children?: React.ReactNode
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
const InfoCard = (props: InfoCardProps) => {
|
|
@@ -28,7 +28,7 @@ const InfoCard = (props: InfoCardProps) => {
|
|
|
28
28
|
) : (
|
|
29
29
|
<h3 className="info-card__title">{props.title}</h3>
|
|
30
30
|
)}
|
|
31
|
-
{props.subtitle && <span className={"text-
|
|
31
|
+
{props.subtitle && <span className={"text-sm text-gray-700"}>{props.subtitle}</span>}
|
|
32
32
|
</div>
|
|
33
33
|
{typeof props.children == "string" ? (
|
|
34
34
|
<div className="markdown">
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
.tooltip {
|
|
2
|
+
@apply relative;
|
|
3
|
+
display: inline-block;
|
|
4
|
+
width: fit-content;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.tooltip__element {
|
|
8
|
+
@apply w-full;
|
|
9
|
+
@apply fixed;
|
|
10
|
+
@apply bg-primary-dark;
|
|
11
|
+
@apply text-white;
|
|
12
|
+
@apply rounded;
|
|
13
|
+
@apply p-2;
|
|
14
|
+
@apply text-sm;
|
|
15
|
+
@apply font-bold;
|
|
16
|
+
@apply text-center;
|
|
17
|
+
@apply normal-case;
|
|
18
|
+
@apply opacity-0;
|
|
19
|
+
@apply invisible;
|
|
20
|
+
transform: translate(-50%, calc(-100% - 10px * 2));
|
|
21
|
+
|
|
22
|
+
max-width: 280px;
|
|
23
|
+
transition: opacity 0.2s;
|
|
24
|
+
|
|
25
|
+
&--visible {
|
|
26
|
+
@apply opacity-100;
|
|
27
|
+
@apply visible;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
&::before {
|
|
31
|
+
content: "";
|
|
32
|
+
@apply absolute;
|
|
33
|
+
@apply bottom-0;
|
|
34
|
+
@apply w-0;
|
|
35
|
+
@apply h-0;
|
|
36
|
+
@apply border-solid;
|
|
37
|
+
left: 50%;
|
|
38
|
+
bottom: -8px;
|
|
39
|
+
transform: translateX(-50%);
|
|
40
|
+
border-width: 10px 7px 0 7px;
|
|
41
|
+
border-color: theme("colors.primary-dark") transparent transparent transparent;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import React, { useState, useRef, useEffect } from "react"
|
|
2
|
+
import useKeyPress from "../helpers/useKeyPress"
|
|
3
|
+
import "./Tooltip.scss"
|
|
4
|
+
|
|
5
|
+
export interface TooltipProps {
|
|
6
|
+
className?: string
|
|
7
|
+
id: string
|
|
8
|
+
text: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface TooltipPosition {
|
|
12
|
+
top: number
|
|
13
|
+
left: number
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const Tooltip = ({ className, id, text, children }: React.PropsWithChildren<TooltipProps>) => {
|
|
17
|
+
const [position, setPosition] = useState<TooltipPosition | null>(null)
|
|
18
|
+
const childrenWrapperRef = useRef<HTMLDivElement>(null)
|
|
19
|
+
|
|
20
|
+
const show = () => {
|
|
21
|
+
const { x, y, width, height } = childrenWrapperRef.current?.getBoundingClientRect() || {}
|
|
22
|
+
|
|
23
|
+
if (x && y && width && height) {
|
|
24
|
+
setPosition({ top: y, left: x + width / 2 })
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const hide = () => setPosition(null)
|
|
29
|
+
|
|
30
|
+
useKeyPress("Escape", () => hide())
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
window.addEventListener("scroll", () => hide())
|
|
34
|
+
|
|
35
|
+
return () => {
|
|
36
|
+
window.removeEventListener("scroll", () => hide())
|
|
37
|
+
}
|
|
38
|
+
}, [])
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div
|
|
42
|
+
className={`tooltip ${className || ""}`}
|
|
43
|
+
onFocus={show}
|
|
44
|
+
onMouseEnter={show}
|
|
45
|
+
onBlur={hide}
|
|
46
|
+
onMouseLeave={hide}
|
|
47
|
+
>
|
|
48
|
+
<div
|
|
49
|
+
className={`tooltip__element ${position ? "tooltip__element--visible" : ""}`}
|
|
50
|
+
style={position || {}}
|
|
51
|
+
role="tooltip"
|
|
52
|
+
id={id}
|
|
53
|
+
data-test-id="tooltip-element"
|
|
54
|
+
>
|
|
55
|
+
{text}
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<div className="tooltip__children" data-test-id="tooltip-children" ref={childrenWrapperRef}>
|
|
59
|
+
{children}
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export { Tooltip as default, Tooltip }
|
package/src/blocks/ViewItem.tsx
CHANGED
|
@@ -23,14 +23,14 @@ const ViewItem = (props: ViewItemProps) => {
|
|
|
23
23
|
if (props.truncated) valueClassName += " is-truncated"
|
|
24
24
|
|
|
25
25
|
return (
|
|
26
|
-
<div id={props.id} className={viewItemClasses.join(" ")} data-
|
|
26
|
+
<div id={props.id} className={viewItemClasses.join(" ")} data-test-id={props.dataTestId}>
|
|
27
27
|
{props.label && (
|
|
28
28
|
<span className={`view-item__label ${props.error ? "text-alert text-sm" : ""}`}>
|
|
29
29
|
{props.label}
|
|
30
30
|
</span>
|
|
31
31
|
)}
|
|
32
32
|
{props.children && (
|
|
33
|
-
<span className={valueClassName} data-
|
|
33
|
+
<span className={valueClassName} data-test-id={props.dataTestId}>
|
|
34
34
|
{props.children}
|
|
35
35
|
</span>
|
|
36
36
|
)}
|
package/src/forms/Dropzone.tsx
CHANGED
|
@@ -59,7 +59,7 @@ const Dropzone = (props: DropzoneProps) => {
|
|
|
59
59
|
<progress className="dropzone__progress" max="100" value={props.progress}></progress>
|
|
60
60
|
) : (
|
|
61
61
|
<div className={dropzoneClasses.join(" ")} {...getRootProps()}>
|
|
62
|
-
<input id={props.id} {...getInputProps()} data-
|
|
62
|
+
<input id={props.id} {...getInputProps()} data-test-id={"dropzone-input"} />
|
|
63
63
|
{isDragActive ? (
|
|
64
64
|
<p>{props.strings?.dropHere ?? t("t.dropFilesHere")}</p>
|
|
65
65
|
) : (
|
package/src/forms/Field.tsx
CHANGED
package/src/forms/FieldGroup.tsx
CHANGED
|
@@ -63,8 +63,8 @@ const FieldGroup = ({
|
|
|
63
63
|
}: FieldGroupProps) => {
|
|
64
64
|
// Always default align two-option radio groups side by side
|
|
65
65
|
if (fields?.length === 2) {
|
|
66
|
-
fieldGroupClassName = `${fieldGroupClassName
|
|
67
|
-
fieldClassName = `${fieldClassName
|
|
66
|
+
fieldGroupClassName = `${fieldGroupClassName} flex`
|
|
67
|
+
fieldClassName = `${fieldClassName} flex-initial mr-4`
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
const [checkedInputs, setCheckedInputs] = useState<string[]>([])
|
|
@@ -82,7 +82,7 @@ const FieldGroup = ({
|
|
|
82
82
|
type={type}
|
|
83
83
|
id={item.id}
|
|
84
84
|
defaultValue={item.value || item.id}
|
|
85
|
-
name={subfieldsExist() || item.uniqueName ? `${name}-${item.value
|
|
85
|
+
name={subfieldsExist() || item.uniqueName ? `${name}-${item.value}` : name}
|
|
86
86
|
onClick={(e) => {
|
|
87
87
|
// We cannot reliably target an individual checkbox in a field group since they have the same name, so we keep track on our own
|
|
88
88
|
if (e.currentTarget.checked) {
|
|
@@ -95,12 +95,12 @@ const FieldGroup = ({
|
|
|
95
95
|
disabled={item.disabled}
|
|
96
96
|
ref={register(validation)}
|
|
97
97
|
{...item.inputProps}
|
|
98
|
-
data-
|
|
98
|
+
data-test-id={item.dataTestId ?? dataTestId}
|
|
99
99
|
/>
|
|
100
100
|
<label
|
|
101
101
|
htmlFor={item.id}
|
|
102
|
-
className={`font-semibold ${fieldLabelClassName
|
|
103
|
-
item.disabled
|
|
102
|
+
className={`font-semibold ${fieldLabelClassName} ${
|
|
103
|
+
item.disabled && "text-gray-600 cursor-not-allowed"
|
|
104
104
|
}`}
|
|
105
105
|
>
|
|
106
106
|
{item.label}
|
|
@@ -150,8 +150,8 @@ const FieldGroup = ({
|
|
|
150
150
|
{item.additionalText && checkedInputs.indexOf(item.label) >= 0 && (
|
|
151
151
|
<Field
|
|
152
152
|
id={item.id}
|
|
153
|
-
key={`${item.value
|
|
154
|
-
name={`${name}-${item.value
|
|
153
|
+
key={`${item.value}-additionalText`}
|
|
154
|
+
name={`${name}-${item.value}`}
|
|
155
155
|
register={register}
|
|
156
156
|
defaultValue={item.defaultText}
|
|
157
157
|
placeholder={strings?.description ?? t("t.description")}
|
|
@@ -168,12 +168,12 @@ const FieldGroup = ({
|
|
|
168
168
|
{groupLabel && <label className="text__caps-spaced">{groupLabel}</label>}
|
|
169
169
|
{groupNote && <p className="field-note mb-4">{groupNote}</p>}
|
|
170
170
|
|
|
171
|
-
<div className={`field ${error
|
|
171
|
+
<div className={`field ${error && "error"} ${fieldGroupClassName || ""} mb-0`}>
|
|
172
172
|
{fields?.map((item) => (
|
|
173
173
|
<div className={`field ${fieldClassName || ""} mb-1`} key={item.id}>
|
|
174
174
|
{getInputSet(item)}
|
|
175
175
|
{item.subFields && checkedInputs.indexOf(item.label) >= 0 && (
|
|
176
|
-
<div className={"ml-8"} key={`${item.value
|
|
176
|
+
<div className={"ml-8"} key={`${item.value}-subfields`}>
|
|
177
177
|
{item.subFields?.map((subItem) => {
|
|
178
178
|
return getInputSet(subItem)
|
|
179
179
|
})}
|
|
@@ -27,7 +27,7 @@ const HouseholdMemberForm = (props: HouseholdMemberFormProps) => {
|
|
|
27
27
|
className="edit-link"
|
|
28
28
|
onClick={() => props.editMember && props.editMember(props.memberId)}
|
|
29
29
|
type={"button"}
|
|
30
|
-
data-
|
|
30
|
+
data-test-id={"app-household-member-edit-button"}
|
|
31
31
|
>
|
|
32
32
|
{props.strings?.edit ?? t("t.edit")}
|
|
33
33
|
</button>
|
|
@@ -80,7 +80,7 @@ const MultiSelectField = (props: MultiSelectFieldProps) => {
|
|
|
80
80
|
return (
|
|
81
81
|
<div className="field multi-select-field">
|
|
82
82
|
{props.label && label}
|
|
83
|
-
<div className="control" data-
|
|
83
|
+
<div className="control" data-test-id={props.dataTestId}>
|
|
84
84
|
<Icon symbol="search" size="medium" />
|
|
85
85
|
<input
|
|
86
86
|
id={props.id}
|
package/src/forms/PhoneField.tsx
CHANGED
|
@@ -60,7 +60,7 @@ export const PhoneField = (props: {
|
|
|
60
60
|
{props.label}
|
|
61
61
|
</label>
|
|
62
62
|
)}
|
|
63
|
-
<div className={props.controlClassName} data-
|
|
63
|
+
<div className={props.controlClassName} data-test-id={props.dataTestId}>
|
|
64
64
|
{props.mask ? (
|
|
65
65
|
<Controller {...controllerProps} render={props.mask} />
|
|
66
66
|
) : (
|
|
@@ -68,7 +68,7 @@ export const PhoneField = (props: {
|
|
|
68
68
|
)}
|
|
69
69
|
</div>
|
|
70
70
|
{props.subNote && <p className="field-sub-note">{props.subNote}</p>}
|
|
71
|
-
<ErrorMessage id={`${props.id
|
|
71
|
+
<ErrorMessage id={`${props.id}-error`} error={props.error}>
|
|
72
72
|
{props.errorMessage}
|
|
73
73
|
</ErrorMessage>
|
|
74
74
|
</div>
|
package/src/forms/Select.tsx
CHANGED
|
@@ -60,8 +60,8 @@ export const Select = ({
|
|
|
60
60
|
className="input"
|
|
61
61
|
id={id || name}
|
|
62
62
|
name={name}
|
|
63
|
-
data-
|
|
64
|
-
aria-describedby={describedBy ? describedBy : `${id
|
|
63
|
+
data-test-id={dataTestId}
|
|
64
|
+
aria-describedby={describedBy ? describedBy : `${id}-error`}
|
|
65
65
|
aria-invalid={!!error || false}
|
|
66
66
|
aria-label={label}
|
|
67
67
|
ref={register && register(validation)}
|
|
@@ -79,7 +79,7 @@ export const Select = ({
|
|
|
79
79
|
</div>
|
|
80
80
|
{subNote && <p className="field-sub-note">{subNote}</p>}
|
|
81
81
|
{error && errorMessage && (
|
|
82
|
-
<ErrorMessage id={`${id
|
|
82
|
+
<ErrorMessage id={`${id}-error`} error={error}>
|
|
83
83
|
{errorMessage}
|
|
84
84
|
</ErrorMessage>
|
|
85
85
|
)}
|
package/src/forms/Textarea.tsx
CHANGED
|
@@ -57,7 +57,7 @@ export const Textarea = (props: TextareaProps) => {
|
|
|
57
57
|
wrap={props.wrap ?? "soft"}
|
|
58
58
|
title={props.label}
|
|
59
59
|
{...inputProps}
|
|
60
|
-
data-
|
|
60
|
+
data-test-id={props.dataTestId}
|
|
61
61
|
/>
|
|
62
62
|
{props.note && <p className="field-note font-normal mb-2">{props.note}</p>}
|
|
63
63
|
{props.errorMessage && <span className="textarea-error-message">{props.errorMessage}</span>}
|
package/src/headers/Hero.tsx
CHANGED
|
@@ -20,7 +20,7 @@ export interface HeroProps {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
const HeroButton = (props: { title: string; href: string; className?: string }) => (
|
|
23
|
-
<span className={
|
|
23
|
+
<span className={props.className + " hero__button"}>
|
|
24
24
|
<LinkButton href={props.href}>{props.title}</LinkButton>
|
|
25
25
|
</span>
|
|
26
26
|
)
|
|
@@ -44,7 +44,7 @@ const Hero = (props: HeroProps) => {
|
|
|
44
44
|
classNames = "centered"
|
|
45
45
|
}
|
|
46
46
|
return (
|
|
47
|
-
<div className={`hero ${classNames}`} style={styles} data-
|
|
47
|
+
<div className={`hero ${classNames}`} style={styles} data-test-id={"hero-component"}>
|
|
48
48
|
<h1 className={`hero__title ${props.extraLargeTitle ? "lg:text-6.5xl" : ""}`}>
|
|
49
49
|
{props.title}
|
|
50
50
|
</h1>
|
|
@@ -157,7 +157,7 @@ const SiteHeader = (props: SiteHeaderProps) => {
|
|
|
157
157
|
}
|
|
158
158
|
dropdownOptionKeyDown(event, index)
|
|
159
159
|
}}
|
|
160
|
-
data-
|
|
160
|
+
data-test-id={`${option.title}-${index}`}
|
|
161
161
|
>
|
|
162
162
|
{dropdownOptionContent(option)}
|
|
163
163
|
</button>
|
|
@@ -327,7 +327,7 @@ const SiteHeader = (props: SiteHeaderProps) => {
|
|
|
327
327
|
}`}
|
|
328
328
|
href={menuLink.href}
|
|
329
329
|
key={`${menuLink.title}-${index}`}
|
|
330
|
-
data-
|
|
330
|
+
data-test-id={`${menuLink.title}-${index}`}
|
|
331
331
|
>
|
|
332
332
|
{menuContent}
|
|
333
333
|
</LinkComponent>
|
|
@@ -367,7 +367,7 @@ const SiteHeader = (props: SiteHeaderProps) => {
|
|
|
367
367
|
onMouseEnter={() => changeMenuShow(menuLink.title, activeMenus, setActiveMenus)}
|
|
368
368
|
onMouseLeave={() => changeMenuShow(menuLink.title, activeMenus, setActiveMenus)}
|
|
369
369
|
role={"button"}
|
|
370
|
-
data-
|
|
370
|
+
data-test-id={`${menuLink.title}-${index}`}
|
|
371
371
|
>
|
|
372
372
|
{menuContent}
|
|
373
373
|
</span>
|
package/src/icons/Icon.tsx
CHANGED
|
@@ -171,7 +171,7 @@ const Icon = (props: IconProps) => {
|
|
|
171
171
|
<span
|
|
172
172
|
className={wrapperClasses.join(" ")}
|
|
173
173
|
aria-hidden={props.ariaHidden}
|
|
174
|
-
data-
|
|
174
|
+
data-test-id={props.dataTestId ?? null}
|
|
175
175
|
>
|
|
176
176
|
<SpecificIcon fill={props.fill ? props.fill : undefined} />
|
|
177
177
|
</span>
|
|
@@ -179,7 +179,7 @@ const Icon = (props: IconProps) => {
|
|
|
179
179
|
<span
|
|
180
180
|
className={wrapperClasses.join(" ")}
|
|
181
181
|
aria-hidden={props.ariaHidden}
|
|
182
|
-
data-
|
|
182
|
+
data-test-id={props.dataTestId ?? null}
|
|
183
183
|
style={{ color: props.fill }}
|
|
184
184
|
>
|
|
185
185
|
{SpecificIcon}
|