mobile-react-infinite-calendar
v1.2.1
Published
A mobile-optimized infinite scroll calendar component for React
Maintainers
Readme
React Infinite Calendar Mobile
모바일 최적화된 무한 스크롤 캘린더 컴포넌트 (한국 공휴일 지원)
A mobile-optimized infinite scroll calendar component for React with Korean holidays support.
특징
- 🔄 무한 스크롤: 월간 부드러운 무한 스크롤
- 📱 모바일 최적화: 터치 친화적 디자인과 반응형 레이아웃
- 🎯 자동 포커스: IntersectionObserver를 통한 자동 월 감지
- 📅 날짜 선택기: 내장된 연도/월 드롭다운 선택기
- 🎉 한국 공휴일 지원: API 키 설정으로 한국 공휴일 표시
- 🚀 동적 이벤트 로딩: API 기반 스마트 이벤트 로딩 및 캐싱
- 🎨 커스터마이징: 유연한 테마 및 스타일 옵션
- 🌐 다국어 지원: 여러 언어 지원 (ko, en, ja, zh, de, fr, it, es)
- ⚡ 고성능: 가상화 렌더링으로 부드러운 성능
- 🔧 최적화된 상태 관리: 격리된 로컬 상태로 성능 최적화
- 📦 TypeScript: 완벽한 TypeScript 지원
- 🏗️ 모듈러 아키텍처: 비즈니스 로직과 UI 완전 분리
- 🌐 브라우저 호환성: 모던 브라우저 및 Safari 12.1+ 지원
설치
npm install mobile-react-infinite-calendarPeer Dependencies
다음 패키지들이 설치되어 있어야 합니다:
npm install react react-dom date-fns브라우저 호환성
✅ 지원 브라우저
| 브라우저 | 최소 버전 | 비고 | | -------------- | --------- | ----------------- | | Chrome | 58+ | 완전 지원 | | Firefox | 55+ | 완전 지원 | | Safari | 12.1+ | 완전 지원 | | iOS Safari | 12.2+ | 모바일 최적화 | | Edge | 79+ | 완전 지원 |
🔑 핵심 기능 호환성
- ✅ IntersectionObserver: Safari 12.1+ 지원
- ✅ CSS Grid/Flexbox: 모든 모던 브라우저
- ✅ Touch Events: 모바일 Safari 완전 지원
- ✅ Date API: 네이티브 JavaScript Date 사용
📱 모바일 Safari 최적화
이 패키지는 모바일 Safari에서 발생할 수 있는 터치 이슈들을 미리 방지합니다:
- ✅ Passive Scroll Events: 터치 성능 최적화
- ✅ Bounce Effect 제어: iOS 스크롤 바운스 효과 처리
- ✅ Touch Scrolling:
-webkit-overflow-scrolling: touch적용 - ✅ 주소창 동적 높이: 자동 높이 계산으로 대응
터치 최적화 기능:
- 🚫 스크롤 바운스 중 무한 로딩 방지
- ⚡ 하드웨어 가속 스크롤 활성화
- 📏 동적 뷰포트 높이 자동 대응
- 🎯 버튼/셀렉트 터치 최적화:
- 최소 44px 터치 타겟 크기 보장
touch-action: manipulation으로 더블탭 지연 제거- 모바일에서 hover 효과 자동 비활성화
- iOS 하이라이트 제거
빠른 시작
import { InfiniteCalendar } from "mobile-react-infinite-calendar";
// 가장 간단한 사용법 (한국 공휴일 지원)
function App() {
return <InfiniteCalendar holidayServiceKey="your_api_key_here" />;
}사용 가이드
1. 기본 사용법
import { InfiniteCalendar } from "mobile-react-infinite-calendar";
function App() {
return (
<InfiniteCalendar
holidayServiceKey="your_api_key_here"
onDayAction={(date, dayInfo) => {
console.log("날짜 클릭:", date.toDateString());
if (dayInfo?.events.length > 0) {
console.log(`이벤트 ${dayInfo.events.length}개`);
}
}}
/>
);
}2. 이벤트 관리
// 간단한 방식 (권장)
const events = [
{
date: '2024-01-15',
title: '팀 미팅',
color: '#3b82f6'
},
{
date: '2024-01-20',
title: '프로젝트 검토'
// color, id 생략 시 자동 처리
}
]
// 원본 데이터를 포함한 이벤트
const eventsWithOriginalData = [
{
date: '2024-01-15',
title: '팀 미팅',
color: '#3b82f6',
originalData: {
meetingId: 123,
location: '회의실 A',
participants: ['김철수', '이영희'],
agenda: '프로젝트 진행 상황 검토'
}
}
]
<InfiniteCalendar
holidayServiceKey="your_api_key_here"
events={eventsWithOriginalData}
onDayAction={(date, dayInfo) => {
// 원본 데이터 접근
const event = dayInfo?.events[0]
if (event?.originalData) {
console.log('미팅 위치:', event.originalData.location)
console.log('참석자:', event.originalData.participants)
}
console.log(`날짜 클릭: ${date.toDateString()}`)
if (dayInfo?.events.length > 0) {
console.log(`이벤트 ${dayInfo.events.length}개`)
}
}}
/>
// 상세한 방식 (기존 호환성)
const detailedEvents = [
{
id: '1',
title: '팀 미팅',
startTime: '2024-01-15T10:00:00',
endTime: '2024-01-15T11:00:00',
color: '#3b82f6'
}
]3. 한국 공휴일 설정
// 🔑 API 키 설정 (필수)
<InfiniteCalendar holidayServiceKey="your_api_key_here" />
// 커스텀 공휴일 추가 (자동 공휴일 + 커스텀)
const customHolidays = [
{ name: '회사 창립일', date: '2024-03-15', color: 'green' },
{ name: '팀 워크샵', date: '2024-06-20', color: 'purple' },
{ name: '프로젝트 마감', date: '2024-12-31', color: 'orange' },
{ name: '생일', date: '2024-08-15', color: 'pink' },
{ name: '특별 이벤트', date: '2024-10-10', color: '#4ecdc4' } // hex 색상도 가능
]
<InfiniteCalendar
holidayServiceKey="your_api_key_here"
holidays={customHolidays}
/>한국 공휴일 API 키 발급
- 공공데이터포털 접속
- "특일정보" API 검색 및 신청
- 발급받은 키를
holidayServiceKey에 설정
// 개발 환경 설정
// .env 파일
REACT_APP_HOLIDAY_API_KEY=your_api_key_here
// 사용
<InfiniteCalendar
holidayServiceKey={process.env.REACT_APP_HOLIDAY_API_KEY}
/>지원되는 공휴일:
- 🎌 신정, 설날, 추석 등 주요 공휴일
- 🏛️ 어린이날, 현충일, 광복절 등 국가 기념일
- 🌸 부처님오신날 등 종교 기념일
- 📅 대체공휴일 및 임시공휴일
사용 가능한 색상:
'red'🔴 (기본값) - 공휴일'green'🟢 - 개인 기념일'purple'🟣 - 특별 행사'orange'🟠 - 마감일, 알림'pink'🩷 - 생일, 기념일'yellow'🟡 - 일반 이벤트'#hex'- 커스텀 색상 (예:'#4ecdc4','#ff6b6b')
4. UI 커스터마이징
// 헤더 커스터마이징
<InfiniteCalendar
holidayServiceKey="your_api_key_here"
options={{
header: {
show: true,
monthTitle: true,
todayButton: false, // 오늘 버튼 숨김
weekDays: false, // 요일 헤더 숨김
datePicker: true
}
}}
/>
// 높이 설정
<InfiniteCalendar
holidayServiceKey="your_api_key_here"
options={{
height: 600 // 고정 높이 (px)
// height: 'auto' // 자동 높이 (기본값)
// height: '100vh' // CSS 단위도 가능
}}
/>
// 자동 높이 + 하단 네비게이션 고려
<InfiniteCalendar
holidayServiceKey="your_api_key_here"
options={{
autoHeight: {
bottomOffset: 80, // 하단 네비게이션 높이
minHeight: 300 // 최소 높이
}
}}
/>
// 모바일 Safari에서 더 부드러운 스크롤
<InfiniteCalendar
holidayServiceKey="your_api_key_here"
options={{
height: 'auto',
autoHeight: {
bottomOffset: 100, // Safari 주소창 고려
topOffset: 60 // 상단 네비게이션 고려
}
}}
/>
// 스타일 커스터마이징
<InfiniteCalendar
holidayServiceKey="your_api_key_here"
options={{
classNames: {
container: 'my-calendar-container',
header: 'custom-header bg-gray-100',
dayCell: 'hover:bg-blue-50 rounded-lg',
todayButton: 'btn-primary'
}
}}
/>
// 최소 UI (임베디드용)
<InfiniteCalendar
holidayServiceKey="your_api_key_here"
options={{
header: false, // 전체 헤더 숨김
height: 400 // 고정 높이 권장
}}
/>5. 디버그 및 개발 도구
// 간단한 디버깅 (ERROR, WARN, INFO만 출력)
<InfiniteCalendar
holidayServiceKey="your_api_key_here"
options={{
debug: true
}}
/>
// 상세한 디버그 설정
<InfiniteCalendar
holidayServiceKey="your_api_key_here"
options={{
debug: {
enabled: true,
level: 'info', // 로그 레벨: 'error' | 'warn' | 'info' | 'debug'
showPerformance: false // 성능 로그 표시 여부
}
}}
/>
// 개발 환경에서만 활성화
<InfiniteCalendar
holidayServiceKey="your_api_key_here"
options={{
debug: process.env.NODE_ENV === 'development'
}}
/>고급 기능
1. 동적 이벤트 로딩
// API 기반 동적 이벤트 로딩
const fetchEvents = async (startDate: Date, endDate: Date) => {
const response = await fetch(`/api/events?start=${startDate.toISOString()}&end=${endDate.toISOString()}`)
return response.json()
}
<InfiniteCalendar
holidayServiceKey="your_api_key_here"
dynamicEvents={fetchEvents}
dynamicEventMapping={{
id: 'eventId',
title: 'eventName',
date: 'eventDate',
startTime: 'startTime',
endTime: 'endTime',
color: 'eventColor'
}}
onDayAction={(date, dayInfo) => {
// 동적 이벤트의 원본 데이터 접근
const event = dayInfo?.events[0]
if (event?.originalData) {
console.log('원본 API 데이터:', event.originalData)
// API에서 받은 모든 필드에 접근 가능
}
}}
onDynamicEventLoad={(startDate, endDate, events) => {
console.log(`로드된 이벤트: ${events.length}개 (${startDate.toDateString()} ~ ${endDate.toDateString()})`)
}}
/>
// 커스텀 데이터 변환
<InfiniteCalendar
holidayServiceKey="your_api_key_here"
dynamicEvents={fetchEvents}
dynamicEventTransform={(apiData) => ({
id: apiData.id || Math.random().toString(),
title: apiData.subject || 'Untitled',
date: apiData.scheduledDate,
color: apiData.priority === 'high' ? '#ff4444' : '#4444ff',
originalData: apiData // 원본 데이터 보존
})}
/>동적 이벤트 특징:
- 🔄 자동 로딩: 스크롤 시 필요한 월의 이벤트만 로드
- 💾 스마트 캐싱: 이미 로드된 월은 캐시에서 빠르게 표시
- 📅 선행 로딩: 현재 월 기준 ±2개월 미리 로드
- 🎯 점프 감지: 데이트피커로 먼 날짜 이동 시 확장 로드
- 🔄 재시도 로직: 네트워크 오류 시 자동 재시도
- 📊 유연한 매핑: 다양한 API 응답 구조 지원
2. 다국어 지원
// 영어 사용자
function EnglishCalendar() {
const holidays = [
{ name: "Independence Day", date: "2024-07-04", color: "red" },
{ name: "Thanksgiving", date: "2024-11-28", color: "orange" },
];
return (
<InfiniteCalendar
locale="en-US" // 로케일 설정 필수
holidays={holidays} // 공휴일 직접 제공
/>
);
}
// 일본어 사용자
function JapaneseCalendar() {
return <InfiniteCalendar locale="ja-JP" holidays={myJapaneseHolidays} />;
}지원 로케일:
ko-KR,ko- 한국어 (기본값, 공휴일 지원)en-US,en- 영어ja-JP,ja- 일본어zh-CN,zh- 중국어de-DE,de- 독일어fr-FR,fr- 프랑스어it-IT,it- 이탈리아어es-ES,es- 스페인어
3. 고급 훅 사용
import { useCalendarComposer } from "su-react-infinite-calendar";
function CustomCalendarControls() {
const { activeMonth, setActiveMonth, monthsData, addNextMonth } =
useCalendarComposer({
events: [],
holidays: [],
holidayServiceKey: "your_api_key_here",
});
return (
<button onClick={() => setActiveMonth(new Date())}>Go to Today</button>
);
}4. 전체 옵션 예시
<InfiniteCalendar
events={events}
holidays={customHolidays}
holidayServiceKey="your_api_key_here"
dynamicEvents={fetchEvents}
onDayAction={(date, dayInfo) => {
openEventModal(date, dayInfo?.events);
}}
options={{
header: {
show: true,
monthTitle: true,
todayButton: true,
weekDays: true,
datePicker: false,
},
classNames: {
container: "shadow-lg rounded-xl",
dayCell: "custom-day-cell",
},
height: "auto",
initialDate: new Date(),
debug: process.env.NODE_ENV === "development",
}}
/>타입 정의
CalendarEvent
// 제네릭을 사용한 유연한 이벤트 타입
interface CalendarEvent<T = any> {
date: string; // YYYY-MM-DD 형식 (필수)
title?: string; // 툴팁이나 클릭 시 표시용
color?: string; // 도트 색상 (기본: 빨강)
id?: string; // 고유 식별자 (자동 생성 가능)
originalData?: T; // 원본 데이터를 그대로 보관
}
// 사용 예시
type MyApiEvent = {
eventId: number;
eventName: string;
startDateTime: string;
endDateTime: string;
location: string;
participants: string[];
};
const events: CalendarEvent<MyApiEvent>[] = [{
date: '2024-01-15',
title: '팀 미팅',
color: '#1a73e8',
originalData: {
eventId: 123,
eventName: '월간 팀 미팅',
startDateTime: '2024-01-15T10:00:00',
endDateTime: '2024-01-15T11:30:00',
location: '회의실 A',
participants: ['김철수', '이영희']
}
}];Holiday
interface Holiday {
id?: string; // Optional (auto-generated if not provided)
name: string;
date: string; // YYYY-MM-DD format
color?: string; // Text color for the date (default: 'red')
}CalendarOptions
interface CalendarOptions {
// Display 옵션
header?:
| boolean
| {
show?: boolean;
monthTitle?: boolean;
todayButton?: boolean;
weekDays?: boolean;
datePicker?: boolean;
};
// 스타일 커스터마이징
classNames?: {
container?: string;
header?: string;
monthTitle?: string;
weekDay?: string;
dayCell?: string;
todayButton?: string;
};
// 높이 설정
height?: number | "auto" | string;
autoHeight?: {
topOffset?: number; // 상단 여백 (기본: 0)
bottomOffset?: number; // 하단 여백 (기본: 20)
minHeight?: number; // 최소 높이 (기본: 400)
maxHeight?: number; // 최대 높이 (기본: window.innerHeight)
};
// 디버그 옵션
debug?:
| boolean
| {
enabled?: boolean; // 로그 활성화/비활성화 (기본: false)
level?: "error" | "warn" | "info" | "debug"; // 로그 레벨 (기본: 'error')
showPerformance?: boolean; // 성능 로그 표시 (기본: false)
};
// 기타 UI 옵션
initialDate?: Date;
}API Reference
Props
| Prop | Type | Default | Description |
| ----------------------- | ---------------------------------------------------------------------------------- | --------- | --------------------------- |
| events | CalendarEvent[] | [] | 정적 이벤트 배열 |
| holidays | Holiday[] | [] | 커스텀 공휴일 배열 |
| holidayServiceKey | string | - | 공휴일 API 키 (한국만 해당) |
| dynamicEvents | (startDate: Date, endDate: Date) => Promise<any[]> | - | 동적 이벤트 로딩 함수 |
| dynamicEventMapping | object | - | API 응답 필드 매핑 |
| dynamicEventTransform | (apiData: any) => CalendarEvent | - | 커스텀 데이터 변환 함수 |
| onDynamicEventLoad | (startDate: Date, endDate: Date, events: CalendarEvent[]) => void | - | 동적 이벤트 로드 완료 콜백 |
| onDayAction | (date: Date, dayInfo?: { events: CalendarEvent[], holidays: Holiday[] }) => void | - | 날짜 클릭 시 콜백 |
| locale | string | 'ko-KR' | 로케일 설정 |
| options | CalendarOptions | - | UI/스타일 옵션 |
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
