Calendar#
날짜를 시각적으로 탐색하고 선택할 수 있는 캘린더 컴포넌트입니다.
Live Preview#
class CalendarNoneExample extends StatefulComponent {
const CalendarNoneExample({super.key});
@override
State<CalendarNoneExample> createState() => _CalendarNoneExampleState();
}
class _CalendarNoneExampleState extends State<CalendarNoneExample> {
@override
Component build(BuildContext context) {
return CoCalendar(
selectionMode: CoreCalendarSelectionMode.none,
);
}
}
class CalendarNoneExample extends StatefulWidget {
const CalendarNoneExample({super.key});
@override
State<CalendarNoneExample> createState() => _CalendarNoneExampleState();
}
class _CalendarNoneExampleState extends State<CalendarNoneExample> {
@override
Widget build(BuildContext context) {
return CoCalendar(
selectionMode: CoreCalendarSelectionMode.none,
);
}
}
class CalendarDefaultExample extends StatefulComponent {
const CalendarDefaultExample({super.key});
@override
State<CalendarDefaultExample> createState() => _CalendarDefaultExampleState();
}
class _CalendarDefaultExampleState extends State<CalendarDefaultExample> {
@override
Component build(BuildContext context) {
return CoCalendar.single();
}
}
class CalendarDefaultExample extends StatefulWidget {
const CalendarDefaultExample({super.key});
@override
State<CalendarDefaultExample> createState() => _CalendarDefaultExampleState();
}
class _CalendarDefaultExampleState extends State<CalendarDefaultExample> {
@override
Widget build(BuildContext context) {
return CoCalendar.single();
}
}
class CalendarMultiExample extends StatefulComponent {
const CalendarMultiExample({super.key});
@override
State<CalendarMultiExample> createState() => _CalendarMultiExampleState();
}
class _CalendarMultiExampleState extends State<CalendarMultiExample> {
@override
Component build(BuildContext context) {
return CoCalendar.multi();
}
}
class CalendarMultiExample extends StatefulWidget {
const CalendarMultiExample({super.key});
@override
State<CalendarMultiExample> createState() => _CalendarMultiExampleState();
}
class _CalendarMultiExampleState extends State<CalendarMultiExample> {
@override
Widget build(BuildContext context) {
return CoCalendar.multi();
}
}
class CalendarRangeExample extends StatefulComponent {
const CalendarRangeExample({super.key});
@override
State<CalendarRangeExample> createState() => _CalendarRangeExampleState();
}
class _CalendarRangeExampleState extends State<CalendarRangeExample> {
@override
Component build(BuildContext context) {
return CoCalendar.range();
}
}
class CalendarRangeExample extends StatefulWidget {
const CalendarRangeExample({super.key});
@override
State<CalendarRangeExample> createState() => _CalendarRangeExampleState();
}
class _CalendarRangeExampleState extends State<CalendarRangeExample> {
@override
Widget build(BuildContext context) {
return CoCalendar.range();
}
}
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- 날짜를 시각적으로 탐색하고 선택해야 할 때
- 범위(체크인/체크아웃) 또는 다중 날짜 선택이 필요할 때
대신 다른 컴포넌트를 사용하세요:
DatePicker: 입력 필드와 결합된 날짜 선택 폼 요소일 때Input: 단순 날짜 텍스트 입력만 필요할 때
기본 사용법 (Basic Usage)#
// 단일 선택
CoCalendar.single(
onChanged: (value) => print('Selected: $value'),
)
// 범위 선택
CoCalendar.range(
onChanged: (value) => print('Range: $value'),
)
// 다중 선택
CoCalendar.multi(
onChanged: (value) => print('Multi: $value'),
)
// 단일 선택
CoCalendar.single(
onChanged: (value) => print('Selected: $value'),
)
// 범위 선택
CoCalendar.range(
onChanged: (value) => print('Range: $value'),
)
// 다중 선택
CoCalendar.multi(
onChanged: (value) => print('Multi: $value'),
)
Props / Parameters#
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
selectionMode |
CoreCalendarSelectionMode |
single |
선택 모드 |
value |
CoreCalendarValue? |
null |
현재 선택 값 |
onChanged |
Function(CoreCalendarValue?)? |
null |
선택 변경 콜백 |
initialView |
CoreCalendarView? |
null |
초기 표시 월/년 |
stateBuilder |
CoreCalendarDateStateBuilder? |
null |
날짜별 활성/비활성 결정 |
minDate |
DateTime? |
null |
최소 선택 가능 날짜 |
maxDate |
DateTime? |
null |
최대 선택 가능 날짜 |
calendarStyle |
CoreCalendarStyle<Clr>? |
null |
인스턴스별 스타일 (chrome / 슬롯 / 상태 토큰) |
스타일 시스템 (Style System)#
CoCalendar 의 모든 chrome / dimensional / 슬롯 / 상태 토큰 override 는
단일 calendarStyle: CoreCalendarStyle<Clr> 슬롯으로 흐릅니다 (Epic #1302).
selectionMode / initialView 같은 시맨틱 enum 과 동작 필드는 위젯에 그대로
남고, 스타일 슬롯에는 들어가지 않습니다 (원칙 6 / 7).
구조#
CoreCalendarStyle<Clr> 는 composite Style 입니다 — 하위 컴포넌트의 Style 을
nested 로 보유합니다.
| 필드 | 타입 | 적용 대상 |
|---|---|---|
navButtonStyle |
CoreButtonStyle<Clr>? |
prev / next 네비 버튼, 헤더 버튼 |
dateCellStyle |
CoreButtonStyle<Clr>? |
날짜 / 월 / 연도 셀 버튼 chrome |
arrowIconStyle |
CoreIconStyle<Clr>? |
prev / next 화살표 아이콘 |
headerLabelStyle |
CoreTextStyle<Clr>? |
헤더 라벨 ("May 2026") |
weekdayLabelStyle |
CoreTextStyle<Clr>? |
요일 라벨 (Sun / Mon …) |
selectedColor | Clr? | 선택된 셀 배경 |
todayColor | Clr? | 오늘 셀 배경 |
todayTextColor | Clr? | 오늘 셀 텍스트 |
rangeSelectionColor | Clr? | range 내부 셀 배경 |
rangeSelectionTextColor | Clr? | range 내부 셀 텍스트 |
상태 토큰 5 개는 grid 안의 state-coloured 셀이라 단일 sub-component chrome 에 귀속되지 않으므로 nested slot Style 이 아닌 평면(flat) 색 토큰으로 노출합니다.
Resolve chain#
design system default
→ CoreCalendarTheme.style // 프로젝트 공통
→ parent component slot override
(예: CoreDatePickerStyle.calendarStyle)
→ widget.calendarStyle // 인스턴스별
CoreCalendarStyle.merge 는 nested slot Style (navButtonStyle 등) 을
재귀적으로 머지하므로 부모 / theme / 인스턴스 단계에서 부분 override 가
가능합니다.
사용 예#
CoCalendar(
selectionMode: CoreCalendarSelectionMode.single,
calendarStyle: CoreCalendarStyle<Color>(
selectedColor: Colors.purple,
dateCellStyle: CoreButtonStyle(
labelStyle: CoreTextStyle(fontWeight: 600),
),
),
onChanged: (value) => print(value),
)
CoCalendar(
selectionMode: CoreCalendarSelectionMode.single,
calendarStyle: CoreCalendarStyle<String>(
selectedColor: 'var(--coui-primary)',
rangeSelectionColor: 'var(--coui-secondary)',
),
onChanged: (value) => print(value),
)
변형 (Variants)#
단일 선택 (Single)#
CoCalendar.single(
onChanged: (value) => print('Selected: $value'),
)
범위 선택 (Range)#
CoCalendar.range(
onChanged: (value) => print('Range: $value'),
)
범위 모드에서는 듀얼 캘린더 레이아웃이 표시됩니다.
다중 선택 (Multi)#
CoCalendar.multi(
onChanged: (value) => print('Multi: $value'),
)
표시 전용 (None)#
CoCalendar(
selectionMode: CoreCalendarSelectionMode.none,
)
동작 스펙 (Behavior)#
선택 모드#
CoreCalendarSelectionMode.none // 표시 전용
CoreCalendarSelectionMode.single // 단일 날짜 선택
CoreCalendarSelectionMode.range // 시작~끝 범위 선택
CoreCalendarSelectionMode.multi // 다중 날짜 선택
- Single: 클릭으로 선택, 다시 클릭하면 해제
- Range: 첫 번째 클릭=시작, 두 번째 클릭=끝. 자동 정렬(start < end)
- Multi: 클릭할 때마다 선택/해제 토글
CoreCalendarValue#
// 단일 선택
CoreCalendarValue.single(DateTime(2024, 3, 15))
// 범위 선택
CoreCalendarValue.range(DateTime(2024, 3, 10), DateTime(2024, 3, 20))
// 다중 선택
CoreCalendarValue.multi([DateTime(2024, 3, 5), DateTime(2024, 3, 15)])
뷰 전환#
CoreCalendarViewType.date: 월별 일 그리드 (6행 × 7열)CoreCalendarViewType.month: 월 선택 (4×3 그리드)CoreCalendarViewType.year: 연도 선택 (4×4 그리드)- 헤더의 월/연도를 클릭하면 상위 뷰로 전환
날짜 상태 검증#
CoCalendar.single(
stateBuilder: (date) {
if (date.isBefore(DateTime.now())) return CoreCalendarDateState.disabled;
return CoreCalendarDateState.enabled;
},
onChanged: (value) => print(value),
)
크로스 플랫폼 차이점 (Platform Differences)#
| 항목 | Flutter | Web |
|---|---|---|
| 클래스명 | CoCalendar | CoCalendar |
| 값 모델 | CoreCalendarValue | CoreCalendarValue |
| 선택 모드 | none/single/range/multi | none/single/range/multi |
| 뷰 전환 | date → month → year | date → month → year |
| 범위 레이아웃 | 듀얼 캘린더 | 듀얼 캘린더 |
| 네비게이션 | CoButton(variant: .outline) |
CoButton(variant: .outline) |
| 날짜 셀 | CoButton(variant: .ghost/.primary/.secondary) |
CoButton(variant: .ghost/.primary/.secondary) |
관련 컴포넌트 (Related Components)#
- DatePicker: 입력 필드 + 캘린더 팝업