Skip to content

Commit 1258bfa

Browse files
committed
remove focus first for screenreaders, style tweaks
1 parent 3898967 commit 1258bfa

File tree

3 files changed

+95
-97
lines changed

3 files changed

+95
-97
lines changed

src/components/Card.tsx

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,6 @@ const StepCard = ({
245245
overlayChildren,
246246
...otherProps }: StepCardProps) => {
247247

248-
// Helps to stop focusing first child when is already focused
249-
const [previousFocusedElement, setPreviousFocusedElement] = useState<HTMLElement | null>(null);
250248
const overlayRef = useRef<HTMLDivElement>(null);
251249
const [showOverlay, setShowOverlay] = useState<boolean>(false);
252250

@@ -260,20 +258,9 @@ const StepCard = ({
260258
}
261259
};
262260

263-
const handleOverlayFocus = useCallback((event: FocusEvent) => {
261+
const handleOverlayFocus = useCallback(() => {
264262
setShowOverlay(true);
265-
const firstOverlayFocusableElement = document.getElementById('overlay-element')?.querySelector(
266-
'button, [href], input, select, textarea'
267-
) as HTMLElement;
268-
269-
if (
270-
(firstOverlayFocusableElement !== previousFocusedElement) &&
271-
(event.target === overlayRef.current)
272-
) {
273-
setPreviousFocusedElement(firstOverlayFocusableElement);
274-
firstOverlayFocusableElement.focus();
275-
}
276-
}, [overlayRef, previousFocusedElement]);
263+
}, []);
277264

278265
const hideFocusableElements = useCallback(() => {
279266
const focusableElements = Array.from(document.getElementById("step-card")?.querySelectorAll(

src/components/Exercise/styles.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@ import { colors } from "../../theme";
22
import { css } from "styled-components";
33

44
export const exerciseStyles = css`
5-
65
&.is-selected {
76
background-color: ${colors.card.header.background};
8-
9-
.step-card-footer-inner,
10-
.step-card-body,
11-
.step-card-header,
7+
8+
.step-card-footer-inner,
9+
.step-card-body,
10+
.step-card-header,
1211
.answer-letter-wrapper::before {
1312
background-color: ${colors.card.header.background} !important;
1413
}
@@ -17,6 +16,10 @@ export const exerciseStyles = css`
1716
&.preview-card {
1817
--spacing: 0.8rem;
1918
19+
[data-task-step-id] {
20+
padding: 0;
21+
}
22+
2023
.step-card-header,
2124
.step-card-body {
2225
background-color: ${colors.palette.white};
@@ -86,6 +89,12 @@ export const exerciseStyles = css`
8689
}
8790
}
8891
92+
&.has-correct-answer .answer-correct:not(.answer-selected) .answer-label .answer-letter-wrapper:before {
93+
color: ${colors.palette.white};
94+
border-color: ${colors.answer.correct};
95+
background: ${colors.answer.correct};
96+
}
97+
8998
.question-feedback-content {
9099
font-size: 1.6rem;
91100
}
@@ -122,5 +131,7 @@ export const exerciseStyles = css`
122131
font-weight: bold;
123132
font-size: 1.6rem;
124133
}
134+
135+
125136
}
126137
`;

src/components/ExercisePreview.tsx

Lines changed: 77 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -4,92 +4,92 @@ import { IncludeRemoveQuestion } from "./IncludeRemoveQuestion";
44
import { Exercise } from "./Exercise";
55

66
export interface ExercisePreviewProps {
7-
exercise: ExerciseData;
8-
selected: boolean;
9-
onIncludeHandler: () => void;
10-
onRemoveHandler: () => void;
11-
onClickDetails: () => void;
12-
enableOverlay?: boolean;
7+
exercise: ExerciseData;
8+
selected: boolean;
9+
onIncludeHandler: () => void;
10+
onRemoveHandler: () => void;
11+
onClickDetails: () => void;
12+
enableOverlay?: boolean;
1313
}
1414

15-
/**
15+
/**
1616
* An Exercise version with less interaction with card and grants an Overlay with Include/Remove component
17-
*/
17+
*/
1818
export const ExercisePreview = (
19-
{
20-
exercise,
21-
selected,
22-
onIncludeHandler,
23-
onRemoveHandler,
24-
onClickDetails,
25-
enableOverlay = false,
26-
}: ExercisePreviewProps) => {
19+
{
20+
exercise,
21+
selected,
22+
onIncludeHandler,
23+
onRemoveHandler,
24+
onClickDetails,
25+
enableOverlay = false,
26+
}: ExercisePreviewProps) => {
2727

28-
const exercisePreviewProps = (exercise: ExerciseData) => {
29-
const formatAnswerData = (questions: ExerciseQuestionData[]) => questions.map((q) => (
30-
{ id: q.id, correct_answer_id: (q.answers.find((a) => a.correctness === '1.0')?.id || '') }));
28+
const exercisePreviewProps = (exercise: ExerciseData) => {
29+
const formatAnswerData = (questions: ExerciseQuestionData[]) => questions.map((q) => (
30+
{ id: q.id, correct_answer_id: (q.answers.find((a) => a.correctness === '1.0')?.id || '') }));
3131

32-
const questionStateFields = {
33-
available_points: '1.0',
34-
is_completed: true,
35-
answer_id: '1',
36-
free_response: '',
37-
feedback_html: '',
38-
correct_answer_feedback_html: '',
39-
attempts_remaining: 0,
40-
attempt_number: 1,
41-
incorrectAnswerId: 0
42-
}
32+
const questionStateFields = {
33+
available_points: '1.0',
34+
is_completed: true,
35+
answer_id: '1',
36+
free_response: '',
37+
feedback_html: '',
38+
correct_answer_feedback_html: '',
39+
attempts_remaining: 0,
40+
attempt_number: 1,
41+
incorrectAnswerId: 0
42+
}
4343

44-
const questionStates = formatAnswerData(exercise.questions).reduce((acc, answer) => {
45-
const { id, correct_answer_id } = answer;
46-
return { ...acc, [id]: { ...questionStateFields, correct_answer_id } };
47-
}, {});
44+
const questionStates = formatAnswerData(exercise.questions).reduce((acc, answer) => {
45+
const { id, correct_answer_id } = answer;
46+
return { ...acc, [id]: { ...questionStateFields, correct_answer_id } };
47+
}, {});
4848

49-
const step: StepBase = {
50-
id: 1,
51-
uid: exercise.uid,
52-
available_points: '1.0',
53-
};
49+
const step: StepBase = {
50+
id: 1,
51+
uid: exercise.uid,
52+
available_points: '1.0',
53+
};
5454

55-
return {
56-
canAnswer: true,
57-
needsSaved: true,
58-
hasMultipleAttempts: false,
59-
onAnswerChange: () => undefined,
60-
onAnswerSave: () => undefined,
61-
onNextStep: () => undefined,
62-
apiIsPending: false,
63-
canUpdateCurrentStep: false,
64-
step: step,
65-
questionNumber: exercise.number as number,
66-
numberOfQuestions: exercise.questions.length,
67-
questionStates: questionStates,
68-
show_all_feedback: false, // Hide all feedback
69-
};
55+
return {
56+
canAnswer: true,
57+
needsSaved: true,
58+
hasMultipleAttempts: false,
59+
onAnswerChange: () => undefined,
60+
onAnswerSave: () => undefined,
61+
onNextStep: () => undefined,
62+
apiIsPending: false,
63+
canUpdateCurrentStep: false,
64+
step: step,
65+
questionNumber: exercise.number as number,
66+
numberOfQuestions: exercise.questions.length,
67+
questionStates: questionStates,
68+
show_all_feedback: false, // Hide all feedback
7069
};
70+
};
7171

72-
const includeRemoveQuestionComponent = React.useMemo(() =>
73-
<IncludeRemoveQuestion
74-
buttonVariant={selected ? 'remove' : 'include'}
75-
onIncludeHandler={onIncludeHandler}
76-
onRemoveHandler={onRemoveHandler}
77-
onClickDetails={onClickDetails}
78-
/>
79-
, [selected, onIncludeHandler, onRemoveHandler, onClickDetails]);
72+
const includeRemoveQuestionComponent = React.useMemo(() =>
73+
<IncludeRemoveQuestion
74+
buttonVariant={selected ? 'remove' : 'include'}
75+
onIncludeHandler={onIncludeHandler}
76+
onRemoveHandler={onRemoveHandler}
77+
onClickDetails={onClickDetails}
78+
/>
79+
, [selected, onIncludeHandler, onRemoveHandler, onClickDetails]);
8080

81-
return (
82-
<Exercise
83-
exercise={exercise}
84-
className={selected ? 'preview-card is-selected' : 'preview-card'}
85-
{
86-
...(enableOverlay
87-
? {
88-
overlayChildren: includeRemoveQuestionComponent,
89-
}
90-
: {})
91-
}
92-
{...exercisePreviewProps(exercise)}
93-
/>
94-
);
95-
};
81+
return (
82+
<Exercise
83+
exercise={exercise}
84+
className={selected ? 'preview-card is-selected' : 'preview-card'}
85+
{
86+
...(enableOverlay
87+
? {
88+
overlayChildren: includeRemoveQuestionComponent,
89+
}
90+
: {})
91+
}
92+
{...exercisePreviewProps(exercise)}
93+
/>
94+
);
95+
};

0 commit comments

Comments
 (0)