diff --git a/a11y/index.html b/a11y/index.html
index 12fa3e7..8fd9bcf 100644
--- a/a11y/index.html
+++ b/a11y/index.html
@@ -1,16 +1,13 @@
-
-
-
-
-
-
-
- Accessibility
-
-
-
-
-
-
-
+
+
+
+
+
+
+ Accessibility
+
+
+
+
+
diff --git a/a11y/package.json b/a11y/package.json
index 1148c94..9396d14 100644
--- a/a11y/package.json
+++ b/a11y/package.json
@@ -4,7 +4,7 @@
"version": "0.0.0",
"type": "module",
"scripts": {
- "dev": "vite",
+ "dev": "vite --host",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
diff --git a/a11y/src/App.tsx b/a11y/src/App.tsx
index a8159f9..b8fecc8 100644
--- a/a11y/src/App.tsx
+++ b/a11y/src/App.tsx
@@ -6,11 +6,11 @@ import FlightBooking from "./components/FlightBooking";
function App() {
return (
);
}
diff --git a/a11y/src/components/FlightBooking.css b/a11y/src/components/FlightBooking.css
index d9d6083..5ae3543 100644
--- a/a11y/src/components/FlightBooking.css
+++ b/a11y/src/components/FlightBooking.css
@@ -34,7 +34,7 @@
width: 30px;
height: 30px;
border-radius: 16px;
- border: 1px solid #C0C0C0;
+ border: 1px solid #c0c0c0;
background-color: #fff;
cursor: pointer;
display: flex;
@@ -61,3 +61,17 @@
border-radius: 4px;
cursor: pointer;
}
+
+.visually-hidden {
+ overflow: hidden;
+ white-space: nowrap;
+ clip: rect(1px, 1px, 1px, 1px);
+ -webkit-clip-path: inset(50%);
+ clip-path: inset(50%);
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ margin: 0;
+ padding: 0;
+ border: 0;
+}
diff --git a/a11y/src/components/FlightBooking.tsx b/a11y/src/components/FlightBooking.tsx
index 313cab3..b2bf3dc 100644
--- a/a11y/src/components/FlightBooking.tsx
+++ b/a11y/src/components/FlightBooking.tsx
@@ -1,19 +1,15 @@
-import { useState } from "react";
-
import "./FlightBooking.css";
-const MAX_PASSENGERS = 3;
+import useAdultCount from "../hooks/useAdultCount";
const FlightBooking = () => {
- const [adultCount, setAdultCount] = useState(1);
-
- const incrementCount = () => {
- setAdultCount((prev) => Math.min(MAX_PASSENGERS, prev + 1));
- };
-
- const decrementCount = () => {
- setAdultCount((prev) => Math.max(1, prev - 1));
- };
+ const {
+ adultCount,
+ incrementCount,
+ decrementCount,
+ alertMessage,
+ messageForATUser,
+ } = useAdultCount();
return (
@@ -21,15 +17,38 @@ const FlightBooking = () => {
성인
-
+ {alertMessage && (
+
+ {alertMessage}
+
+ )}
항공편 검색
);
diff --git a/a11y/src/hooks/useAdultCount.ts b/a11y/src/hooks/useAdultCount.ts
new file mode 100644
index 0000000..9c93e4d
--- /dev/null
+++ b/a11y/src/hooks/useAdultCount.ts
@@ -0,0 +1,49 @@
+import { useState } from "react";
+import useDebouncedATMessage from "./useDebouncedATMessage";
+
+const MAX_PASSENGERS = 3;
+
+const useAdultCount = () => {
+ const [adultCount, setAdultCount] = useState(1);
+ const [alertMessage, setAlertMessage] = useState("");
+ const { handleDebouncedMessage, messageForATUser } =
+ useDebouncedATMessage(200);
+
+ const incrementCount = () => {
+ if (adultCount + 1 > MAX_PASSENGERS) {
+ alert("더이상 승객을 추가할 수 없습니다.");
+ setAlertMessage("더이상 승객을 추가할 수 없습니다.");
+ return;
+ }
+ if (alertMessage) {
+ setAlertMessage("");
+ }
+
+ handleDebouncedMessage(`성인 승객 수는 ${adultCount + 1}명 입니다.`);
+ setAdultCount((prev) => Math.min(MAX_PASSENGERS, prev + 1));
+ };
+
+ const decrementCount = () => {
+ if (adultCount === 1) {
+ alert("승객은 최소 1명 이상이어야 합니다.");
+ setAlertMessage("승객은 최소 1명 이상이어야 합니다.");
+ return;
+ }
+ if (alertMessage) {
+ setAlertMessage("");
+ }
+
+ handleDebouncedMessage(`성인 승객 수는 ${adultCount - 1}명 입니다.`);
+ setAdultCount((prev) => Math.max(1, prev - 1));
+ };
+
+ return {
+ adultCount,
+ incrementCount,
+ decrementCount,
+ alertMessage,
+ messageForATUser,
+ };
+};
+
+export default useAdultCount;
diff --git a/a11y/src/hooks/useDebounce.ts b/a11y/src/hooks/useDebounce.ts
new file mode 100644
index 0000000..320d44e
--- /dev/null
+++ b/a11y/src/hooks/useDebounce.ts
@@ -0,0 +1,25 @@
+import { useCallback, useRef } from "react";
+
+const useDebounce = ) => void>(
+ func: T,
+ delayTime: number
+) => {
+ const debounceRef = useRef | null>(null);
+
+ const debouncedCallback = useCallback(
+ (...args: Parameters) => {
+ if (debounceRef.current) {
+ clearTimeout(debounceRef.current);
+ }
+
+ debounceRef.current = setTimeout(() => {
+ func(...args);
+ }, delayTime);
+ },
+ [func, delayTime]
+ );
+
+ return debouncedCallback;
+};
+
+export default useDebounce;
diff --git a/a11y/src/hooks/useDebouncedATMessage.ts b/a11y/src/hooks/useDebouncedATMessage.ts
new file mode 100644
index 0000000..f0cbfa2
--- /dev/null
+++ b/a11y/src/hooks/useDebouncedATMessage.ts
@@ -0,0 +1,22 @@
+import { useState } from "react";
+import useDebounce from "./useDebounce";
+
+const MESSAGE_MAINTAIN_TIME = 500;
+
+const useDebouncedATMessage = (delayTime: number) => {
+ const [messageForATUser, setMessageForATUser] = useState("");
+
+ const handleDebouncedMessage = useDebounce((message: string) => {
+ setMessageForATUser(message);
+ setTimeout(() => {
+ setMessageForATUser("");
+ }, MESSAGE_MAINTAIN_TIME);
+ }, delayTime);
+
+ return {
+ messageForATUser,
+ handleDebouncedMessage,
+ };
+};
+
+export default useDebouncedATMessage;