コンテンツスロット

DayFlow はスロットベースのアーキテクチャを採用しており、使用しているフレームワーク(React、Vue など)からカスタム UI コンポーネントをコア日暦エンジンに直接注入できます。

これは ContentSlot メカニズムによって実現されています。コアエンジンはほとんどの UI 要素に対して(Preact を使用した)デフォルトの実装を提供していますが、アプリケーションのデザインに合わせたり、特定のライブラリを使用したりするために、これらを上書きすることができます。

Table of Contents

仕組み

  1. コアがスロットを定義: @dayflow/core の内部で、特定の UI 領域が ContentSlot でラップされています。各スロットには generatorNamegeneratorArgs があります。
  2. 実装を提供: DayFlowCalendar コンポーネントにコンポーネントまたはレンダー関数を渡します。アダプターは、コアで定義された正確な場所にコンポーネントをポータル(転送)します。

利用可能なスロット

ジェネレーター名説明引数
colorPickerイベントの色に使用される小さなカラーピッカー。{ color, onChange, onChangeComplete }
createCalendarDialogColorPickerダイアログで使用されるフル機能のカラーピッカー。{ color, onChange, onAccept, onCancel, styles }
eventContent*イベントカードのカスタムレンダリング(例:eventContentDay)。{ event, viewType, isAllDay, isMobile, isSelected, isDragging, layout }
eventContextMenuイベントの右クリックコンテキストメニューのカスタム実装。{ event, onClose }
eventDetailContentイベントがクリックされたときにポップオーバー/パネルに表示される内容。{ event, isAllDay, onEventDelete, onEventUpdate, onClose, app }
eventDetailDialogイベントがクリックされたときに表示されるカスタムダイアログ。useCalendarAppuseEventDetailDialog: true が必要。{ event, isOpen, isAllDay, onEventDelete, onEventUpdate, onClose, app }
gridContextMenuカレンダーのセル/グリッドの右クリックメニューのカスタム実装。{ date, viewType, onClose }
sidebarCalendarColorPickerサイドバーのカレンダーの色に使用されるカラーピッカー。{ color, onChange, onChangeComplete }
titleBarSlotサイドバーのタイトルバー内の追加コンテンツ。{ isCollapsed, toggleCollapsed }

イベントコンテンツ

eventContent スロットを使用すると、カレンダー内でのイベントのレンダリング方法を完全にカスタマイズできます。他のスロットとは異なり、イベントコンテンツはビューごとに指定する必要があります。これは、各ビューの特定のイベント構造とレイアウトの整合性を保つためです。

ビュー固有のスロット

スロット名説明
eventContentDay日ビューの定时イベントを上書き。
eventContentWeek週ビューの定时イベントを上書き。
eventContentMonth月ビューのイベントを上書き。
eventContentYear年ビューのイベントを上書き。
eventContentAllDayDay日ビューの終日イベントを上書き。
eventContentAllDayWeek週ビューの終日イベントを上書き。
eventContentAllDayMonth月ビューの終日イベントを上書き。
eventContentAllDayYear年ビューの終日イベントを上書き。
ソースコードを表示
import { DayFlowCalendar } from '@dayflow/react'; // or '@dayflow/vue', '@dayflow/svelte', '@dayflow/angular'

export const EventContentShowcase = () => {
  return (
    <DayFlowCalendar
      calendar={calendar}
      // 日ビューのイベントレンダリングをカスタマイズ
      eventContentDay={({ event, isSelected }) => (
        <div className='custom-event-card'>
          <span>{event.title}</span>
          {/* ... カスタムアイコンやレイアウトを追加 */}
        </div>
      )}
      // 月ビューのイベントレンダリングをカスタマイズ
      eventContentMonth={({ event }) => (
        <div className='flex items-center gap-1'>
          <span>🗓️</span>
          <span className='truncate'>{event.title}</span>
        </div>
      )}
      // 簡潔にするため、他のビューの上書きは省略...
    />
  );
};

イベント詳細コンテンツ

eventDetailContent スロットを使用すると、イベントをクリックしたときに表示される詳細ポップオーバーまたはパネルのコンテンツをカスタマイズできます。

ソースコードを表示
import { DayFlowCalendar } from '@dayflow/react'; // or '@dayflow/vue', '@dayflow/svelte', '@dayflow/angular'
import { useCallback } from 'react';

export const CustomDetailPanelShowcase = () => {
  const detailPanel = useCallback(
    ({ event, onEventDelete, onEventUpdate, onClose }) => {
      return (
        <div className='p-4 space-y-3'>
          <h5 className='font-bold'>{event.title}</h5>
          <p>{event.description}</p>

          <div className='flex gap-2'>
            <button
              onClick={() => onEventUpdate({ ...event, title: '更新済み' })}
            >
              更新
            </button>
            <button onClick={() => onEventDelete(event.id)}>削除</button>
          </div>
        </div>
      );
    },
    []
  );

  return (
    <DayFlowCalendar calendar={calendar} eventDetailContent={detailPanel} />
  );
};

イベント詳細ダイアログ

イベント詳細の表示や編集にモーダル/ダイアログインターフェースを使用したい場合は、eventDetailDialog スロットを使用できます。これはモバイルファーストのアプリケーションや、複雑なイベントデータのために広いスペースが必要な場合に特に便利です。

前提条件:ダイアログモードを有効にするには、useCalendarAppuseEventDetailDialog: true を設定してください。この設定がなければスロットは呼び出されません。

代わりに無効化する場合:独自のダイアログを提供せずに組み込みのフローティングパネルを非表示にしたい場合は、スロットを使用するのではなく、useCalendarApp の設定で useEventDetailPanel: false を指定してください。

ソースコードを表示
import { DayFlowCalendar } from '@dayflow/react'; // or '@dayflow/vue', '@dayflow/svelte', '@dayflow/angular'
import { useCallback } from 'react';

export const CustomDetailDialogShowcase = () => {
  const customDialog = useCallback(({ event, isOpen, onClose }) => {
    if (!isOpen) return null;

    return (
      <div className='fixed inset-0 z-50 flex items-center justify-center bg-black/50'>
        <div className='bg-white p-6 rounded-lg shadow-xl'>
          <h2>{event.title}</h2>
          {/* ... ここでカスタムダイアログ UI を構築 */}
          <button onClick={onClose}>閉じる</button>
        </div>
      </div>
    );
  }, []);

  return (
    <DayFlowCalendar calendar={calendar} eventDetailDialog={customDialog} />
  );
};

カスタムカラーピッカーの注入

デフォルトでは、DayFlow は組み込みの BlossomColorPicker を使用します。react-colorvue-color などのライブラリを使用したい場合は、colorPicker スロットを使用して注入できます。

カラーピッカー

React の例

react-color をインストールします:

npm install react-color
pnpm add react-color
yarn add react-color
bun add react-color

DayFlowCalendar に注入します:

ソースコードを表示
import { DayFlowCalendar } from '@dayflow/react'; // or '@dayflow/vue', '@dayflow/svelte', '@dayflow/angular'
import { SketchPicker, PhotoshopPicker } from 'react-color';

function MyCalendar() {
  return (
    <DayFlowCalendar
      calendar={calendar}
      colorPicker={args => (
        <SketchPicker
          color={args.color}
          onChange={color => args.onChange({ hex: color.hex })}
        />
      )}
      createCalendarDialogColorPicker={args => (
        <PhotoshopPicker
          color={args.color}
          onChange={color => args.onChange({ hex: color.hex })}
          onAccept={args.onAccept}
          onCancel={args.onCancel}
        />
      )}
    />
  );
}

コンテキストメニュースロット

eventContextMenugridContextMenu スロットを使用すると、デフォルトの右クリックメニューを完全なカスタム React コンポーネントで置き換えられます。どちらのスロットも、メニューを閉じるための onClose コールバックを受け取ります。

  • eventContextMenu — ユーザーがイベントを右クリックしたときに発火します。{ event, onClose } を受け取ります。
  • gridContextMenu — ユーザーがカレンダーグリッドの空白領域を右クリックしたときに発火します。{ date, viewType, onClose } を受け取ります。

任意のイベントまたは空のセルを右クリックして、カスタムメニューを確認してください:

ソースコードを表示
import { DayFlowCalendar } from '@dayflow/react';
import type {
  EventContextMenuSlotArgs,
  GridContextMenuSlotArgs,
} from '@dayflow/core';
import { useCallback } from 'react';

function MyCalendar() {
  const eventContextMenu = useCallback(
    ({ event, onClose }: EventContextMenuSlotArgs) => (
      <div className='custom-menu'>
        <button
          onClick={() => {
            /* 複製 */ onClose();
          }}
        >
          複製
        </button>
        <button
          onClick={() => {
            /* 共有 */ onClose();
          }}
        >
          共有
        </button>
        <button
          onClick={() => {
            calendar.deleteEvent(event.id);
            onClose();
          }}
        >
          削除
        </button>
      </div>
    ),
    []
  );

  const gridContextMenu = useCallback(
    ({ date, onClose }: GridContextMenuSlotArgs) => (
      <div className='custom-menu'>
        <button
          onClick={() => {
            /* ここにイベントを作成 */ onClose();
          }}
        >
          新しいイベント
        </button>
        <button
          onClick={() => {
            /* リマインダーを設定 */ onClose();
          }}
        >
          リマインダー
        </button>
      </div>
    ),
    []
  );

  return (
    <DayFlowCalendar
      calendar={calendar}
      eventContextMenu={eventContextMenu}
      gridContextMenu={gridContextMenu}
    />
  );
}