useCalendarApp ๋ ˆํผ๋Ÿฐ์Šค

useCalendarApp(config: CalendarAppConfig)์€ DayFlow ์ฝ”์–ด๋ฅผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ์—ฐ๊ฒฐํ•ด ์ฃผ๋Š” ํ›…์ž…๋‹ˆ๋‹ค. ์„ค์ • ๊ฐ์ฒด ํ•˜๋‚˜๋ฅผ ์ „๋‹ฌํ•ด ๋ทฐ๋ฅผ ๋“ฑ๋กํ•˜๊ณ , ์ดˆ๊ธฐ ์ด๋ฒคํŠธ๋ฅผ ๋„ฃ๊ณ , ์„ ํƒ์  UI๋ฅผ ์ผœ๊ณ , ์ƒ๋ช…์ฃผ๊ธฐ ์ฝœ๋ฐฑ์„ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์„œ์—์„œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ์˜ต์…˜์„ ์‚ดํŽด๋ด…๋‹ˆ๋‹ค.

๋น ๋ฅธ ์‹œ์ž‘

import {
  useCalendarApp,
  DayFlowCalendar,
  createMonthView,
  createWeekView,
  ViewType,
} from '@dayflow/react';
import '@dayflow/core/dist/styles.css';

export function TeamCalendar() {
  const calendar = useCalendarApp({
    views: [createMonthView(), createWeekView()],
    defaultView: ViewType.MONTH,
    initialDate: new Date(),
    events: [],
  });

  return <DayFlowCalendar calendar={calendar} />;
}
<template>
  <DayFlowCalendar :calendar="calendar" />
</template>

<script setup>
import { DayFlowCalendar, useCalendarApp } from '@dayflow/vue';
import { createMonthView, createWeekView, ViewType } from '@dayflow/core';
import '@dayflow/core/dist/styles.css';

const calendar = useCalendarApp({
  views: [createMonthView(), createWeekView()],
  defaultView: ViewType.MONTH,
  initialDate: new Date(),
  events: [],
});
</script>
import { Component } from '@angular/core';
import { createMonthView, createWeekView, ViewType } from '@dayflow/core';
import { DayFlowCalendarModule } from '@dayflow/angular';
import '@dayflow/core/dist/styles.css';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [DayFlowCalendarModule],
  template: `
    <dayflow-calendar [calendar]="calendar"></dayflow-calendar>
  `
})
export class AppComponent {
  calendar = {
    views: [createMonthView(), createWeekView()],
    defaultView: ViewType.MONTH,
    initialDate: new Date(),
    events: [],
  };
}
<script>
  import { DayFlowCalendar, useCalendarApp } from '@dayflow/svelte';
  import { createMonthView, createWeekView, ViewType } from '@dayflow/core';
  import '@dayflow/core/dist/styles.css';

  const calendar = useCalendarApp({
    views: [createMonthView(), createWeekView()],
    defaultView: ViewType.MONTH,
    initialDate: new Date(),
    events: [],
  });
</script>

<DayFlowCalendar {calendar} />

์„ค์ • ํ•œ๋ˆˆ์— ๋ณด๊ธฐ

์˜ต์…˜ํƒ€์ž…ํ•„์ˆ˜ ์—ฌ๋ถ€๊ธฐ๋ณธ๊ฐ’์„ค๋ช…
viewsCalendarView[]ํ•„์ˆ˜โ€”๋ทฐ ์ •์˜๋ฅผ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: createMonthView()). ์ตœ์†Œ ํ•˜๋‚˜๋Š” ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
pluginsCalendarPlugin[]์„ ํƒ[]์„ ํƒ์  ํ”Œ๋Ÿฌ๊ทธ์ธ(๋“œ๋ž˜๊ทธ ๋„์šฐ๋ฏธ, ๋‹จ์ถ•ํ‚ค ๋“ฑ)์„ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ํ”Œ๋Ÿฌ๊ทธ์ธ์€ install ์‹œ์ ์— ์•ฑ ์ธ์Šคํ„ด์Šค๋ฅผ ์ „๋‹ฌ๋ฐ›์Šต๋‹ˆ๋‹ค.
eventsEvent[]์„ ํƒ[]์ดˆ๊ธฐ ์ด๋ฒคํŠธ ๋ชฉ๋ก์ž…๋‹ˆ๋‹ค. ์ดํ›„์—๋Š” addEvent/updateEvent๋กœ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜์„ธ์š”.
callbacksCalendarCallbacks์„ ํƒ{}๋ทฐยท๋‚ ์งœยท์ด๋ฒคํŠธ๊ฐ€ ๋ฐ”๋€” ๋•Œ ์‹คํ–‰๋˜๋Š” ์ƒ๋ช…์ฃผ๊ธฐ ํ›…์ž…๋‹ˆ๋‹ค. API์™€ ๋™๊ธฐํ™”ํ•˜๊ธฐ์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.
defaultViewViewType์„ ํƒViewType.WEEK์ฒ˜์Œ ๋กœ๋“œ๋˜๋Š” ๋ทฐ์ž…๋‹ˆ๋‹ค. views์— ํฌํ•จ๋˜์–ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
initialDateDate์„ ํƒnew Date()์ฒ˜์Œ ํฌ์ปค์Šคํ•  ๋‚ ์งœ์ž…๋‹ˆ๋‹ค(ํ‘œ์‹œํ•  ์›” ๊ณ„์‚ฐ์˜ ๊ธฐ์ค€์ด๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค).
timeZonestring์„ ํƒ์‚ฌ์šฉ์ž์˜ ์‹œ์Šคํ…œ ์‹œ๊ฐ„๋Œ€๋ชจ๋“  ๋ทฐ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์ „์—ญ ํ‘œ์‹œยทํŽธ์ง‘ ์‹œ๊ฐ„๋Œ€์ž…๋‹ˆ๋‹ค.
timeFormat'12h' | '24h'์„ ํƒโ€”๋ชจ๋“  ๋ทฐยท๊ฒ€์ƒ‰ยท์ปดํฌ๋„ŒํŠธ์— ์ ์šฉ๋˜๋Š” ์ „์—ญ ์‹œ๊ฐ„ ํ˜•์‹์ž…๋‹ˆ๋‹ค. ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๊ฐ€์žฅ ๋†’์•„ ๋ทฐ ๋‹จ์œ„๋‚˜ ๊ฒ€์ƒ‰ ๋‹จ์œ„ ์„ค์ •์„ ๋ฎ์–ด์”๋‹ˆ๋‹ค.
switcherMode'buttons' | 'select'์„ ํƒ'buttons'ํ—ค๋”์— ๋‚ด์žฅ๋œ ๋ทฐ ์ „ํ™˜๊ธฐ์˜ ํ‘œ์‹œ ๋ฐฉ์‹์„ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค.
calendarsCalendarType[]์„ ํƒ[]์บ˜๋ฆฐ๋” ๋ถ„๋ฅ˜(์—…๋ฌด, ๊ฐœ์ธ ๋“ฑ)๋ฅผ ์ƒ‰์ƒยทํ‘œ์‹œ ์—ฌ๋ถ€์™€ ํ•จ๊ป˜ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.
defaultCalendarstring์„ ํƒ์ฒ˜์Œ ํ‘œ์‹œ๋˜๋Š” ์บ˜๋ฆฐ๋”์ƒˆ ์ด๋ฒคํŠธ๋ฅผ ๋งŒ๋“ค ๋•Œ ์‚ฌ์šฉํ•  ID์ž…๋‹ˆ๋‹ค.
themeThemeConfig์„ ํƒ{ mode: 'light' }์ „์—ญ ํ…Œ๋งˆ ๋ชจ๋“œ์™€ ํ•„์š” ์‹œ ํ† ํฐ ์žฌ์ •์˜๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
localestring | Locale์„ ํƒ'en-US'๊ตญ์ œํ™”(i18n)์— ์‚ฌ์šฉํ•  ๋กœ์ผ€์ผ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์–ธ์–ด ์ฝ”๋“œ(์˜ˆ: 'ja')๋‚˜ Locale ๊ฐ์ฒด๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
useEventDetailDialogboolean์„ ํƒfalse์ธ๋ผ์ธ ํŒจ๋„ ๋Œ€์‹  ๊ธฐ๋ณธ ๋ชจ๋‹ฌ ์ƒ์„ธ ๋Œ€ํ™”์ƒ์ž๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
eventDetailTrigger'click' | 'dbClick'์„ ํƒ'dbClick'๋ฐ์Šคํฌํ†ฑ์—์„œ ์ด๋ฒคํŠธ ์ƒ์„ธ๋ฅผ ํ•œ ๋ฒˆ ํด๋ฆญ์œผ๋กœ ์—ด์ง€ ๋”๋ธ” ํด๋ฆญ์œผ๋กœ ์—ด์ง€ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค. ํ„ฐ์น˜ ์ž…๋ ฅ์—์„œ๋Š” ํ•ญ์ƒ ํ•œ ๋ฒˆ ํƒญํ•˜๋ฉด ์—ด๋ฆฝ๋‹ˆ๋‹ค.
useCalendarHeaderboolean์„ ํƒtrue๊ธฐ๋ณธ ํ—ค๋”๋ฅผ ํ‘œ์‹œํ•˜๊ฑฐ๋‚˜(true) ์ˆจ๊น๋‹ˆ๋‹ค(false). ์ง์ ‘ ๋งŒ๋“  ํ—ค๋”๋ฅผ ์“ฐ๋ ค๋ฉด DayFlowCalendar์˜ calendarHeader ์Šฌ๋กฏ์„ ์‚ฌ์šฉํ•˜์„ธ์š”.
readOnlyboolean | ReadOnlyConfig์„ ํƒfalse๋‚ด์žฅ ํŽธ์ง‘ UI๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค. ๋ถˆ๋ฆฌ์–ธ์ด๋‚˜ ์„ธ๋ถ€ ์ œ์–ด์šฉ ์„ค์ •(๋“œ๋ž˜๊ทธ/์กฐํšŒ)์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ์—์„œ ํ˜ธ์ถœํ•˜๋Š” ์ด๋ฒคํŠธ API๋Š” ๊ณ„์† ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.
allDaySortComparatorAllDaySortComparator์„ ํƒ์บ˜๋ฆฐ๋” ๊ทธ๋ฃน ์ˆœ์„œ, ์—ฌ๋Ÿฌ ๋‚  ์ข…์ผ ์ด๋ฒคํŠธ๊ฐ€ ๋จผ์ €๋ชจ๋“  ๋ทฐ์—์„œ ์ข…์ผ ์ด๋ฒคํŠธ ํ–‰์˜ ์ •๋ ฌ ์ˆœ์„œ๋ฅผ ์ œ์–ดํ•˜๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ๋น„๊ต ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์ง€์ •ํ•˜๋ฉด ๊ธฐ๋ณธ ์ •๋ ฌ์„ ์™„์ „ํžˆ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์š” ์˜ต์…˜

Views (ํ•„์ˆ˜)

  • ๊ฐ ๋ทฐ๋Š” { type, component, config } ํ˜•ํƒœ์˜ CalendarView ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.
  • DayFlow๋Š” ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ •์˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํŒฉํ† ๋ฆฌ(createDayView, createWeekView, createMonthView, createAgendaView, createYearView)๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  • defaultView๋Š” ๋“ฑ๋ก๋œ ๋ทฐ ํƒ€์ž… ์ค‘ ํ•˜๋‚˜์™€ ์ผ์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ดˆ๊ธฐํ™” ๊ณผ์ •์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

Events

  • ์ „๋‹ฌํ•œ ๋ฐฐ์—ด์ด ๋ฉ”๋ชจ๋ฆฌ์ƒ์˜ CalendarApp.state.events ๋ชฉ๋ก์ด ๋ฉ๋‹ˆ๋‹ค.
  • useCalendarApp์€ ์•ฑ์˜ ๋ณ€๊ฒฝ์„ ๊ฐ์‹œํ•˜๋ฏ€๋กœ calendar.addEvent()๋‚˜ calendar.updateEvent()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒํƒœ๊ฐ€ ์ž๋™์œผ๋กœ ๋™๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค.
  • ์ด๋ฒคํŠธ๊ฐ€ Event ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋”ฐ๋ฅด๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”(start/end๋Š” PlainDate, PlainDateTime, ZonedDateTime์„ ๋ฐ›์Šต๋‹ˆ๋‹ค).

Plugins

  • ํ”Œ๋Ÿฌ๊ทธ์ธ์€ { name, install(app), config } ํ˜•ํƒœ์ด๋ฉฐ ์ƒ์„ฑ ์‹œ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
  • ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ๋“œ๋ž˜๊ทธ ํ•ธ๋“ค๋Ÿฌ, ํ‚ค๋ณด๋“œ ๋‹จ์ถ•ํ‚ค, ๋ถ„์„ ์˜ต์ €๋ฒ„๋ฅผ ๋“ฑ๋กํ•˜๊ฑฐ๋‚˜ app.getPlugin(name)์œผ๋กœ ์ž์ฒด API๋ฅผ ๋…ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Callbacks

callbacks๋Š” ์ƒํƒœ๋ฅผ ๋ฐฑ์—”๋“œ๋‚˜ ๋ถ„์„ ๊ณ„์ธต๊ณผ ๋™๊ธฐํ™”๋œ ์ƒํƒœ๋กœ ์œ ์ง€ํ•ด ์ค๋‹ˆ๋‹ค:

  • onViewChange(view)๋Š” ๋ทฐ ์ „ํ™˜์ด ์„ฑ๊ณตํ•œ ๋’ค์— ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
  • onDateChange(date)๋Š” ํฌ์ปค์Šค๋œ ๋‚ ์งœ๊ฐ€ ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค(์ด๋™ ๋˜๋Š” ์„ ํƒ).
  • onVisibleRangeChange(start, end, reason)์€ ํ‘œ์‹œ ์ค‘์ธ ๋‚ ์งœ ๋ฒ”์œ„๊ฐ€ ๋ฐ”๋€” ๋•Œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ๋ณ„๋„ ๊ณ„์‚ฐ ์—†์ด ๋” ์ •ํ™•ํ•œ ๋ฒ”์œ„๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • onEventCreate(event), onEventUpdate(event), onEventDelete(id)๋Š” CRUD ์ž‘์—…์— ๋Œ€์‘ํ•ฉ๋‹ˆ๋‹ค. API ๋™๊ธฐํ™”์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.
  • onEventDoubleClick(event, e)๋Š” ๊ธฐ๋ณธ ๋ชจ๋“œ์ธ eventDetailTrigger: 'dbClick'์—์„œ ์ด๋ฒคํŠธ๋ฅผ ๋”๋ธ” ํด๋ฆญํ•  ๋•Œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ์™ธ๋ถ€ ํŒ์˜ค๋ฒ„์˜ ๊ธฐ์ค€์ ์œผ๋กœ e.currentTarget์„ ์‚ฌ์šฉํ•˜๊ณ , DayFlow ๊ธฐ๋ณธ ์ƒ์„ธ ํŒจ๋„ยท๋Œ€ํ™”์ƒ์ž๋ฅผ ๋ง‰์œผ๋ ค๋ฉด false๋ฅผ ๋ฐ˜ํ™˜ํ•˜์„ธ์š”.
  • onMoreEventsClick(date)๋Š” ์›” ๋ทฐ์—์„œ "+ X๊ฐœ ๋”" ๋งํฌ๋ฅผ ํด๋ฆญํ•  ๋•Œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
  • onCalendarCreate(calendar), onCalendarUpdate(calendar), onCalendarDelete(id)๋Š” ์บ˜๋ฆฐ๋” CRUD ์ž‘์—…์— ๋Œ€์‘ํ•ฉ๋‹ˆ๋‹ค.
  • onCalendarMerge(sourceId, targetId)๋Š” ๋‘ ์บ˜๋ฆฐ๋”๋ฅผ ๋ณ‘ํ•ฉํ•  ๋•Œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค(์˜ˆ: "์—…๋ฌด"๋ฅผ "๊ฐœ์ธ"์— ํ•ฉ์น˜๋Š” ๊ฒฝ์šฐ).
  • onRender()๋Š” ์บ˜๋ฆฐ๋”๊ฐ€ ๋ Œ๋”๋ง์„ ํ•œ ์ฐจ๋ก€ ๋งˆ์ณค์„ ๋•Œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค(๊ณ„์ธก์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค).

defaultView์™€ initialDate

  • defaultView๋Š” ์ดˆ๊ธฐ state.currentView๋ฅผ ์ •ํ•ฉ๋‹ˆ๋‹ค. ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด DayFlow๊ฐ€ ViewType.WEEK๋กœ ๋˜๋Œ์•„๊ฐ€๋ฏ€๋กœ, ๋ทฐ๊ฐ€ ํ•˜๋‚˜๋ฟ์ธ ์บ˜๋ฆฐ๋”์—์„œ๋Š” ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•˜์„ธ์š”.
  • initialDate๋Š” state.currentDate์™€ ๋‚ด๋ถ€ visibleMonth๋ฅผ ํ•จ๊ป˜ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค. ๋ผ์šฐํŒ…์ด๋‚˜ ์‚ฌ์šฉ์ž ์„ค์ •์—์„œ ๋‚ ์งœ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค๋ฉด ์ด ๊ฐ’์„ ๋ฐ”๊พธ์„ธ์š”.

timeZone

  • timeZone์€ ์ผยท์ฃผยท์›”ยท์•„์  ๋‹คยท์—ฐ๊ฐ„ ๋ทฐ์˜ ๊ธฐ๋ณธ ํ‘œ์‹œ ๋ฐ ํŽธ์ง‘ ์‹œ๊ฐ„๋Œ€๋ฅผ ์ •ํ•ฉ๋‹ˆ๋‹ค.
  • ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด DayFlow๊ฐ€ ์‚ฌ์šฉ์ž์˜ ์‹œ์Šคํ…œ ์‹œ๊ฐ„๋Œ€์—์„œ ๊ฐ’์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  • timeZone์„ ๋ฐ”๊พธ๋ฉด UI๊ฐ€ ๋‹ค์‹œ ๊ณ„์‚ฐ๋˜์–ด ํ‘œ์‹œ๋˜์ง€๋งŒ, ๊ทธ ์ž์ฒด๋กœ ์ด๋ฒคํŠธ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ”๋€Œ์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.
  • ๋ณ€๊ฒฝ์ด ์ ์šฉ๋œ ๋’ค์—๋„ ํŽธ์ง‘ ์ฝœ๋ฐฑ์€ ์ •๊ทœํ™”๋œ ์ด๋ฒคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. DayFlow๋Š” ์ž„์‹œ ํ‘œ์‹œ์šฉ ์‹œ๊ฐ„๋Œ€๋ฅผ ์ €์žฅ ํ˜•ํƒœ๋กœ ๋‚จ๊ธฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ์ผยท์ฃผ ๋ทฐ์˜ secondaryTimeZone์€ ํ‘œ์‹œ ์ „์šฉ ์ฐธ์กฐ ์ถ•์ผ ๋ฟ์ด๋ฉฐ, ์•ฑ์˜ ๊ธฐ๋ณธ ์‹œ๊ฐ„๋Œ€๋ฅผ ๋Œ€์ฒดํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

switcherMode

  • 'buttons': ๊ฐ€๋กœ ๋ฒ„ํŠผ ๊ทธ๋ฃน์œผ๋กœ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์Šคํฌํ†ฑ์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.
  • 'select': ๋“œ๋กญ๋‹ค์šด์œผ๋กœ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ๊ณต๊ฐ„์ด ๋ถ€์กฑํ•˜๊ฑฐ๋‚˜ ๋ทฐ ํƒ€์ž…์ด ๋งŽ์„ ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

calendars์™€ defaultCalendar

  • calendars๋Š” ๊ฐ ์บ˜๋ฆฐ๋” ํƒ€์ž…(id, name, colors, ํ‘œ์‹œ ์—ฌ๋ถ€)์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์บ˜๋ฆฐ๋” ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๊ฐ€ theme.mode('light' | 'dark' | 'auto')์— ๋”ฐ๋ผ ๋ฐ์€ ์ƒ‰์ƒ๊ณผ ์–ด๋‘์šด ์ƒ‰์ƒ์„ ์ž๋™์œผ๋กœ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.
  • defaultCalendar๋Š” ์ƒˆ ์ด๋ฒคํŠธ๊ฐ€ ์–ด๋–ค ์บ˜๋ฆฐ๋”๋ฅผ ์ƒ์†ํ• ์ง€ ์ •ํ•ฉ๋‹ˆ๋‹ค. ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ์ฒ˜์Œ ํ‘œ์‹œ๋˜๋Š” ์บ˜๋ฆฐ๋”๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

CalendarType์˜ ์†์„ฑ:

์†์„ฑํƒ€์ž…ํ•„์ˆ˜ ์—ฌ๋ถ€์„ค๋ช…
idstring์˜ˆ๊ณ ์œ  ์‹๋ณ„์ž์ž…๋‹ˆ๋‹ค(์˜ˆ: 'work', 'personal').
namestring์˜ˆUI์— ํ‘œ์‹œ๋˜๋Š” ์ด๋ฆ„์ž…๋‹ˆ๋‹ค.
colorsCalendarColors์˜ˆ๋ผ์ดํŠธ ๋ชจ๋“œ ์ƒ‰์ƒ ์„ธํŠธ์ž…๋‹ˆ๋‹ค(์•„๋ž˜ ์ฐธ๊ณ ).
darkColorsCalendarColors์•„๋‹ˆ์˜ค๋‹คํฌ ๋ชจ๋“œ ์ƒ‰์ƒ ์„ธํŠธ์ž…๋‹ˆ๋‹ค. ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด colors๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
descriptionstring์•„๋‹ˆ์˜ค์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์„ ํƒ์  ์„ค๋ช…์ž…๋‹ˆ๋‹ค.
iconstring์•„๋‹ˆ์˜ค์บ˜๋ฆฐ๋” ์ด๋ฆ„ ์˜†์— ํ‘œ์‹œํ•  ์ด๋ชจ์ง€ ๋˜๋Š” ์•„์ด์ฝ˜ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค.
isVisibleboolean์•„๋‹ˆ์˜ค์ด ์บ˜๋ฆฐ๋”์˜ ์ด๋ฒคํŠธ๋ฅผ ํ‘œ์‹œํ• ์ง€ ์—ฌ๋ถ€์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์€ true์ž…๋‹ˆ๋‹ค.
isDefaultboolean์•„๋‹ˆ์˜ค์ด ์บ˜๋ฆฐ๋”๋ฅผ ์‹œ์Šคํ…œ ๊ธฐ๋ณธ ์บ˜๋ฆฐ๋”๋กœ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.
readOnlyboolean์•„๋‹ˆ์˜ค์ด ์บ˜๋ฆฐ๋”์˜ ์ด๋ฒคํŠธ์— ๋Œ€ํ•ด ๋“œ๋ž˜๊ทธยทํฌ๊ธฐ ์กฐ์ ˆยทํŽธ์ง‘ UI๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค.
sourcestring์•„๋‹ˆ์˜ค์ถœ์ฒ˜ ๋ ˆ์ด๋ธ”์ž…๋‹ˆ๋‹ค(์˜ˆ: 'Google Calendar', 'iCloud').
subscription{ url, status, meta? }์•„๋‹ˆ์˜คICS ๋˜๋Š” ์›๊ฒฉ ์บ˜๋ฆฐ๋”์˜ ๊ตฌ๋… ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ์ž…๋‹ˆ๋‹ค.

CalendarColors์˜ ์†์„ฑ:

์†์„ฑํƒ€์ž…์„ค๋ช…
eventColorstring์ด๋ฒคํŠธ ๋ฐฐ๊ฒฝ์ƒ‰์ž…๋‹ˆ๋‹ค(๋ณดํ†ต ๋ฐ˜ํˆฌ๋ช…).
eventSelectedColorstring์ด๋ฒคํŠธ๊ฐ€ ์„ ํƒ๋˜์—ˆ์„ ๋•Œ์˜ ๋ฐฐ๊ฒฝ์ƒ‰์ž…๋‹ˆ๋‹ค.
lineColorstring๊ฐ•์กฐ ๋˜๋Š” ํ…Œ๋‘๋ฆฌ ์ƒ‰์ƒ์ž…๋‹ˆ๋‹ค.
textColorstring์ด๋ฒคํŠธ ํ…์ŠคํŠธ ์ƒ‰์ƒ์ž…๋‹ˆ๋‹ค.

theme

theme ์„ค์ •์€ ์บ˜๋ฆฐ๋” ์ „์ฒด์˜ ์‹œ๊ฐ์  ์™ธํ˜•์„ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค:

const calendar = useCalendarApp({
  theme: {
    mode: 'dark', // 'light' | 'dark' | 'auto'
  },
});

ํ…Œ๋งˆ ๋ชจ๋“œ:

  • 'light': ๋ฐ์€ ๋ฐฐ๊ฒฝ๊ณผ ์–ด๋‘์šด ๊ธ€์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ผ์ดํŠธ ๋ชจ๋“œ(๊ธฐ๋ณธ๊ฐ’)
  • 'dark': ์–ด๋‘์šด ๋ฐฐ๊ฒฝ๊ณผ ๋ฐ์€ ๊ธ€์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋‹คํฌ ๋ชจ๋“œ
  • 'auto': ์‹œ์Šคํ…œ ํ…Œ๋งˆ ์„ค์ •์„ ์ž๋™์œผ๋กœ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค

์ฝ”๋“œ๋กœ ํ…Œ๋งˆ ๋ฐ”๊พธ๊ธฐ:

// Get current theme
const currentTheme = calendar.app.getTheme();

// Set theme
calendar.app.setTheme('dark');

// Subscribe to theme changes
calendar.app.subscribeThemeChange(theme => {
  console.log('Theme changed to:', theme);
});

๋‹คํฌ ๋ชจ๋“œ ์ƒ‰์ƒ ์ง์ ‘ ์ง€์ •ํ•˜๊ธฐ:

์บ˜๋ฆฐ๋” ํƒ€์ž…๋งˆ๋‹ค ๋ผ์ดํŠธ ๋ชจ๋“œ์™€ ๋‹คํฌ ๋ชจ๋“œ์— ์„œ๋กœ ๋‹ค๋ฅธ ์ƒ‰์ƒ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

const calendars = [
  {
    id: 'work',
    name: 'Work',
    colors: {
      // Light mode colors
      lineColor: '#0066cc',
      eventColor: '#e6f2ff',
      eventSelectedColor: '#cce4ff',
      textColor: '#003d7a',
    },
    darkColors: {
      // Dark mode colors
      lineColor: '#4da6ff',
      eventColor: '#1a3d5c',
      eventSelectedColor: '#2a5a8a',
      textColor: '#b3d9ff',
    },
  },
];

ํ…Œ๋งˆ์— ๋Œ€ํ•œ ์ „์ฒด ๋ฌธ์„œ๋Š” ๋‹คํฌ ๋ชจ๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

locale

locale ์˜ต์…˜์€ ์บ˜๋ฆฐ๋”์˜ ์–ธ์–ด์™€ ์ง€์—ญ ์„ค์ •์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

  • ๋ฌธ์ž์—ด: 'en-US', 'ja', 'zh', 'de', 'fr', 'es', 'ko' ๊ฐ™์€ ์–ธ์–ด ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • Locale ๊ฐ์ฒด: ํƒ€์ž… ์•ˆ์ „์„ฑ์„ ์œ„ํ•ด ๊ฐ€์ ธ์˜จ Locale ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๊ฑฐ๋‚˜, ์ง€์›๋˜์ง€ ์•Š๋Š” ์–ธ์–ด๋ผ๋ฉด ์ง์ ‘ ๋งŒ๋“  ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
// String code
const calendar = useCalendarApp({
  locale: 'ja',
});

// Additional Locale object from the localization plugin
import { ja } from '@dayflow/plugin-localization';
const calendar = useCalendarApp({
  locale: ja,
});

// Custom Locale object
const customLocale = {
  code: 'it',
  messages: { today: 'Oggi', ... }
};
const calendar = useCalendarApp({
  locale: customLocale,
});

useEventDetailDialog

  • true๋กœ ์„ค์ •ํ•˜๋ฉด ๊ธฐ๋ณธ ๋ชจ๋‹ฌ ๋Œ€ํ™”์ƒ์ž(DefaultEventDetailDialog)๊ฐ€ ์ผœ์ง‘๋‹ˆ๋‹ค.
  • DayFlowCalendar์˜ eventDetailContent๋‚˜ eventDetailDialog์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”์–ด์˜ ์ƒํƒœ ๊ด€๋ฆฌ๋Š” ๊ทธ๋Œ€๋กœ ๋‘๊ณ  UI๋งŒ ๊ต์ฒดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

eventDetailTrigger

  • 'dbClick'(๊ธฐ๋ณธ๊ฐ’): ํ•œ ๋ฒˆ ํด๋ฆญํ•˜๋ฉด ์ด๋ฒคํŠธ๊ฐ€ ์„ ํƒ๋˜๊ณ , ๋”๋ธ” ํด๋ฆญํ•˜๋ฉด ์ƒ์„ธ ํŒจ๋„ยท๋Œ€ํ™”์ƒ์ž๊ฐ€ ์—ด๋ฆฝ๋‹ˆ๋‹ค.
  • 'click': ํ•œ ๋ฒˆ ํด๋ฆญํ•˜๋ฉด ์ƒ์„ธ ํŒจ๋„ยท๋Œ€ํ™”์ƒ์ž๊ฐ€ ๋ฐ”๋กœ ์—ด๋ฆฝ๋‹ˆ๋‹ค.
  • ํ„ฐ์น˜ ์ž…๋ ฅ์€ ์ด ์˜ต์…˜๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ๋ฅผ ํƒญํ•˜๋ฉด ์ƒ์„ธ๊ฐ€ ์—ด๋ฆฝ๋‹ˆ๋‹ค.
const calendar = useCalendarApp({
  views: [createMonthView()],
  eventDetailTrigger: 'click',
});

useCalendarHeader

  • true(๊ธฐ๋ณธ๊ฐ’): ๋‚ด์žฅ ์บ˜๋ฆฐ๋” ํ—ค๋”๋ฅผ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค.
  • false: ํ—ค๋”๋ฅผ ์™„์ „ํžˆ ์ˆจ๊น๋‹ˆ๋‹ค.

์ง์ ‘ ๋งŒ๋“  ํ—ค๋”๋ฅผ ๋ Œ๋”๋งํ•˜๋ ค๋ฉด DayFlowCalendar์˜ calendarHeader ์Šฌ๋กฏ์„ ์‚ฌ์šฉํ•˜์„ธ์š”. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์บ˜๋ฆฐ๋” ํ—ค๋”๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

readOnly

  • true: ๋‚ด์žฅ ํŽธ์ง‘ UI(๋“œ๋ž˜๊ทธ, ์ƒ์„ฑ, ํŽธ์ง‘)๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค.
  • ReadOnlyConfig: ์„ธ๋ถ€์ ์œผ๋กœ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค.
    • draggable: ๋“œ๋ž˜๊ทธ ํ—ˆ์šฉ ์—ฌ๋ถ€์ž…๋‹ˆ๋‹ค.
    • viewable: ์ด๋ฒคํŠธ ์ƒ์„ธ๋ฅผ ์—ด ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€์ž…๋‹ˆ๋‹ค.
  • calendar.addEvent(), calendar.updateEvent(), calendar.deleteEvent(), calendar.applyEventsChanges() ๊ฐ™์€ ์ฝ”๋“œ ๊ธฐ๋ฐ˜ API๋Š” ์ฝ๊ธฐ ์ „์šฉ ๋ชจ๋“œ์—์„œ๋„ ๊ทธ๋Œ€๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.
  • ์ง์ ‘ ๋งŒ๋“  UI์—์„œ๋Š” calendar.canMutateFromUI()๋กœ ์ƒ์„ฑยทํŽธ์ง‘ยท์‚ญ์ œ ์ปจํŠธ๋กค์„ ํ‘œ์‹œํ• ์ง€ ํŒ๋‹จํ•˜์„ธ์š”.
  • ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์ฝ๊ธฐ ์ „์šฉ ๋ชจ๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

allDaySortComparator

๋ชจ๋“  ๋ทฐ(์ผ, ์ฃผ, ์›”, ์•„์  ๋‹ค, ์—ฐ)์—์„œ ์ข…์ผ ์ด๋ฒคํŠธ ํ–‰์˜ ์ •๋ ฌ ์ˆœ์„œ๋ฅผ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ DayFlow๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค:

  • ์ข…์ผ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜์Œ ๋“ฑ์žฅํ•œ ์ˆœ์„œ๋Œ€๋กœ calendarId ๊ธฐ์ค€์œผ๋กœ ๋ฌถ์Šต๋‹ˆ๋‹ค
  • ์—ฌ๋Ÿฌ ๋‚ ์— ๊ฑธ์นœ ์ข…์ผ ์ด๋ฒคํŠธ๋ฅผ ํ•˜๋ฃจ์งœ๋ฆฌ ์ข…์ผ ์ด๋ฒคํŠธ๋ณด๋‹ค ์œ„์— ๋‘ก๋‹ˆ๋‹ค
  • ๊ฐ™์€ ์บ˜๋ฆฐ๋”์˜ ์ข…์ผ ์ด๋ฒคํŠธ๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ๋ชจ์•„ ๋‘ก๋‹ˆ๋‹ค

์ตœ์ข… ์ˆœ์„œ๋ฅผ ์™„์ „ํžˆ ์ง์ ‘ ์ •ํ•˜๊ณ  ์‹ถ์„ ๋•Œ๋งŒ allDaySortComparator๋ฅผ ์ „๋‹ฌํ•˜์„ธ์š”. ์ง€์ •ํ•˜๋ฉด ๋น„๊ต ํ•จ์ˆ˜์˜ ๊ฒฐ๊ณผ๊ฐ€ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๋น„๊ต ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ์ •๋ ฌ์„ ์™„์ „ํžˆ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‘ ๊ฐœ์˜ Event ๊ฐ์ฒด๋ฅผ ๋ฐ›์œผ๋ฉฐ JavaScript์˜ Array.sort์™€ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค:

const calendar = useCalendarApp({
  allDaySortComparator: (a, b) => a.title.localeCompare(b.title),
});

@dayflow/core์—์„œ ๋‚ด๋ณด๋‚ด๋Š” ํ—ฌํผ ํ•จ์ˆ˜:

ํ—ฌํผ๋™์ž‘
sortAllDayByTitle์ข…์ผ ์ด๋ฒคํŠธ๋ฅผ ์ œ๋ชฉ ๊ธฐ์ค€ ์•ŒํŒŒ๋ฒณ์ˆœ์œผ๋กœ ์ •๋ ฌํ•˜๋ฉฐ, ๊ธฐ๋ณธ ๊ทธ๋ฃนํ™” ๋ฐฉ์‹์„ ์™„์ „ํžˆ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค
import { sortAllDayByTitle } from '@dayflow/core';

const calendar = useCalendarApp({
  allDaySortComparator: sortAllDayByTitle,
});

๋Ÿฐํƒ€์ž„์— ์ •๋ ฌ์„ ๋ฐ”๊พธ๋ ค๋ฉด updateConfig๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”:

calendar.app.updateConfig({ allDaySortComparator: sortAllDayByTitle });

// Restore the default calendar-grouped ordering
calendar.app.updateConfig({ allDaySortComparator: undefined });

๊ณ ๊ธ‰ ์„ค์ • ์˜ˆ์‹œ

import {
  useCalendarApp,
  DayFlowCalendar,
  createMonthView,
  createWeekView,
  ViewType,
} from '@dayflow/react'; // or '@dayflow/vue', '@dayflow/svelte', '@dayflow/angular'
import { createSidebarPlugin } from '@dayflow/plugin-sidebar';
import '@dayflow/core/dist/styles.css';

const calendars = [
  {
    id: 'work',
    name: 'Work',
    colors: {
      eventColor: '#2563eb',
      eventSelectedColor: '#1d4ed8',
      lineColor: '#1e40af',
      textColor: '#ffffff',
    },
  },
  {
    id: 'personal',
    name: 'Personal',
    colors: {
      eventColor: '#f97316',
      eventSelectedColor: '#ea580c',
      lineColor: '#c2410c',
      textColor: '#ffffff',
    },
  },
];

export function AdvancedCalendar() {
  const calendar = useCalendarApp({
    views: [createMonthView(), createWeekView()],
    defaultView: ViewType.WEEK,
    initialDate: new Date('2024-10-01'),
    events: [],
    calendars,
    defaultCalendar: 'work',
    switcherMode: 'select',
    callbacks: {
      onEventUpdate: event => api.events.update(event),
      onVisibleRangeChange: (start, end, reason) =>
        preloadVisibleRange(start, end, reason),
    },
    plugins: [
      createSidebarPlugin({
        width: 280,
        initialCollapsed: false,
      }),
    ],
    useEventDetailDialog: true,
  });

  return <DayFlowCalendar calendar={calendar} />;
}

ํŒ: useCalendarApp์ด ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ์ฒด๋Š” ์ƒํƒœ(currentView, currentDate, events)์™€ ๋™์ž‘์„ ๋ชจ๋‘ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ฐ™์€ ์ธ์Šคํ„ด์Šค๋ฅผ DayFlowCalendar, ์ง์ ‘ ๋งŒ๋“  ํˆด๋ฐ”, ์‚ฌ์ด๋“œ ํŒจ๋„๊ณผ ๊ณต์œ ํ•˜๋ฉด ๋ชจ๋“  ๊ฒƒ์ด ๋™๊ธฐํ™”๋œ ์ƒํƒœ๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€์˜ ๋‚ด์šฉ