Schedule

Schedule

일별·주별·월별·연별 뷰를 가진 일정 컴포넌트예요. @mantine/schedule 패키지의 컴포넌트예요. 자동 뷰 전환과 함께 모든 일정 뷰(Day, Week, Month, Year)를 결합한 통합 컴포넌트예요.

출처: 문서

본문

사용법 (Usage)

Schedule은 자동 뷰 전환과 함께 모든 일정 뷰(Day, Week, Month, Year)를 결합한 통합 컴포넌트예요. 헤더의 뷰 선택기를 사용해 뷰 간에 전환할 수 있어요.

import { Schedule } from '@mantine/schedule';
import { events } from './data';

function Demo() {
  return (
    <Schedule
      events={events}
      onEventClick={() => {}}
    />
  );
}

제어된 상태 (Controlled state)

view, onViewChange, date, onDateChange props로 현재 뷰와 날짜를 외부에서 제어할 수 있어요. 커스텀 내비게이션을 만들거나 다른 컴포넌트와 통합할 수 있게 해줘요.

import { useState } from 'react';
import { Text } from '@mantine/core';
import { Schedule, ScheduleViewLevel } from '@mantine/schedule';
import { events } from './data';

function Demo() {
  const [view, setView] = useState('week');
  const [date, setDate] = useState(new Date());

  return (
    <>
      <Text>Current view: {view}</Text>
      <Schedule
        view={view as ScheduleViewLevel}
        onViewChange={setView as (v: ScheduleViewLevel) => void}
        date={date}
        onDateChange={(newDate) => setDate(new Date(newDate))}
        events={events}
      />
    </>
  );
}

뷰별 props (View-specific props)

dayViewProps, weekViewProps, monthViewProps, yearViewProps를 통해 뷰별 props를 전달해 각 뷰를 커스터마이즈할 수 있어요. 이 props는 해당 뷰 컴포넌트로 전달돼요.

예를 들어 Day와 Week 뷰에 다른 시간 범위를 설정하거나, Month와 Year 뷰의 주 시작 요일을 커스터마이즈할 수 있어요.

import { Schedule } from '@mantine/schedule';
import { events } from './data';

function Demo() {
  return (
    <Schedule
      events={events}
      dayViewProps={{ startTime: '08:00:00', endTime: '17:00:00' }}
      weekViewProps={{ startTime: '08:00:00', endTime: '17:00:00' }}
      monthViewProps={{ firstDayOfWeek: 1 }}
      yearViewProps={{ firstDayOfWeek: 1 }}
    />
  );
}

기본 뷰 (Default view)

defaultView로 비제어 모드에서 처음 표시할 뷰를 제어할 수 있어요.

import { Schedule } from '@mantine/schedule';
import { events } from './data';

function Demo() {
  return (
    <Schedule
      events={events}
      defaultView="month"
    />
  );
}

커스텀 헤더 (Custom header)

ScheduleHeader 복합 컴포넌트를 자체 컨트롤과 함께 사용해 커스텀 헤더를 만들 수 있어요. 뷰별 props로 withHeader={false}를 전달해 모든 뷰에서 기본 헤더를 비활성화할 수 있어요.

import dayjs from 'dayjs';
import { useState } from 'react';
import {
  DateStringValue,
  getStartOfWeek,
  Schedule,
  ScheduleHeader,
  ScheduleViewLevel,
} from '@mantine/schedule';
import { events } from './data';

function getNavigationHandlers(
  date: DateStringValue,
  view: ScheduleViewLevel
) {
  const d = dayjs(date);
  switch (view) {
    case 'day':
      return {
        previous: d.subtract(1, 'day'),
        next: d.add(1, 'day'),
      };
    case 'week':
      return {
        previous: d.subtract(1, 'week'),
        next: d.add(1, 'week'),
      };
    case 'month':
      return {
        previous: d.subtract(1, 'month').startOf('month'),
        next: d.add(1, 'month').startOf('month'),
      };
    case 'year':
      return {
        previous: d.subtract(1, 'year').startOf('year'),
        next: d.add(1, 'year').startOf('year'),
      };
  }
}

function getHeaderLabel(date: DateStringValue, view: ScheduleViewLevel) {
  const d = dayjs(date);
  switch (view) {
    case 'day':
      return d.format('dddd, MMMM D, YYYY');
    case 'week': {
      const start = dayjs(
        getStartOfWeek({ date, firstDayOfWeek: 1 })
      );
      const end = start.add(6, 'day');
      if (start.month() === end.month()) {
        return `${start.format('MMM D')} – ${end.format('D, YYYY')}`;
      }
      return `${start.format('MMM D')} – ${end.format('MMM D, YYYY')}`;
    }
    case 'month':
      return d.format('MMMM YYYY');
    case 'year':
      return d.format('YYYY');
  }
}

function Demo() {
  const [date, setDate] = useState(
    dayjs().format('YYYY-MM-DD')
  );
  const [view, setView] = useState('week');

  const nav = getNavigationHandlers(date, view as ScheduleViewLevel);

  return (
    <>
      <ScheduleHeader>
        <ScheduleHeader.Control
          onClick={() => setDate(nav.previous.format('YYYY-MM-DD') as DateStringValue)}
        >
          ‹
        </ScheduleHeader.Control>
        <ScheduleHeader.Title>
          {getHeaderLabel(date, view as ScheduleViewLevel)}
        </ScheduleHeader.Title>
        <ScheduleHeader.Control
          onClick={() => setDate(nav.next.format('YYYY-MM-DD') as DateStringValue)}
        >
          ›
        </ScheduleHeader.Control>
        <ScheduleHeader.Today
          onClick={() => setDate(dayjs().format('YYYY-MM-DD') as DateStringValue)}
        />
        <ScheduleHeader.Control onClick={() => window.print()}>
          Print
        </ScheduleHeader.Control>
      </ScheduleHeader>
      <Schedule
        date={date}
        onDateChange={setDate}
        view={view as ScheduleViewLevel}
        onViewChange={setView as (v: ScheduleViewLevel) => void}
        events={events}
        dayViewProps={{ withHeader: false }}
        weekViewProps={{ withHeader: false }}
        monthViewProps={{ withHeader: false }}
        yearViewProps={{ withHeader: false }}
      />
    </>
  );
}

공통 props (Common props)

다음 props는 모든 뷰에서 공유돼요:

  • events – 표시할 이벤트
  • locale – 날짜 형식 로케일
  • radius – 테두리 반경
  • labels – i18n 라벨 재정의
  • renderEventBody – 커스텀 이벤트 렌더러
  • withDragDrop – 드래그 앤 드롭 활성화
  • onEventDrop – 드래그 앤 드롭 핸들러
  • canDragEvent – 드래그 권한 콜백
  • withEventResize – 이벤트 리사이즈 활성화
  • onEventResize – 리사이즈 핸들러
  • canResizeEvent – 리사이즈 권한 콜백
  • mode – 상호작용 모드 (default 또는 static)

이 props는 자동으로 모든 뷰에 전달돼요. 뷰별 커스터마이즈에는 dayViewProps, weekViewProps, monthViewProps, yearViewProps props를 사용해요.

어젠다 뷰 (Agenda view)

withAgenda prop으로 DayView, WeekView, MonthView의 헤더에 "Agenda" 버튼을 표시할 수 있어요. 클릭하면 현재 표시된 날짜 범위의 이벤트를 보여주는 AgendaView가 열려요.

import dayjs from 'dayjs';
import { Schedule } from '@mantine/schedule';

const today = dayjs().format('YYYY-MM-DD');
const tomorrow = dayjs().add(1, 'day').format('YYYY-MM-DD');

const events = [
  {
    id: 'standup',
    title: 'Morning Standup',
    start: `${today} 09:00:00`,
    end: `${today} 09:30:00`,
    color: 'blue',
  },
  {
    id: 'team-meeting',
    title: 'Team Meeting',
    start: `${today} 10:00:00`,
    end: `${today} 11:30:00`,
    color: 'green',
  },
  {
    id: 'weekly-review-series',
    title: 'Weekly review',
    start: `${dayjs(today).startOf('week').format('YYYY-MM-DD')} 16:00:00`,
    end: `${dayjs(today).startOf('week').format('YYYY-MM-DD')} 17:00:00`,
    color: 'orange',
    recurrence: {
      rrule: 'FREQ=WEEKLY;COUNT=8',
    },
  },
];

function Demo() {
  return (
    <Schedule events={events} withAgenda />
  );
}

드래그 앤 드롭 (Drag and drop)

withEventsDragAndDrop prop으로 이벤트 드래그 앤 드롭을 활성화할 수 있어요. 이벤트는 모든 뷰에서 서로 다른 타임 슬롯과 날짜로 드래그할 수 있어요.

import { useState } from 'react';
import dayjs from 'dayjs';
import { Schedule, ScheduleEventData } from '@mantine/schedule';

const today = dayjs().format('YYYY-MM-DD');
const tomorrow = dayjs().add(1, 'day').format('YYYY-MM-DD');

const initialEvents: ScheduleEventData[] = [
  {
    id: 1,
    title: 'Morning Standup',
    start: `${today} 09:00:00`,
    end: `${today} 09:30:00`,
    color: 'blue',
  },
  {
    id: 2,
    title: 'Team Meeting',
    start: `${today} 10:00:00`,
    end: `${today} 11:30:00`,
    color: 'green',
  },
  {
    id: 6,
    title: 'All Day Conference',
    start: `${today} 00:00:00`,
    end: dayjs(today).add(1, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss'),
    color: 'red',
  },
];

function Demo() {
  const [events, setEvents] = useState(initialEvents);

  const handleEventDrop = ({ eventId, newStart, newEnd }: { eventId: string | number; newStart: string; newEnd: string }) => {
    setEvents((prev) =>
      prev.map((event) =>
        event.id === eventId ? { ...event, start: newStart, end: newEnd } : event
      )
    );
  };

  return (
    <Schedule
      events={events}
      onEventDrop={handleEventDrop}
      withEventsDragAndDrop
    />
  );
}

이벤트 생성 및 업데이트 (Create and update events)

withDragSlotSelect prop으로 사용자가 타임 슬롯이나 날짜 셀을 가로질러 드래그해 범위를 선택할 수 있게 해요. 드래그가 끝나면 onSlotDragEnd 콜백이 범위의 시작·종료 날짜로 호출돼요. onTimeSlotClick, onAllDaySlotClick, onDayClick, onEventClick 콜백과 결합하면 모든 뷰에서 완전한 이벤트 생성·편집 경험을 구현할 수 있어요.

import dayjs from 'dayjs';
import { useRef, useState } from 'react';
import { PlusIcon } from '@phosphor-icons/react';
import { ActionIcon, Box, Group } from '@mantine/core';
import { Schedule, ScheduleEventData } from '@mantine/schedule';
import { EventData, EventForm } from './EventForm';
import { events } from './events';

function Demo() {
  const [allEvents, setAllEvents] = useState(events);
  const [formOpened, setFormOpened] = useState(false);
  const [selectedEventData, setSelectedEventData] = useState(null);
  const mobileSelectedDate = useRef(dayjs().format('YYYY-MM-DD'));

  const handleTimeSlotClick = ({ slotStart, slotEnd }: { slotStart: string; slotEnd: string }) => {
    setSelectedEventData({
      title: '',
      start: new Date(slotStart),
      end: new Date(slotEnd),
      color: 'blue',
    });
    setFormOpened(true);
  };

  const handleAllDaySlotClick = (slotDate: string) => {
    setSelectedEventData({
      title: '',
      start: dayjs(slotDate).startOf('day').toDate(),
      end: dayjs(slotDate).endOf('day').toDate(),
      color: 'blue',
    });
    setFormOpened(true);
  };

  const handleDayClick = (date: string) => {
    setSelectedEventData({
      title: '',
      start: dayjs(date).startOf('day').toDate(),
      end: dayjs(date).endOf('day').toDate(),
      color: 'blue',
    });
    setFormOpened(true);
  };

  const handleEventClick = (event: ScheduleEventData) => {
    setSelectedEventData({
      id: event.id,
      title: event.title,
      start: new Date(event.start),
      end: new Date(event.end),
      color: event.color || 'blue',
    });
    setFormOpened(true);
  };

  const handleSubmit = (values: EventData) => {
    if (values.id) {
      setAllEvents((prev) =>
        prev.map((event) =>
          event.id === values.id
            ? {
                ...event,
                title: values.title,
                start: dayjs(values.start).toISOString(),
                end: dayjs(values.end).toISOString(),
                color: values.color || 'blue',
              }
            : event
        )
      );
    } else {
      setAllEvents((prev) => [
        ...prev,
        {
          id: Math.random().toString(36).substring(2, 11),
          title: values.title,
          start: dayjs(values.start).toISOString(),
          end: dayjs(values.end).toISOString(),
          color: values.color || 'blue',
        },
      ]);
    }
  };

  const handleSlotDragEnd = (rangeStart: string, rangeEnd: string) => {
    setSelectedEventData({
      title: '',
      start: new Date(rangeStart),
      end: new Date(rangeEnd),
      color: 'blue',
    });
    setFormOpened(true);
  };

  const handleDeleteEvent = () => {
    if (selectedEventData?.id) {
      setAllEvents((prev) => prev.filter((e) => e.id !== selectedEventData.id));
    }
  };

  const handleCreateEvent = () => {
    const selectedDate = mobileSelectedDate.current;
    setSelectedEventData({
      title: '',
      start: dayjs(selectedDate).startOf('day').toDate(),
      end: dayjs(selectedDate).endOf('day').toDate(),
      color: 'blue',
    });
    setFormOpened(true);
  };

  return (
    <>
      <Schedule
        events={allEvents}
        onTimeSlotClick={handleTimeSlotClick}
        onAllDaySlotClick={handleAllDaySlotClick}
        onDayClick={handleDayClick}
        onEventClick={handleEventClick}
        onSlotDragEnd={handleSlotDragEnd}
        withDragSlotSelect
      />
      <EventForm
        setFormOpened={setFormOpened}
        onExitTransitionEnd={() => setSelectedEventData(null)}
        values={selectedEventData}
        onSubmit={handleSubmit}
        onDelete={selectedEventData?.id ? handleDeleteEvent : undefined}
      />
    </>
  );
}

외부 드래그 앤 드롭 (External drag and drop)

onExternalEventDrop을 사용하면 컴포넌트 바깥에서 일정으로 항목을 끌어올 수 있어요. 외부 항목은 onDragStart 중에 dataTransfer에 데이터를 설정해야 해요. 콜백은 DataTransfer 객체와 드롭 대상 날짜시간을 받아요.

import { useRef, useState } from 'react';
import dayjs from 'dayjs';
import { Box, Grid, Text } from '@mantine/core';
import { Schedule, ScheduleEventData } from '@mantine/schedule';

const sidebarItems = [
  { title: 'Quick Sync', duration: 30, color: 'teal' },
  { title: 'Workshop', duration: 120, color: 'orange' },
  { title: 'One-on-One', duration: 60, color: 'violet' },
];

function Demo() {
  const [events, setEvents] = useState([]);
  const nextId = useRef(1);

  const handleExternalDrop = (dataTransfer: DataTransfer, dropDateTime: string) => {
    const raw = dataTransfer.getData('text/plain');
    if (!raw) {
      return;
    }

    const data = JSON.parse(raw);
    const start = dayjs(dropDateTime);
    const end = start.add(data.duration, 'minutes');

    setEvents((prev) => [
      ...prev,
      {
        id: nextId.current++,
        title: data.title,
        start: start.format('YYYY-MM-DD HH:mm:ss'),
        end: end.format('YYYY-MM-DD HH:mm:ss'),
        color: data.color,
      },
    ]);
  };

  const handleEventDrop = ({ eventId, newStart, newEnd }: { eventId: string | number; newStart: string; newEnd: string }) => {
    setEvents((prev) =>
      prev.map((event) =>
        event.id === eventId ? { ...event, start: newStart, end: newEnd } : event
      )
    );
  };

  return (
    <Grid>
      <Grid.Col span={4}>
        <Text>Drag to schedule</Text>
        {sidebarItems.map((item) => (
          <div
            draggable
            onDragStart={(e) => {
              e.dataTransfer.setData('text/plain', JSON.stringify(item));
              e.dataTransfer.effectAllowed = 'copy';
            }}
            style={{ padding: '8px 12px', marginBottom: 8, cursor: 'grab' }}
          >
            {item.title}
          </div>
        ))}
      </Grid.Col>
      <Grid.Col span={8}>
        <Schedule events={events} onExternalEventDrop={handleExternalDrop} onEventDrop={handleEventDrop} />
      </Grid.Col>
    </Grid>
  );
}

양방향 드래그 앤 드롭 (Bidirectional drag and drop)

onExternalEventDrop과 withEventsDragAndDrop을 함께 사용하면 양방향 드래그 앤 드롭을 활성화할 수 있어요. 사이드바에서 끌어온 항목은 목록에서 제거되고 일정에 추가돼요. 일정에서 사이드바로 끌어온 이벤트는 일정에서 제거돼요. 이벤트를 드래그할 때 일정은 dataTransfer에 { eventId }를 가진 application/json을 설정하며, 사이드바 드롭 존이 이를 읽어 이벤트를 식별해요.

import { useRef, useState } from 'react';
import dayjs from 'dayjs';
import { Box, Grid, Text } from '@mantine/core';
import { Schedule, ScheduleEventData } from '@mantine/schedule';

interface SidebarItem {
  title: string;
  duration: number;
  color: string;
}

const initialSidebarItems: SidebarItem[] = [
  { title: 'Quick Sync', duration: 30, color: 'teal' },
  { title: 'Workshop', duration: 120, color: 'orange' },
  { title: 'One-on-One', duration: 60, color: 'violet' },
];

function Demo() {
  const [sidebarItems, setSidebarItems] = useState(initialSidebarItems);
  const [events, setEvents] = useState([]);
  const [sidebarHighlight, setSidebarHighlight] = useState(false);
  const nextId = useRef(1);

  const handleExternalDrop = (dataTransfer: DataTransfer, dropDateTime: string) => {
    const raw = dataTransfer.getData('text/plain');
    if (!raw) {
      return;
    }

    const data = JSON.parse(raw);
    const start = dayjs(dropDateTime);
    const end = start.add(data.duration, 'minutes');

    setEvents((prev) => [
      ...prev,
      {
        id: nextId.current++,
        title: data.title,
        start: start.format('YYYY-MM-DD HH:mm:ss'),
        end: end.format('YYYY-MM-DD HH:mm:ss'),
        color: data.color,
      },
    ]);
    setSidebarItems((prev) => prev.filter((item) => item.title !== data.title));
  };

  const handleEventDrop = ({ eventId, newStart, newEnd }: { eventId: string | number; newStart: string; newEnd: string }) => {
    setEvents((prev) =>
      prev.map((event) =>
        event.id === eventId ? { ...event, start: newStart, end: newEnd } : event
      )
    );
  };

  const handleSidebarDrop = (e: React.DragEvent) => {
    e.preventDefault();
    setSidebarHighlight(false);
    const raw = e.dataTransfer.getData('application/json');
    if (!raw) {
      return;
    }

    const { eventId } = JSON.parse(raw);
    const event = events.find((ev) => String(ev.id) === String(eventId));
    if (!event) {
      return;
    }

    const duration = dayjs(event.end).diff(dayjs(event.start), 'minutes');
    setSidebarItems((prev) => [
      ...prev,
      { title: event.title, duration, color: event.color || 'blue' },
    ]);
    setEvents((prev) => prev.filter((ev) => ev.id !== event.id));
  };

  return (
    <Grid>
      <Grid.Col span={4}>
        <div
          onDragOver={(e) => {
            e.preventDefault();
            e.dataTransfer.dropEffect = 'move';
            setSidebarHighlight(true);
          }}
          onDragLeave={() => setSidebarHighlight(false)}
          onDrop={handleSidebarDrop}
          style={{ padding: 8, borderRadius: 8 }}
        >
          <Text>Unscheduled</Text>
          {sidebarItems.map((item) => (
            <div
              draggable
              onDragStart={(e) => {
                e.dataTransfer.setData('text/plain', JSON.stringify(item));
                e.dataTransfer.effectAllowed = 'copy';
              }}
              style={{ padding: '8px 12px', marginBottom: 8, cursor: 'grab' }}
            >
              {item.title}
            </div>
          ))}
          {sidebarItems.length === 0 && (
            <Text>Drag events here to unschedule</Text>
          )}
        </div>
      </Grid.Col>
      <Grid.Col span={8}>
        <Schedule
          events={events}
          onExternalEventDrop={handleExternalDrop}
          onEventDrop={handleEventDrop}
          withEventsDragAndDrop
        />
      </Grid.Col>
    </Grid>
  );
}

이벤트 리사이즈 (Event resize)

withEventResize prop으로 이벤트 리사이즈를 활성화할 수 있어요. 사용자는 이벤트의 위나 아래 가장자리를 끌어 시작 또는 종료 시간을 조정할 수 있어요. onEventResize 콜백으로 리사이즈를 처리해요. 이벤트 리사이즈는 Day와 Week 뷰에서 동작하며 드래그 앤 드롭과 결합할 수 있어요.

import { useState } from 'react';
import dayjs from 'dayjs';
import { Schedule, ScheduleEventData } from '@mantine/schedule';

const today = dayjs().format('YYYY-MM-DD');
const tomorrow = dayjs().add(1, 'day').format('YYYY-MM-DD');

const initialEvents: ScheduleEventData[] = [
  {
    id: 1,
    title: 'Morning Standup',
    start: `${today} 09:00:00`,
    end: `${today} 09:30:00`,
    color: 'blue',
  },
  {
    id: 2,
    title: 'Team Meeting',
    start: `${today} 10:00:00`,
    end: `${today} 11:30:00`,
    color: 'green',
  },
];

function Demo() {
  const [events, setEvents] = useState(initialEvents);

  const handleEventUpdate = ({ eventId, newStart, newEnd }: { eventId: string | number; newStart: string; newEnd: string }) => {
    setEvents((prev) =>
      prev.map((event) =>
        event.id === eventId ? { ...event, start: newStart, end: newEnd } : event
      )
    );
  };

  return (
    <Schedule
      events={events}
      withEventResize
      onEventResize={handleEventUpdate}
      onEventDrop={handleEventUpdate}
      withEventsDragAndDrop
    />
  );
}

반복 이벤트 (Recurring events)

Schedule은 각 뷰에서 표시된 날짜 범위에 대해 반복 이벤트를 자동으로 확장해요. 전체 문서는 반복 이벤트 가이드를 참고해요.

import { useState } from 'react';
import { Schedule } from '@mantine/schedule';

const events = [
  {
    id: 'schedule-series',
    title: 'Weekly planning (series)',
    start: '2024-01-15 10:00:00',
    end: '2024-01-15 11:00:00',
    color: 'blue',
    recurrence: {
      rrule: 'FREQ=WEEKLY;BYDAY=MO,WE;COUNT=16',
      exdate: ['2024-01-17 10:00:00'],
    },
  },
  {
    id: 'schedule-series-override',
    title: 'Weekly planning (moved one occurrence)',
    start: '2024-01-17 16:00:00',
    end: '2024-01-17 17:00:00',
    color: 'grape',
    recurringEventId: 'schedule-series',
    recurrenceId: '2024-01-17 10:00:00',
  },
];

function Demo() {
  const [date, setDate] = useState('2024-01-15');
  return <Schedule date={date} onDateChange={setDate} events={events} />;
}

배경 이벤트 (Background events)

이벤트에 display="background"를 설정하면 전체 너비, 반투명, 비상호작용 블록으로 일반 이벤트 뒤에 렌더링돼요. 배경 이벤트는 부재, 점심 시간, 집중 시간 또는 다른 차단 기간을 표시할 때 유용해요. 배경 이벤트는 Day, Week, Month 뷰에서 동작해요.

import dayjs from 'dayjs';
import { useState } from 'react';
import { Schedule, ScheduleEventData } from '@mantine/schedule';

const today = dayjs().format('YYYY-MM-DD');

const events: ScheduleEventData[] = [
  {
    id: 'lunch-block',
    title: 'Lunch break',
    start: `${today} 12:00:00`,
    end: `${today} 13:00:00`,
    color: 'gray',
    display: 'background',
  },
  {
    id: 'focus-time',
    title: 'Focus time',
    start: `${today} 14:00:00`,
    end: `${today} 16:00:00`,
    color: 'blue',
    display: 'background',
  },
  {
    id: 'team-meeting',
    title: 'Team meeting',
    start: `${today} 10:00:00`,
    end: `${today} 11:00:00`,
    color: 'violet',
  },
];

function Demo() {
  const [date, setDate] = useState(today);

  return (
    <Schedule date={date} onDateChange={setDate} events={events} />
  );
}

반응형 레이아웃 (Responsive layout)

Schedule은 layout="responsive" prop을 지원하며, 컨테이너 너비에 따라 뷰를 자동으로 전환해요. 컨테이너를 아래로 조정하면 뷰가 변경되는 것을 볼 수 있어요.

import { Box } from '@mantine/core';
import { Schedule } from '@mantine/schedule';
import { events } from './data';

function Demo() {
  return (
    <Box maw={800}>
      <Schedule events={events} layout="responsive" />
    </Box>
  );
}

뷰 컴포넌트 (View components)

개별 뷰를 더 세밀하게 제어하려면 뷰 컴포넌트를 직접 사용할 수 있어요:

  • DayView – 타임 슬롯이 있는 단일 날짜
  • WeekView – 타임 슬롯이 있는 전체 주
  • MonthView – 달력 월 그리드
  • YearView – 전체 연도 개요

더 알아보기 (Learn more)