Components

Calendar

A date field component that allows users to enter and edit a single date or a range of dates.

Overview

单月日历:‹ › 翻月、outside 日期灰显、today 与选中态用 primary 底色。

GPUI · Live previewGPUI WASM

Installation

Calendar 是单个 Rust 文件(src/calendar.rs),日期数学用 Howard Hinnant 的 civil-from-days 算法自实现 —— 不依赖 chrono。浏览器里 "today" 走 js_sys::Date,因为 SystemTime::now() 在 wasm32 上会 panic。

Cargo.toml
[dependencies]gpui-kit = "0.6.6"[target.'cfg(target_family = "wasm")'.dependencies]js-sys = "=0.3.98"   # browser "today" — SystemTime::now panics on wasm

Download runnable example

Terminal
# Download the runnable example crate, then:cargo run --locked -- --calendar# Other demos:cargo run --locked -- --calendar rangecargo run --locked -- --calendar dropdowncargo run --locked -- --calendar presetscargo run --locked -- --calendar datetimecargo run --locked -- --calendar booked

Usage

Calendar 是一个 entity(持 visible month、selection、disabled 集合),宿主在 cx.new(..) 里构造并 cx.subscribe 收 CalendarSelectEvent。

Example.rs
use justdo_command::calendar::{Calendar, CalendarMode, CalendarSelectEvent, Date};// Calendar is an entity — host it in a view and subscribe for selections.let calendar = cx.new(|_| {    Calendar::new()        .selected(Date::today())        .dropdown(true)});cx.subscribe(&calendar, |_, _, event: &CalendarSelectEvent, cx| {    // CalendarSelection::Single(date) | ::Range { start, end }    cx.notify();}).detach();// in render(): .child(calendar.clone())

网页预览与桌面端运行同一份 Rust / GPUI 组件。

Composition

结构对齐 shadcn/ui 的 Calendar / RangeCalendar。

Structure
Calendar                  entity — owns visible month + selection state├── header                ‹ prev · caption · next ›│     caption             text, or "September ⌄  2026 ⌄" with .dropdown(true)│     popup               4×3 month grid / ±5-year grid overlay├── weekday row           S M T W T F S└── day grid              32px cells — outside days dimmed    Date                  proleptic-Gregorian math, no external crate    CalendarSelectEvent   emitted on every pick (Single / Range)
Example.rs
// Cell states are computed per day in day_cell():is_today     → accent backgroundis_selected  → primary bg + primary-foreground inkrange start/end → primary, outer rounded cornerrange middle    → accent bg, square cornersoutside         → muted inkdisabled_dates  → muted + 45% opacity, clicks intercepted

Notes

Range picking. .mode(CalendarMode::Range) 下首点定 start、次点定 end(点在 start 之前会自动交换),第三次点击重开新 range。.months(2) 并排渲染相邻两月,‹ › 只出现在首/末格。

Caption dropdown. .dropdown(true) 把 caption 换成 "September ⌄ / 2026 ⌄" 两个 ghost 按钮,点击展开 4×3 月格或前后 ±5 年网格;弹层用 block_mouse_except_scroll() 拦截点击,不会穿透到下层日期格。

Outside days. 上/下月补位的日期灰显但可点 —— 点了之后视图跳到该日期所在月(shadcn 同款行为)。

Accessibility

Keyboard & focus

每一天是 gpui_base::Button —— Tab 聚焦、Enter/Space 激活、focus-visible 描边都由原语提供;icon-only 翻月按钮带 a11y_label("Previous month")。

Disabled dates

.disabled_dates(..) 内的日期被原语标记为 disabled —— 半透明渲染且点击拦截,配合预设表示已订/不可用。

API Reference

Calendar entity 的 builder API 与事件。

APISignatureNotes
Calendar::new()-> CalendarEntity; visible month defaults to today.
.mode(..)CalendarModeSingle | Range picking.
.months(..)usize1 or 2 month columns side by side.
.visible_month(..)(year, month)First visible month.
.selected(..)DateInitial single selection.
.range(..)(start, end)Initial range selection.
.disabled_dates(..)Vec<Date>Unpickable dates (booked).
.dropdown(..)boolCaption → month/year select buttons.
CalendarSelectEventselection: CalendarSelectionSingle(Date) | Range { start, end }.
Date{ year, month, day }today(), add_days(..); no external crate.

Source & inspiration

结构与视觉参考 shadcn/ui Calendar (React Aria) 。本页交互由 Rust / GPUI 绘制,基础样式来自 gpui-kit 。