Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] - 여행 계획 등록 페이지 접근성 개선 #554

Merged
merged 17 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
00ec4aa
feat(TextField): 필수 항목이면 '필수 항목입니다'를 접근성 리더기가 읽어주는 기능 구현
jinyoung234 Oct 19, 2024
621747c
feat(TravelPlanRegisterPage): input을 enter 했을 때 캘린더가 열리는 것 구현
jinyoung234 Oct 19, 2024
97176b3
feat(TravelPlanRegisterPage): 캘린더가 열리고 닫힐 때 안내 메시지 추가
jinyoung234 Oct 20, 2024
cab03c8
feat(Calendar): 캘린더 이전, 이후 버튼 눌렀을 때 안내메시지 추가
jinyoung234 Oct 20, 2024
947d2f2
feat(Calendar): 캘린더 내 각 일을 선택 가능하도록 접근성 개선
jinyoung234 Oct 20, 2024
79e3c7e
feat(AccordionTrigger): 아코디언 버튼을 눌렀을 때 열림, 닫힘 상태 메시지 제공
jinyoung234 Oct 20, 2024
f237e65
feat(GoogleSearchPopup): 팝업이 열렸을 때 input이 포커스 간 후 접근성 메시지를 읽는 것 구현
jinyoung234 Oct 21, 2024
e075b6e
fix(GoogleSearchPopup): 자동완성 장소 항목을 엔터 했을 경우 런타임 에러 발생하는 부분 해결
jinyoung234 Oct 21, 2024
5a354ef
refactor(GoogleSearchPopup): 팝업 열렸을 때 다른 요소들이 스크린 리더기가 접근하지 못하도록 개선
jinyoung234 Oct 21, 2024
8e46fe5
refactor(AccordionTrigger): 아코디언 버튼 aria-label 추가
jinyoung234 Oct 21, 2024
80ee5cc
feat(PlaceTodoListItem): todo 삭제 버튼 aria-label 추가
jinyoung234 Oct 21, 2024
5541d25
feat: 등록 바텀 시트 등장할 때 focus trap 적용
jinyoung234 Oct 21, 2024
9eee3cb
fix: 전체 화면 탭이 적용되지 않는 문제 해결
jinyoung234 Oct 21, 2024
289f3a1
Merge branch 'develop/fe' into feature/fe/#538
jinyoung234 Oct 21, 2024
985cd7c
Merge branch 'develop/fe' into feature/fe/#538
jinyoung234 Oct 22, 2024
2f0a396
fix: ci 문제 해결
jinyoung234 Oct 22, 2024
860512c
Merge branch 'develop/fe' into feature/fe/#538
jinyoung234 Oct 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { css } from "@emotion/react";
import styled from "@emotion/styled";

export const Layout = styled.div`
Expand All @@ -19,3 +20,16 @@ export const TitleContainer = styled.div`
export const Title = styled.h2`
${({ theme }) => theme.typography.mobile.bodyBold}
`;

export const visualHiddenStyle = css`
overflow: hidden;
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;

white-space: nowrap;
clip: rect(0, 0, 0, 0);
`;
Comment on lines +24 to +35

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 리버가 VisualHidden 컴포넌트를 구현했더라고요 이후에 합치면 좋을 거 같아요!

Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,13 @@ const AccordionTrigger = ({ children, onDeleteItem }: AccordionTriggerProps) =>

return (
<S.Layout onClick={() => handleToggleAccordion(label)}>
<div aria-live="assertive" css={S.visualHiddenStyle}>
{isClosed ? "아코디언이 열렸습니다." : "아코디언이 닫혔습니다."}
</div>
<S.TitleContainer>
<button>{isClosed ? <UpArrow /> : <DownArrow />}</button>
<button aria-label={isClosed ? `아코디언 열기` : `아코디언 닫기`}>
{isClosed ? <UpArrow /> : <DownArrow />}
</button>
<S.Title>{children}</S.Title>
</S.TitleContainer>
<IconButton
Expand Down
13 changes: 13 additions & 0 deletions frontend/src/components/common/Calendar/Calendar.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,16 @@ export const WeekRow = styled.tr`
export const boldTextStyle = css`
font-weight: 700;
`;

export const visualHiddenStyle = css`
overflow: hidden;
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;

white-space: nowrap;
clip: rect(0, 0, 0, 0);
`;
Comment on lines +83 to +95

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도요!

53 changes: 47 additions & 6 deletions frontend/src/components/common/Calendar/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,21 @@ const Calendar = ({
weekdays,
} = useCalendar();

const isPreventPreviousMonthMoveButton = today.getMonth() === calendarDetail.month;

const handleKeyDown = (
event: React.KeyboardEvent<HTMLElement>,
date: Date,
isSelectable: boolean,
) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
if (isSelectable) {
onSelectDate(date);
}
}
};

return (
<S.Layout ref={calendarRef} {...props}>
<S.HeaderContainer>
Expand All @@ -43,17 +58,30 @@ const Calendar = ({
color={PRIMITIVE_COLORS.white}
iconType="prev-arrow"
onClick={prevMonth}
disabled={today.getMonth() === calendarDetail.month}
disabled={isPreventPreviousMonthMoveButton}
aria-label={"이전 달 이동 버튼"}
data-cy={CYPRESS_DATA_MAP.calendar.previousMonthMoveButton}
/>
<Text textType="detail" css={S.boldTextStyle} data-cy={CYPRESS_DATA_MAP.calendar.headTitle}>
{calendarDetail.year}년 {calendarDetail.month + 1}월

<Text
aria-live="polite"
textType="detail"
css={S.boldTextStyle}
data-cy={CYPRESS_DATA_MAP.calendar.headTitle}
>
{`${calendarDetail.year}년 ${calendarDetail.month + 1}월`}
{isPreventPreviousMonthMoveButton && (
<div aria-live="assertive" css={S.visualHiddenStyle}>
이전 달로 이동하는 버튼을 누를 수 없습니다.
</div>
)}
</Text>
<IconButton
size="12"
color={PRIMITIVE_COLORS.white}
iconType="next-arrow"
onClick={nextMonth}
aria-label="다음 달 이동 버튼"
data-cy={CYPRESS_DATA_MAP.calendar.nextMonthMoveButton}
/>
</S.HeaderContainer>
Expand All @@ -67,15 +95,28 @@ const Calendar = ({
<S.DaysGridContainer>
{calendarDetail.days.map(({ date, isCurrentMonth }) => {
const isSelectable = isCurrentMonth && date >= today;
const formattedDate = date.toLocaleDateString("ko-KR", {
year: "numeric",
month: "long",
day: "numeric",
});

return (
<S.DayCell
key={date.toString()}
$isCurrentMonth={isCurrentMonth}
$isSelectable={isSelectable}
onClick={() => isSelectable && onSelectDate(date)}
onKeyDown={(event) => handleKeyDown(event, date, isSelectable)}
tabIndex={isSelectable ? 0 : -1}
role="gridcell"
aria-selected={isSelectable}
aria-label={formattedDate}
data-cy={CYPRESS_DATA_MAP.calendar.dayCell}
$isCurrentMonth={isCurrentMonth}
$isSelectable={isSelectable}
>
<Text textType="detail">{isCurrentMonth ? date.getDate() : ""}</Text>
<Text tabIndex={-1} aria-hidden="true" textType="detail">
{isCurrentMonth ? date.getDate() : ""}
</Text>
</S.DayCell>
);
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ export const Layout = styled.div`
max-width: 48rem;

background-color: ${PRIMITIVE_COLORS.white};
transform: translateX(-3.2rem);
`;

export const StyledInput = styled.input`
Expand Down Expand Up @@ -106,3 +105,12 @@ export const ButtonContainer = styled.div`
margin-top: auto;
padding: 1.6rem;
`;

export const layoutStyle = css`
position: relative;

max-width: 48rem;
min-width: 28rem;
min-height: 100svh;
margin: 0 auto;
`;
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useCallback, useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";

import { Global, css } from "@emotion/react";

Expand All @@ -21,6 +22,12 @@ const GoogleSearchPopup = ({ onClosePopup, onSearchPlaceInfo }: GoogleSearchPopu
const [autocomplete, setAutocomplete] = useState<google.maps.places.Autocomplete | null>(null);
const inputRef = useRef<HTMLInputElement | null>(null);

useEffect(() => {
if (inputRef.current) {
inputRef.current.focus();
}
}, []);

const onLoadAutocomplete = (autocomplete: google.maps.places.Autocomplete) => {
setAutocomplete(autocomplete);

Expand All @@ -32,7 +39,7 @@ const GoogleSearchPopup = ({ onClosePopup, onSearchPlaceInfo }: GoogleSearchPopu
if (autocomplete !== null) {
const place = autocomplete.getPlace();

if (place.geometry && place.geometry.location && place.address_components) {
if (place && place.geometry && place.geometry.location && place.address_components) {
const newCenter = {
lat: place.geometry.location.lat(),
lng: place.geometry.location.lng(),
Expand Down Expand Up @@ -68,39 +75,43 @@ const GoogleSearchPopup = ({ onClosePopup, onSearchPlaceInfo }: GoogleSearchPopu
};
}, [onPlaceChanged]);

return (
<S.Layout data-cy={CYPRESS_DATA_MAP.googleSearchPopup.container}>
<Global styles={S.autocompleteStyles} />
<Autocomplete onLoad={onLoadAutocomplete} onPlaceChanged={onPlaceChanged}>
<S.InputContainer>
<S.StyledInput
ref={inputRef}
type="text"
placeholder="예) 영동대로 517, 삼성동 159"
data-cy={CYPRESS_DATA_MAP.googleSearchPopup.searchInput}
/>
</S.InputContainer>
</Autocomplete>
<S.TipContainer>
<p>tip</p>
<p>
도로명이나 지역명을 이용해서 검색해 보세요. 건물 번호, 번지를 함께 입력하지면 더욱 정확한
결과가 검색됩니다.
</p>
</S.TipContainer>

<S.ButtonContainer>
<Button
css={css`
width: 100%;
`}
onClick={onClosePopup}
variants="secondary"
>
취소
</Button>
</S.ButtonContainer>
</S.Layout>
return createPortal(
<div css={S.layoutStyle}>
<S.Layout data-cy={CYPRESS_DATA_MAP.googleSearchPopup.container}>
<Global styles={S.autocompleteStyles} />
<Autocomplete onLoad={onLoadAutocomplete} onPlaceChanged={onPlaceChanged}>
<S.InputContainer>
<S.StyledInput
ref={inputRef}
type="text"
placeholder="예) 영동대로 517, 삼성동 159"
data-cy={CYPRESS_DATA_MAP.googleSearchPopup.searchInput}
aria-label="장소 검색 입력창. 도로명, 지역명, 건물 번호 등을 입력하세요. 자동완성 결과가 나타나면 화살표 키로 원하는 장소를 선택할 수 있습니다."
/>
</S.InputContainer>
</Autocomplete>
<S.TipContainer>
<p>tip</p>
<p>
도로명이나 지역명을 이용해서 검색해 보세요. 건물 번호, 번지를 함께 입력하지면 더욱
정확한 결과가 검색됩니다.
</p>
</S.TipContainer>

<S.ButtonContainer>
<Button
css={css`
width: 100%;
`}
onClick={onClosePopup}
variants="secondary"
>
취소
</Button>
</S.ButtonContainer>
</S.Layout>
</div>,
document.body,
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,37 +24,40 @@ const EditRegisterModalBottomSheet = ({
onConfirm,
}: EditRegisterModalBottomSheetProps) => {
return (
<Modal isOpen={isOpen} onCloseModal={onClose} position="bottom" boxLayoutGap="xxxl">
<Modal.Header headerPosition="center">
<S.HandleBar />
</Modal.Header>
<Modal.Body direction="column" css={S.modalBodyStyle}>
<Tturi />
<S.TextContainer>
<Text textType="bodyBold">{mainText}</Text>
<Text textType="detail" css={S.subTextStyle}>
{subText}
</Text>
</S.TextContainer>
</Modal.Body>
<Modal.Footer>
<Button
variants="secondary"
onClick={onClose}
data-cy={CYPRESS_DATA_MAP.modalBottomSheet.closeButton}
>
취소
</Button>
<Button
variants="primary"
onClick={onConfirm}
disabled={isPending}
data-cy={CYPRESS_DATA_MAP.modalBottomSheet.confirmButton}
>
{isPending ? <Spinner variants="circle" size={20} /> : "확인"}
</Button>
</Modal.Footer>
</Modal>
isOpen && (
<Modal isOpen={isOpen} onCloseModal={onClose} position="bottom" boxLayoutGap="xxxl">
<Modal.Header headerPosition="center">
<S.HandleBar />
</Modal.Header>
<Modal.Body direction="column" css={S.modalBodyStyle}>
<Tturi />
<S.TextContainer>
<Text textType="bodyBold">{mainText}</Text>
<Text textType="detail" css={S.subTextStyle}>
{subText}
</Text>
</S.TextContainer>
</Modal.Body>

<Modal.Footer>
<Button
variants="secondary"
onClick={onClose}
data-cy={CYPRESS_DATA_MAP.modalBottomSheet.closeButton}
>
취소
</Button>
<Button
variants="primary"
onClick={onConfirm}
disabled={isPending}
data-cy={CYPRESS_DATA_MAP.modalBottomSheet.confirmButton}
>
{isPending ? <Spinner variants="circle" size={20} /> : "확인"}
</Button>
</Modal.Footer>
</Modal>
)
);
};

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/common/Modal/Modal.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import React from "react";
import ReactDOM from "react-dom";

import FocusTrap from "@components/common/FocusTrap";
import ModalBody from "@components/common/Modal/ModalBody/ModalBody";
import ModalFooter from "@components/common/Modal/ModalFooter/ModalFooter";
import ModalHeader from "@components/common/Modal/ModalHeader/ModalHeader";

import useBottomSheet from "@hooks/useBottomSheet";
import useModalControl from "@hooks/useModalControl";

import FocusTrap from "../FocusTrap";
import * as S from "./Modal.style";
import { GapSize } from "./Modal.type";

Expand Down
13 changes: 13 additions & 0 deletions frontend/src/components/common/TextField/TextField.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,16 @@ export const TextContainer = styled.div`
export const symbolStyle = css`
color: ${theme.colors.text.required};
`;

export const visualHiddenStyle = css`
overflow: hidden;
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;

white-space: nowrap;
clip: rect(0, 0, 0, 0);
`;
Comment on lines +34 to +45

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분도요!

Loading
Loading