内容插槽

DayFlow 采用了基于插槽的架构,允许您直接从所使用的框架(React、Vue 等)中注入自定义 UI 组件到核心日历引擎中。

这是通过 ContentSlot 机制实现的。虽然核心引擎为大多数 UI 元素提供了默认实现(使用 Preact),但您可以覆盖它们以符合您的应用设计或使用特定的第三方库。

Table of Contents

工作原理

  1. 核心定义插槽:在 @dayflow/core 内部,某些 UI 区域被包装 in a ContentSlot 中。每个插槽都有一个 generatorName(生成器名称)和 generatorArgs(生成器参数)。
  2. 您提供实现:您将组件或渲染函数传递给 DayFlowCalendar 组件。适配器随后会将您的组件以 Portal(传送门)的形式渲染到核心定义的精确位置。

可用插槽

生成器名称描述参数
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点击事件时显示的自定义对话框。需要在 useCalendarApp 中设置 useEventDetailDialog: true{ event, isOpen, isAllDay, onEventDelete, onEventUpdate, onClose, app }
gridContextMenu自定义日历格子/网格的右键菜单。{ date, viewType, onClose }
sidebarCalendarColorPicker用于侧边栏日历颜色的颜色选择器。{ color, onChange, onChangeComplete }
titleBarSlot侧边栏标题栏中的额外内容。{ isCollapsed, toggleCollapsed }

事件内容

eventContent 插槽允许您完全自定义事件在日历中的渲染方式。与其他插槽不同,事件内容必须针对每个视图分别指定,以确保布局与每个视图特定的事件结构保持一致。

视图特定插槽

插槽名称描述
eventContentDay重写天视图(Day View)中的定时事件。
eventContentWeek重写周视图(Week View)中的定时事件。
eventContentMonth重写月视图(Month View)中的事件。
eventContentYear重写年视图(Year View)中的事件。
eventContentAllDayDay重写天视图(Day View)中的全天事件。
eventContentAllDayWeek重写周视图(Week View)中的全天事件。
eventContentAllDayMonth重写月视图(Month View)中的全天事件。
eventContentAllDayYear重写年视图(Year View)中的全天事件。
查看源代码
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 插槽。这对于移动优先的应用或需要更多空间展示复杂事件数据的情况特别有用。

前提条件:在 useCalendarApp 中设置 useEventDetailDialog: 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}
    />
  );
}