Skip to content

Commit d577b50

Browse files
authored
Merge pull request ucfopen#1079 from ewainberg/issue/1067-add-tooltip-widget
Converts popover from the issues table into a widget
2 parents e95b69c + eb87ba2 commit d577b50

File tree

9 files changed

+260
-194
lines changed

9 files changed

+260
-194
lines changed

assets/js/Components/Icons/FilledInfoIcon.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React from 'react';
2-
3-
export default function FilledInfoIcon({ circleColor = "var(--link-color)", iconColor = "#fff", ...props }) {
2+
export default function FilledInfoIcon({ circleColor = "var(--link-color)", iconColor = "var(--white)", ...props }) {
43
return (
54
<svg
65
xmlns="http://www.w3.org/2000/svg"

assets/js/Components/Reports/IssuesTable.css

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4,68 +4,6 @@
44
gap: 6px;
55
}
66

7-
.issue-info-btn {
8-
border: none;
9-
background: none;
10-
cursor: pointer;
11-
padding: 0;
12-
margin-left: 4px;
13-
display: flex;
14-
align-items: center;
15-
line-height: 1;
16-
border-radius: 50%;
17-
transition: box-shadow 0.15s, background 0.15s;
18-
}
19-
20-
.issue-info-btn:hover,
21-
.issue-info-btn:focus {
22-
background: #e3f0fc;
23-
box-shadow: 0 0 0 3px var(--link-color-hover);
24-
outline: none;
25-
}
26-
27-
.icon-info {
28-
transition: filter 0.15s;
29-
}
30-
31-
.issue-info-btn:hover .icon-info,
32-
.issue-info-btn:focus .icon-info {
33-
filter: brightness(1.2) drop-shadow(0 2px 4px #1976d244);
34-
}
35-
36-
.issue-info-popover {
37-
position: fixed;
38-
inset: unset;
39-
z-index: 1000;
40-
background: #fff;
41-
border: 1px solid #ccc;
42-
border-radius: 6px;
43-
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
44-
padding: 12px 16px;
45-
min-width: 220px;
46-
max-width: 320px;
47-
font-size: 0.95em;
48-
outline: none;
49-
}
50-
51-
.issue-info-popover::backdrop {
52-
background: rgba(0,0,0,0.2); /* Slight dim, no blur */
53-
backdrop-filter: none;
54-
}
55-
56-
.issue-info-popover-content {
57-
margin-bottom: 8px;
58-
}
59-
60-
.issue-info-popover-close {
61-
border: none;
62-
background: none;
63-
color: var(--link-color);
64-
cursor: pointer;
65-
font-size: 1em;
66-
float: right;
67-
}
68-
697
.sr-only {
708
position: absolute !important;
719
left: -9999px !important;
Lines changed: 5 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { useState, useEffect, useRef } from 'react'
22
import SortableTable from '../Widgets/SortableTable'
33
import { formNameFromRule } from '../../Services/Ufixit'
4-
import InfoIcon from '../Icons/FilledInfoIcon'
4+
import InfoPopover from '../Widgets/InfoPopover'
55
import './IssuesTable.css'
66

77
export default function IssuesTable({
@@ -33,13 +33,6 @@ export default function IssuesTable({
3333
})
3434
const [localIssues, setLocalIssues] = useState([])
3535
const [rows, setRows] = useState([])
36-
const [popover, setPopover] = useState({ open: false, content: '', x: 0, y: 0 });
37-
const popoverContentRef = useRef(null);
38-
const lastButtonRef = useRef(null);
39-
const [ariaLive, setAriaLive] = useState('');
40-
const closeButtonRef = useRef(null);
41-
42-
const dialogRef = useRef(null);
4336

4437
const sortContent = () => {
4538
let tempRows = (issues) ? Object.values(localIssues) : []
@@ -49,7 +42,6 @@ export default function IssuesTable({
4942
let aValue = a[sortBy]
5043
let bValue = b[sortBy]
5144

52-
// If sorting by label, use labelText for comparison
5345
if (sortBy === "label") {
5446
aValue = a.labelText || ""
5547
bValue = b.labelText || ""
@@ -77,31 +69,6 @@ export default function IssuesTable({
7769
setRows(sortContent())
7870
}, [tableSettings, localIssues])
7971

80-
useEffect(() => {
81-
if (popover.open && dialogRef.current) {
82-
if (!dialogRef.current.open) {
83-
dialogRef.current.showModal();
84-
}
85-
if (closeButtonRef.current) {
86-
closeButtonRef.current.focus();
87-
}
88-
setAriaLive(popover.content);
89-
90-
const close = () => setPopover(p => ({ ...p, open: false }));
91-
window.addEventListener('click', close);
92-
return () => window.removeEventListener('click', close);
93-
} else if (dialogRef.current && dialogRef.current.open) {
94-
dialogRef.current.close();
95-
}
96-
}, [popover.open, popover.content]);
97-
98-
// When popover closes, return focus to the last info button
99-
useEffect(() => {
100-
if (!popover.open && lastButtonRef.current) {
101-
lastButtonRef.current.focus();
102-
}
103-
}, [popover.open]);
104-
10572
useEffect(() => {
10673
if (issues) {
10774
let tempIssues = Object.values(issues)
@@ -121,31 +88,10 @@ export default function IssuesTable({
12188
issue.label = (
12289
<span className="issue-label">
12390
{label}
124-
<button
125-
type="button"
126-
title={t('report.button.issue_tooltip')}
127-
aria-haspopup="dialog"
128-
aria-expanded={popover.open}
129-
aria-controls={popover.open ? "issue-info-popover" : undefined}
130-
className="issue-info-btn"
131-
ref={el => {
132-
if (popover.open) return;
133-
lastButtonRef.current = el;
134-
}}
135-
onClick={e => {
136-
e.stopPropagation();
137-
const rect = e.target.getBoundingClientRect();
138-
setPopover({
139-
open: true,
140-
content: t(`form.${formName}.summary`),
141-
x: rect.right + window.scrollX + 8,
142-
y: rect.top + window.scrollY - 120,
143-
});
144-
lastButtonRef.current = e.target;
145-
}}
146-
>
147-
<InfoIcon width={18} height={18} className="icon-info" circleColor="var(--link-color)" iconColor="#fff" />
148-
</button>
91+
<InfoPopover
92+
t={t}
93+
content={t(`form.${formName}.summary`)}
94+
/>
14995
</span>
15096
)
15197
issue.summary = t(`form.${formName}.summary`)
@@ -155,7 +101,6 @@ export default function IssuesTable({
155101
return issue
156102
}))
157103

158-
// Merge the issues with the same labels
159104
let mergedIssues = []
160105
let labels = []
161106
tempIssues.forEach((issue) => {
@@ -197,42 +142,6 @@ export default function IssuesTable({
197142
handleTableSettings={handleTableSettings}
198143
t={t}
199144
/>
200-
{/* ARIA for screen readers */}
201-
<div aria-live="polite" className="sr-only">
202-
{ariaLive}
203-
</div>
204-
{popover.open && (
205-
<dialog
206-
id="issue-info-popover"
207-
ref={dialogRef}
208-
className="issue-info-popover"
209-
style={{
210-
left: popover.x,
211-
top: popover.y,
212-
}}
213-
tabIndex={0}
214-
aria-labelledby="issue-info-popover-title"
215-
aria-describedby="issue-info-popover-content"
216-
onClick={e => e.stopPropagation()}
217-
>
218-
<div
219-
id="issue-info-popover-content"
220-
className="issue-info-popover-content"
221-
tabIndex={-1}
222-
ref={popoverContentRef}
223-
>
224-
{popover.content}
225-
</div>
226-
<button
227-
type="button"
228-
className="issue-info-popover-close"
229-
ref={closeButtonRef}
230-
onClick={() => setPopover({ ...popover, open: false })}
231-
>
232-
{t('fix.button.close_learn_more')}
233-
</button>
234-
</dialog>
235-
)}
236145
</>
237146
)
238147
}

assets/js/Components/ReportsPage.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,6 @@ export default function ReportsPage({t, report, settings, quickSearchTerm}) {
254254
<div className="flex-column w-100 flex-shrink-1 flex-grow-1">
255255
{ showChart && (
256256
<div className="mt-4">
257-
<div className="flex-row w-100 justify-content-center">
258-
<h2 className="primary-dark mt-0 mb-2">{t('report.title.barriers_remaining')}</h2>
259-
</div>
260257
<div id="resolutionsReport" className="graph-container">
261258
<ResolutionsReport t={t} reports={reports}/>
262259
</div>

assets/js/Components/Widgets/Combobox.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
.combo-input {
3030
background-color: var(--white);
31+
display: block;
3132
font-size: .85em;
3233
padding: .4em .15em .4em .5em;
3334
border: 1px solid var(--border-color);

assets/js/Components/Widgets/FixIssuesContentPreview.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export default function FixIssuesContentPreview({
8989
}
9090

9191
const addPreviewHelperElements = (doc, errorElement) => {
92-
if(!activeIssue || !doc) {
92+
if(!activeIssue || !doc || !errorElement) {
9393
return doc
9494
}
9595

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
.info-label {
2+
display: inline-flex;
3+
align-items: center;
4+
gap: 6px;
5+
}
6+
7+
.info-popover-btn {
8+
border: none;
9+
background: none;
10+
cursor: pointer;
11+
padding: 0;
12+
margin-inline-start: 4px;
13+
display: flex;
14+
align-items: center;
15+
line-height: 1;
16+
border-radius: 50%;
17+
}
18+
19+
.info-popover-btn:hover,
20+
.info-popover-btn:focus {
21+
outline: 2px solid var(--focus-color);
22+
outline-offset: 1px;
23+
}
24+
25+
.icon-info {
26+
transition: filter var(--transition-time);
27+
}
28+
29+
.info-popover-btn:hover .icon-info,
30+
.info-popover-btn:focus .icon-info {
31+
filter: brightness(var(--hover-brightness));
32+
}
33+
34+
/* The popover dialog itself */
35+
.info-popover-dialog {
36+
position: fixed;
37+
inset: unset;
38+
z-index: 1000;
39+
background: var(--white);
40+
border: 1px solid var(--border-color);
41+
border-radius: 6px;
42+
padding: 12px 16px;
43+
min-width: 220px;
44+
max-width: 320px;
45+
outline: none;
46+
}
47+
48+
.info-popover-dialog::backdrop {
49+
background: var(--backdrop-color);
50+
backdrop-filter: none;
51+
}
52+
53+
.info-popover-content {
54+
margin-bottom: 8px;
55+
text-decoration: none !important;
56+
font-size: 1.1em !important;
57+
color: var(--text-color) !important;
58+
font-weight: normal !important;
59+
}
60+
61+
.info-popover-close {
62+
border: none;
63+
background: none;
64+
color: var(--link-color);
65+
cursor: pointer;
66+
font-size: 1em;
67+
float: right;
68+
}
69+
70+
/* Screen reader-only utility */
71+
.sr-only {
72+
position: absolute !important;
73+
left: -9999px !important;
74+
height: 1px;
75+
width: 1px;
76+
overflow: hidden;
77+
clip: rect(1px, 1px, 1px, 1px);
78+
white-space: nowrap;
79+
}

0 commit comments

Comments
 (0)