@sanguo-dev/calendar-ui 0.0.0-stage → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +193 -2
- package/dist/index.cjs +1079 -0
- package/dist/index.d.cts +286 -0
- package/dist/index.d.mts +286 -0
- package/dist/index.mjs +1074 -0
- package/package.json +59 -4
- package/src/calendar.ts +785 -0
- package/src/components/day.ts +79 -0
- package/src/components/grid.ts +181 -0
- package/src/components/header.ts +69 -0
- package/src/components/nav.ts +20 -0
- package/src/components/weekdays.ts +19 -0
- package/src/index.ts +26 -0
- package/src/locales/en-US.ts +28 -0
- package/src/locales/index.ts +19 -0
- package/src/locales/zh-CN.ts +13 -0
- package/src/style.css +388 -0
- package/src/types/calendar.ts +267 -0
- package/src/types/components.ts +69 -0
- package/src/types/index.ts +32 -0
- package/src/types/locale.ts +26 -0
- package/src/types/utils.ts +28 -0
- package/src/utils/date.ts +82 -0
- package/src/utils/days.ts +88 -0
- package/src/utils/dom.ts +11 -0
- package/src/utils/motion.ts +39 -0
package/README.md
CHANGED
|
@@ -1,3 +1,194 @@
|
|
|
1
|
-
#
|
|
1
|
+
# calendar-ui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
纯 DOM、零依赖的公历日历核心,不依赖任何农历 / 节假日库。副标题、左上角标记和透传数据通过 `CalendarAdapter` 注入,第三方可以接自己的日历实现。
|
|
4
|
+
|
|
5
|
+
## 用法
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { createCalendarUI } from "@sanguo-dev/calendar-ui";
|
|
9
|
+
import "@sanguo-dev/calendar-ui/style.css";
|
|
10
|
+
|
|
11
|
+
const instance = createCalendarUI(container, {
|
|
12
|
+
weekStartsOn: 1, // 0 周日 / 1 周一(默认)
|
|
13
|
+
locale: "zh-CN", // 或 "en-US" / 自定义语言包
|
|
14
|
+
onSelect: (day) => console.log(day.year, day.month, day.day, day.data),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
instance.nextMonth();
|
|
18
|
+
instance.select("2026-12-01");
|
|
19
|
+
instance.destroy();
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 选项
|
|
23
|
+
|
|
24
|
+
| 选项 | 类型 | 说明 |
|
|
25
|
+
| --------------- | --------------------------------------- | --------------------------------- |
|
|
26
|
+
| `initialDate` | `CalendarDateInput` | 初始日期,默认今天 |
|
|
27
|
+
| `minDate` | `CalendarDateInput` | 最小可选日期(包含) |
|
|
28
|
+
| `maxDate` | `CalendarDateInput` | 最大可选日期(包含) |
|
|
29
|
+
| `disabledDates` | `readonly CalendarDateInput[]` | 禁止选中的日期 |
|
|
30
|
+
| `mode` | `"single" \| "range"` | 选择模式,默认 `"single"` |
|
|
31
|
+
| `months` | `1 \| 2` | 范围模式月数,`2` 为相邻两月 |
|
|
32
|
+
| `animation` | `CalendarAnimationOptions` | 动画与折叠配置,默认全关 |
|
|
33
|
+
| `subtitle` | `SubtitleRenderer` | 自定义副标题,优先于 adapter |
|
|
34
|
+
| `weekStartsOn` | `0 \| 1` | 一周从哪天开始,默认 1 |
|
|
35
|
+
| `locale` | `CalendarLocale \| CalendarLocaleName` | 界面语言,默认 `"zh-CN"` |
|
|
36
|
+
| `theme` | `"light" \| "dark" \| "auto"` | 主题,默认 `"auto"` |
|
|
37
|
+
| `header` | `boolean` | 是否显示头部,默认 `true` |
|
|
38
|
+
| `renderHeader` | `HeaderRenderer` | 自定义头部,替换默认的 `‹ 标题 ›` |
|
|
39
|
+
| `adapter` | `CalendarAdapter<TData>` | 日历适配器;不传就是纯公历 |
|
|
40
|
+
| `onSelect` | `(day: CalendarDay<TData>) => void` | 选中某一天时触发 |
|
|
41
|
+
| `onRangeChange` | `(range: CalendarRange) => void` | 范围变化时触发 |
|
|
42
|
+
| `onMonthChange` | `(year: number, month: number) => void` | 切换月份时触发 |
|
|
43
|
+
|
|
44
|
+
## 范围选择
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
const instance = createCalendarUI(container, {
|
|
48
|
+
mode: "range",
|
|
49
|
+
months: 2, // 相邻两个月;默认 1
|
|
50
|
+
initialDate: "2026-10-15",
|
|
51
|
+
onRangeChange: (range) => console.log(range),
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
instance.getRange();
|
|
55
|
+
instance.setRange("2026-10-20", "2026-10-05"); // 自动交换
|
|
56
|
+
instance.setRange("2026-10-05"); // 只设起点
|
|
57
|
+
instance.clearRange();
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- 第一次点击设起点,第二次设终点;
|
|
61
|
+
- 反向选择自动交换;
|
|
62
|
+
- 第三次点击重新开始;
|
|
63
|
+
- `months: 2` 显示相邻两月,移动端自动上下排列;
|
|
64
|
+
- `day.isRangeStart` / `isRangeEnd` / `isInRange` 可用于自定义样式;
|
|
65
|
+
- `setRange` 触发 `onRangeChange`,不触发 `onSelect`。
|
|
66
|
+
|
|
67
|
+
## 折叠
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
const instance = createCalendarUI(container, {
|
|
71
|
+
animation: {
|
|
72
|
+
collapse: {},
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- 不配置 `animation.collapse` 就没有底部箭头;
|
|
78
|
+
- 配置后默认展开,`collapse.defaultCollapsed: true` 可默认折叠;
|
|
79
|
+
- 折叠后显示当前选中行;
|
|
80
|
+
- 范围模式折叠时显示起点行和终点行(同一周只显示一行);
|
|
81
|
+
- 双视图下每个月份只显示属于该月的端点行;
|
|
82
|
+
- 折叠/展开只通过底部箭头操作,没有额外的实例方法。
|
|
83
|
+
|
|
84
|
+
## 动画
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
const instance = createCalendarUI(container, {
|
|
88
|
+
animation: {
|
|
89
|
+
slide: { duration: 220, easing: "ease" }, // 传 {} 即开启
|
|
90
|
+
collapse: { duration: 200, easing: "ease", defaultCollapsed: false }, // 传 {} 即开启
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
- 动画默认关闭:不配置 `animation.slide` 时翻月直接切换;
|
|
96
|
+
- 翻月:旧月份向左/右滑出,新月份从另一侧滑入,两页首尾相接;
|
|
97
|
+
- 折叠:行高、透明度和间距一起过渡;
|
|
98
|
+
- 首次渲染不播放折叠动画;
|
|
99
|
+
- `prefers-reduced-motion: reduce` 下关闭过渡;
|
|
100
|
+
- 也可以通过 `.cui` 的 `--cui-month-duration`、`--cui-collapse-duration` 等 CSS 变量覆盖。
|
|
101
|
+
|
|
102
|
+
## 自定义 subtitle
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
const instance = createCalendarUI(container, {
|
|
106
|
+
subtitle: (day) => (day.month === 10 && day.day === 1 ? "国庆" : null),
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
- 用户 `subtitle` 优先于 `adapter.subtitle`;
|
|
111
|
+
- 返回 `null` / `undefined` 时回退 adapter;
|
|
112
|
+
- 返回 `""` 时明确隐藏;
|
|
113
|
+
- `onSelect` 的 `day.subtitle` 是最终值。
|
|
114
|
+
|
|
115
|
+
## 日期输入
|
|
116
|
+
|
|
117
|
+
`CalendarDateInput = Date | string`,字符串支持 `2026-10-01`、`2026-10-1`、`2026/10/01`、`2026/10/1`,按本地年月日解析,不经过 `new Date(string)`。
|
|
118
|
+
|
|
119
|
+
## 日期约束
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
const instance = createCalendarUI(container, {
|
|
123
|
+
minDate: "2026-10-05",
|
|
124
|
+
maxDate: "2026-10-20",
|
|
125
|
+
disabledDates: ["2026-10-12"],
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
instance.setMinDate("2026-10-06");
|
|
129
|
+
instance.setMaxDate("2026-10-25");
|
|
130
|
+
instance.getMinDate();
|
|
131
|
+
instance.getMaxDate();
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
- `minDate` / `maxDate` 包含边界,可单独或同时设置;
|
|
135
|
+
- `disabledDates` 按本地年月日比较,内部用 `Set` 查询;
|
|
136
|
+
- 边界外和禁用日期渲染为 disabled,点击、键盘、`select()` 都不可选中;
|
|
137
|
+
- 初始日期越界/被禁用时,自动寻找最近的可选日期;
|
|
138
|
+
- 翻月按钮在边界月份禁用,`setMonth()` 越界会夹到边界;
|
|
139
|
+
- `minDate > maxDate`、无效日期、没有任何可选日期都会抛错;
|
|
140
|
+
- setter 失败时不会修改现有状态;
|
|
141
|
+
- `disabledDates` 保持数组,不提供 predicate 函数。
|
|
142
|
+
|
|
143
|
+
## 主题
|
|
144
|
+
|
|
145
|
+
内置 `light` / `dark` / `auto` 主题:
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
const instance = createCalendarUI(container, { theme: "dark" });
|
|
149
|
+
|
|
150
|
+
instance.getTheme(); // "dark"
|
|
151
|
+
instance.setTheme("light");
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
- 主题写到 `.cui[data-theme="light|dark|auto"]`;
|
|
155
|
+
- `setTheme()` 只改 `data-theme`,不重建 DOM;
|
|
156
|
+
- `auto` 跟随最近的祖先 `data-theme`,没有则跟随系统;
|
|
157
|
+
- 两套主题共用布局,只改变量;
|
|
158
|
+
- 可通过 `--cui-bg`、`--cui-fg`、`--cui-accent`、`--cui-rest` 等变量覆盖;\n- 周末的日期数字固定用 `--cui-rest`(和法定节假日同色),由 `.cui__day.is-weekend` 控制,与节假日数据无关。
|
|
159
|
+
|
|
160
|
+
## 适配器
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
interface CalendarAdapter<TData = unknown> {
|
|
164
|
+
readonly id: string;
|
|
165
|
+
decorateMonth(input: MonthInput): ReadonlyArray<DayDecoration<TData> | null>;
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
`decorateMonth` 每次拿到 42 个日期,返回同长度的装饰数组:
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
{
|
|
173
|
+
subtitle?: string; // 格子副标题
|
|
174
|
+
badge?: { text: string; tone?: string }; // 左上角标记,tone 写到 data-tone
|
|
175
|
+
data?: TData; // 透传给 onSelect
|
|
176
|
+
ariaLabel?: string; // 覆盖默认 aria-label
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
核心不解释 `badge` 和 `data` 的含义;`tone` 对应的颜色由 CSS 决定(内置 `rest` / `work` 两种,可通过 `--cui-rest`、`--cui-accent` 覆盖)。
|
|
181
|
+
|
|
182
|
+
官方农历适配器见 `@sanguo-dev/calendar-ui-lunar`;第三方也可以按这个接口接入自己的日历。
|
|
183
|
+
|
|
184
|
+
## 路线图
|
|
185
|
+
|
|
186
|
+
后续功能(翻月动画、折叠当前行、范围选择、min/max、禁用日期、自定义 subtitle)记录在 [TODO.md](TODO.md)。
|
|
187
|
+
|
|
188
|
+
## 开发
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
vp test # 单元测试
|
|
192
|
+
vp run build # 构建 dist
|
|
193
|
+
vp check # 格式、lint、类型检查
|
|
194
|
+
```
|