@fangxinyan/lumina 0.6.14 → 0.6.16
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/dist/{Calendar-RUTPKREW.css → Calendar-I6NHCXIB.css} +65 -0
- package/dist/Calendar.cjs +2 -2
- package/dist/Calendar.d.cts +2 -0
- package/dist/Calendar.d.ts +2 -0
- package/dist/Calendar.js +1 -1
- package/dist/DatePicker-VDVSIARF.css +60 -0
- package/dist/DatePicker.cjs +16 -0
- package/dist/DatePicker.d.cts +49 -0
- package/dist/DatePicker.d.ts +49 -0
- package/dist/DatePicker.js +7 -0
- package/dist/DateTimePicker-DRX7XA74.css +224 -0
- package/dist/DateTimePicker.cjs +16 -0
- package/dist/DateTimePicker.d.cts +61 -0
- package/dist/DateTimePicker.d.ts +61 -0
- package/dist/DateTimePicker.js +7 -0
- package/dist/TimePicker-ZBJOXH3U.css +151 -0
- package/dist/TimePicker.cjs +15 -0
- package/dist/TimePicker.d.cts +63 -0
- package/dist/TimePicker.d.ts +63 -0
- package/dist/TimePicker.js +6 -0
- package/dist/chunk-32FWB5NO.cjs +505 -0
- package/dist/chunk-4KDABJSY.cjs +241 -0
- package/dist/chunk-DU4VSUBF.js +393 -0
- package/dist/chunk-FKP5D5IS.js +271 -0
- package/dist/chunk-I7TOBKJO.js +219 -0
- package/dist/chunk-KHRYPNUV.cjs +293 -0
- package/dist/chunk-SFEWMO45.cjs +415 -0
- package/dist/chunk-YPE6CDXQ.js +483 -0
- package/dist/index.cjs +66 -51
- package/dist/index.d.cts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +15 -12
- package/dist/styles.css +439 -0
- package/docs/llms/calendar.md +2 -1
- package/docs/llms/datepicker.md +69 -0
- package/docs/llms/datetimepicker.md +83 -0
- package/docs/llms/timepicker.md +81 -0
- package/docs/llms.md +5 -2
- package/package.json +7 -3
- package/dist/chunk-XG5D777V.js +0 -90
- package/dist/chunk-ZBTGYTQE.cjs +0 -112
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# DateTimePicker 日期时间选择
|
|
2
|
+
|
|
3
|
+
> 输入框触发的日期时间选择器,把 Calendar 与时分秒列组合在同一个浮层内。
|
|
4
|
+
|
|
5
|
+
## 导入
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { DateTimePicker } from "@fangxinyan/lumina";
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 示例
|
|
12
|
+
|
|
13
|
+
### 基础用法
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<DateTimePicker defaultValue={new Date(2026, 4, 25, 9, 30)} />
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### 受控
|
|
20
|
+
|
|
21
|
+
value 使用 Date | null,onChange 同时返回 Date 和格式化字符串。
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
const [startAt, setStartAt] = useState<Date | null>(new Date(2026, 4, 25, 9, 30));
|
|
25
|
+
<DateTimePicker value={startAt} onChange={setStartAt} allowClear />
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 秒级选择
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
<DateTimePicker
|
|
32
|
+
value={deployAt}
|
|
33
|
+
onChange={setDeployAt}
|
|
34
|
+
format="YYYY-MM-DD HH:mm:ss"
|
|
35
|
+
showSecond
|
|
36
|
+
/>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 范围与步进
|
|
40
|
+
|
|
41
|
+
15 分钟粒度,只允许工作日 08:00 到 20:00 之间的时间。
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
<DateTimePicker
|
|
45
|
+
min={new Date(2026, 4, 1, 8)}
|
|
46
|
+
max={new Date(2026, 4, 31, 20)}
|
|
47
|
+
minuteStep={15}
|
|
48
|
+
disabledDate={(date) => date.getDay() === 0 || date.getDay() === 6}
|
|
49
|
+
disabledTime={(time) => time.hour === 12}
|
|
50
|
+
/>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 尺寸与状态
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
<DateTimePicker size="sm" />
|
|
57
|
+
<DateTimePicker invalid />
|
|
58
|
+
<DateTimePicker size="lg" disabled />
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## API
|
|
62
|
+
|
|
63
|
+
**DateTimePicker**
|
|
64
|
+
|
|
65
|
+
| Prop | 类型 | 默认 | 说明 |
|
|
66
|
+
| --- | --- | --- | --- |
|
|
67
|
+
| value / defaultValue | `Date | null` | — | 受控/初始日期时间 |
|
|
68
|
+
| onChange | `(date: Date | null, dateString: string) => void` | — | 选择或清空时触发 |
|
|
69
|
+
| format | `"YYYY-MM-DD HH:mm" | "YYYY-MM-DD HH:mm:ss" | ((date) => string)` | `"YYYY-MM-DD HH:mm"` | 显示格式或自定义格式化函数 |
|
|
70
|
+
| showSecond | `boolean` | — | 显示秒列 |
|
|
71
|
+
| hourStep / minuteStep / secondStep | `number` | `1` | 列选项步进 |
|
|
72
|
+
| min / max | `Date` | — | 可选日期时间范围 |
|
|
73
|
+
| disabledDate | `(date: Date) => boolean` | — | 自定义禁用日期 |
|
|
74
|
+
| disabledTime | `(time: TimePickerValue, date: Date) => boolean` | — | 按当前日期禁用具体时间 |
|
|
75
|
+
| size | `"sm" | "md" | "lg"` | `"md"` | 输入框尺寸 |
|
|
76
|
+
| allowClear | `boolean` | `false` | 允许清空 |
|
|
77
|
+
| open / defaultOpen / onOpenChange | `—` | — | 受控浮层显隐 |
|
|
78
|
+
| popupClassName / dropdownClassName | `string` | — | 浮层 className |
|
|
79
|
+
| disabled / readOnly / invalid / placeholder | `—` | — | 常规输入状态 |
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
[← 回到索引](../llms.md)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# TimePicker 时间选择
|
|
2
|
+
|
|
3
|
+
> 输入框触发的时分秒选择器,支持步进、范围、禁用时间和秒级选择。
|
|
4
|
+
|
|
5
|
+
## 导入
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { TimePicker } from "@fangxinyan/lumina";
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 示例
|
|
12
|
+
|
|
13
|
+
### 基础用法
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<TimePicker defaultValue="09:30" />
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### 受控
|
|
20
|
+
|
|
21
|
+
value 是 HH:mm / HH:mm:ss 字符串或 null,onChange 第二个参数返回结构化 time。
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
const [time, setTime] = useState<string | null>("09:30");
|
|
25
|
+
<TimePicker value={time} onChange={setTime} allowClear />
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 秒级选择
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
<TimePicker
|
|
32
|
+
value={precise}
|
|
33
|
+
onChange={setPrecise}
|
|
34
|
+
format="HH:mm:ss"
|
|
35
|
+
showSecond
|
|
36
|
+
/>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 范围与步进
|
|
40
|
+
|
|
41
|
+
15 分钟粒度,只允许 08:00 到 20:00 之间的时间。
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
<TimePicker
|
|
45
|
+
min="08:00"
|
|
46
|
+
max="20:00"
|
|
47
|
+
minuteStep={15}
|
|
48
|
+
disabledTime={(time) => time.hour === 12}
|
|
49
|
+
/>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 尺寸与状态
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
<TimePicker size="sm" />
|
|
56
|
+
<TimePicker invalid />
|
|
57
|
+
<TimePicker size="lg" disabled />
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## API
|
|
61
|
+
|
|
62
|
+
**TimePicker**
|
|
63
|
+
|
|
64
|
+
| Prop | 类型 | 默认 | 说明 |
|
|
65
|
+
| --- | --- | --- | --- |
|
|
66
|
+
| value / defaultValue | `string | null` | — | 受控/初始时间 |
|
|
67
|
+
| onChange | `(value: string | null, time: TimePickerValue | null) => void` | — | 选择或清空时触发 |
|
|
68
|
+
| format | `"HH:mm" | "HH:mm:ss"` | `"HH:mm"` | 输出和显示格式 |
|
|
69
|
+
| showSecond | `boolean` | — | 显示秒列 |
|
|
70
|
+
| hourStep / minuteStep / secondStep | `number` | `1` | 列选项步进 |
|
|
71
|
+
| min / max | `string` | — | 可选时间范围 |
|
|
72
|
+
| disabledTime | `(time: TimePickerValue) => boolean` | — | 自定义禁用时间 |
|
|
73
|
+
| size | `"sm" | "md" | "lg"` | `"md"` | 输入框尺寸 |
|
|
74
|
+
| allowClear | `boolean` | `false` | 允许清空 |
|
|
75
|
+
| open / defaultOpen / onOpenChange | `—` | — | 受控浮层显隐 |
|
|
76
|
+
| popupClassName / dropdownClassName | `string` | — | 浮层 className |
|
|
77
|
+
| disabled / readOnly / invalid / placeholder | `—` | — | 常规输入状态 |
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
[← 回到索引](../llms.md)
|
package/docs/llms.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> 拟态风格的 React 18 组件库,目标是 Electron 桌面应用。**写给 AI 编程助手**的按需文档 —— 每个组件单独一个 `.md`,避免一次性读取全部。示例源自 playground 的 demo,可直接复制运行。
|
|
4
4
|
|
|
5
5
|
- **包名**: `@fangxinyan/lumina`
|
|
6
|
-
- **版本**: `0.6.
|
|
6
|
+
- **版本**: `0.6.16`
|
|
7
7
|
- **React 最低版本**: 18
|
|
8
8
|
- **环境**: 带打包器的 React 工程(Vite / Next.js / Webpack / Remix / Electron + Vite 等)
|
|
9
9
|
- **零运行时依赖**: 只依赖 `react` / `react-dom` (peer deps)
|
|
@@ -64,6 +64,9 @@
|
|
|
64
64
|
- [Select 下拉选择](./llms/select.md) — 下拉选择,支持单/多选、搜索、分组、加载态。
|
|
65
65
|
- [AutoComplete 自动补全](./llms/autocomplete.md) — 输入时展示建议下拉,不限定必须从候选中选。
|
|
66
66
|
- [Cascader 级联选择](./llms/cascader.md) — 层级关联数据集合中的多级选择。
|
|
67
|
+
- [DatePicker 日期选择](./llms/datepicker.md) — 输入框触发的日期选择器,复用 Calendar 并支持范围、禁用日期和格式化。
|
|
68
|
+
- [DateTimePicker 日期时间选择](./llms/datetimepicker.md) — 输入框触发的日期时间选择器,把 Calendar 与时分秒列组合在同一个浮层内。
|
|
69
|
+
- [TimePicker 时间选择](./llms/timepicker.md) — 输入框触发的时分秒选择器,支持步进、范围、禁用时间和秒级选择。
|
|
67
70
|
- [ColorPicker 颜色选择](./llms/colorpicker.md) — 拟态风格的颜色选择器:HSV 色域、色相、hex 输入、预设调色板。
|
|
68
71
|
- [Form 表单](./llms/form.md) — 受控表单,字段绑定 + 校验。
|
|
69
72
|
|
|
@@ -83,7 +86,7 @@
|
|
|
83
86
|
- [Pagination 分页](./llms/pagination.md) — 分页控件,支持快速跳转与每页条数切换。
|
|
84
87
|
- [Tabs 选项卡](./llms/tabs.md) — 同一层级的内容分组,通过标签切换。
|
|
85
88
|
- [Collapse 折叠面板](./llms/collapse.md) — 纵向折叠面板。
|
|
86
|
-
- [Calendar 日历](./llms/calendar.md) —
|
|
89
|
+
- [Calendar 日历](./llms/calendar.md) — 查看与选择日期,支持快速切换年份和月份。
|
|
87
90
|
|
|
88
91
|
### 反馈
|
|
89
92
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fangxinyan/lumina",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.16",
|
|
4
4
|
"description": "Lumina — Neumorphic component library for Electron & React apps",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -144,9 +144,10 @@
|
|
|
144
144
|
"build:lib": "tsup",
|
|
145
145
|
"preview": "vite preview",
|
|
146
146
|
"typecheck": "tsc --noEmit",
|
|
147
|
+
"test:unit": "vitest run --root . --environment jsdom",
|
|
147
148
|
"gen:docs": "node scripts/gen-llms-doc.mjs",
|
|
148
149
|
"verify:public-api": "node scripts/verify-public-api.mjs",
|
|
149
|
-
"prepublishOnly": "npm run typecheck && npm run gen:docs && npm run build:lib && npm run verify:public-api"
|
|
150
|
+
"prepublishOnly": "npm run typecheck && npm run test:unit && npm run gen:docs && npm run build:lib && npm run verify:public-api"
|
|
150
151
|
},
|
|
151
152
|
"peerDependencies": {
|
|
152
153
|
"react": ">=18",
|
|
@@ -154,11 +155,13 @@
|
|
|
154
155
|
},
|
|
155
156
|
"devDependencies": {
|
|
156
157
|
"@babel/standalone": "^7.29.2",
|
|
158
|
+
"@testing-library/react": "^16.3.2",
|
|
157
159
|
"@types/node": "^25.6.0",
|
|
158
160
|
"@types/prismjs": "^1.26.6",
|
|
159
161
|
"@types/react": "^18.3.3",
|
|
160
162
|
"@types/react-dom": "^18.3.0",
|
|
161
163
|
"@vitejs/plugin-react": "^4.3.1",
|
|
164
|
+
"jsdom": "^29.1.1",
|
|
162
165
|
"postcss": "^8.5.10",
|
|
163
166
|
"postcss-import": "^16.1.1",
|
|
164
167
|
"prismjs": "^1.30.0",
|
|
@@ -166,7 +169,8 @@
|
|
|
166
169
|
"react-dom": "^18.3.1",
|
|
167
170
|
"tsup": "^8.2.4",
|
|
168
171
|
"typescript": "^5.5.4",
|
|
169
|
-
"vite": "^5.4.2"
|
|
172
|
+
"vite": "^5.4.2",
|
|
173
|
+
"vitest": "^4.1.6"
|
|
170
174
|
},
|
|
171
175
|
"keywords": [
|
|
172
176
|
"react",
|
package/dist/chunk-XG5D777V.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { Icon } from './chunk-FDZG27IG.js';
|
|
2
|
-
import './tokens-RYJ3DFTU.css';
|
|
3
|
-
import './shared-NJHRNLRH.css';
|
|
4
|
-
import './Calendar-RUTPKREW.css';
|
|
5
|
-
import * as React from 'react';
|
|
6
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
7
|
-
|
|
8
|
-
var WEEKDAYS = ["\u65E5", "\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D"];
|
|
9
|
-
var Calendar = React.forwardRef(({
|
|
10
|
-
value,
|
|
11
|
-
defaultValue,
|
|
12
|
-
onChange,
|
|
13
|
-
min,
|
|
14
|
-
max,
|
|
15
|
-
disabledDate,
|
|
16
|
-
className = "",
|
|
17
|
-
...rest
|
|
18
|
-
}, ref) => {
|
|
19
|
-
const [inner, setInner] = React.useState(defaultValue ?? /* @__PURE__ */ new Date());
|
|
20
|
-
const isControlled = value !== void 0;
|
|
21
|
-
const sel = isControlled ? value : inner;
|
|
22
|
-
const [view, setView] = React.useState(new Date(sel.getFullYear(), sel.getMonth(), 1));
|
|
23
|
-
const first = new Date(view.getFullYear(), view.getMonth(), 1);
|
|
24
|
-
const startDay = first.getDay();
|
|
25
|
-
const daysInMonth = new Date(view.getFullYear(), view.getMonth() + 1, 0).getDate();
|
|
26
|
-
const cells = [];
|
|
27
|
-
for (let i = 0; i < startDay; i++) cells.push(null);
|
|
28
|
-
for (let d = 1; d <= daysInMonth; d++) cells.push(d);
|
|
29
|
-
const isSame = (a, b) => a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
30
|
-
const pick = (d) => {
|
|
31
|
-
const next = new Date(view.getFullYear(), view.getMonth(), d);
|
|
32
|
-
if (min && next < min) return;
|
|
33
|
-
if (max && next > max) return;
|
|
34
|
-
if (disabledDate?.(next)) return;
|
|
35
|
-
if (!isControlled) setInner(next);
|
|
36
|
-
onChange?.(next);
|
|
37
|
-
};
|
|
38
|
-
return /* @__PURE__ */ jsxs("div", { ref, className: `calendar ${className}`, ...rest, children: [
|
|
39
|
-
/* @__PURE__ */ jsxs("div", { className: "calendar-head", children: [
|
|
40
|
-
/* @__PURE__ */ jsx(
|
|
41
|
-
"button",
|
|
42
|
-
{
|
|
43
|
-
type: "button",
|
|
44
|
-
className: "btn icon sm ghost",
|
|
45
|
-
onClick: () => setView(new Date(view.getFullYear(), view.getMonth() - 1, 1)),
|
|
46
|
-
"aria-label": "Previous month",
|
|
47
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "chevLeft", size: 14 })
|
|
48
|
-
}
|
|
49
|
-
),
|
|
50
|
-
/* @__PURE__ */ jsxs("button", { type: "button", className: "calendar-title", children: [
|
|
51
|
-
view.getFullYear(),
|
|
52
|
-
" \u5E74 ",
|
|
53
|
-
view.getMonth() + 1,
|
|
54
|
-
" \u6708"
|
|
55
|
-
] }),
|
|
56
|
-
/* @__PURE__ */ jsx(
|
|
57
|
-
"button",
|
|
58
|
-
{
|
|
59
|
-
type: "button",
|
|
60
|
-
className: "btn icon sm ghost",
|
|
61
|
-
onClick: () => setView(new Date(view.getFullYear(), view.getMonth() + 1, 1)),
|
|
62
|
-
"aria-label": "Next month",
|
|
63
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "chevRight", size: 14 })
|
|
64
|
-
}
|
|
65
|
-
)
|
|
66
|
-
] }),
|
|
67
|
-
/* @__PURE__ */ jsxs("div", { className: "calendar-grid", children: [
|
|
68
|
-
WEEKDAYS.map((w) => /* @__PURE__ */ jsx("div", { className: "calendar-dow", children: w }, w)),
|
|
69
|
-
cells.map((d, i) => {
|
|
70
|
-
if (d === null) return /* @__PURE__ */ jsx("div", { className: "calendar-cell out" }, i);
|
|
71
|
-
const date = new Date(view.getFullYear(), view.getMonth(), d);
|
|
72
|
-
const disabled = min && date < min || max && date > max || (disabledDate?.(date) ?? false);
|
|
73
|
-
return /* @__PURE__ */ jsx(
|
|
74
|
-
"button",
|
|
75
|
-
{
|
|
76
|
-
type: "button",
|
|
77
|
-
disabled: !!disabled,
|
|
78
|
-
className: `calendar-cell ${isSame(date, sel) ? "selected" : ""} ${isSame(date, /* @__PURE__ */ new Date()) ? "today" : ""} ${disabled ? "disabled" : ""}`,
|
|
79
|
-
onClick: () => pick(d),
|
|
80
|
-
children: d
|
|
81
|
-
},
|
|
82
|
-
i
|
|
83
|
-
);
|
|
84
|
-
})
|
|
85
|
-
] })
|
|
86
|
-
] });
|
|
87
|
-
});
|
|
88
|
-
Calendar.displayName = "Calendar";
|
|
89
|
-
|
|
90
|
-
export { Calendar };
|
package/dist/chunk-ZBTGYTQE.cjs
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var chunkQMX67CVT_cjs = require('./chunk-QMX67CVT.cjs');
|
|
4
|
-
require('./tokens-RYJ3DFTU.css');
|
|
5
|
-
require('./shared-NJHRNLRH.css');
|
|
6
|
-
require('./Calendar-RUTPKREW.css');
|
|
7
|
-
var React = require('react');
|
|
8
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
9
|
-
|
|
10
|
-
function _interopNamespace(e) {
|
|
11
|
-
if (e && e.__esModule) return e;
|
|
12
|
-
var n = Object.create(null);
|
|
13
|
-
if (e) {
|
|
14
|
-
Object.keys(e).forEach(function (k) {
|
|
15
|
-
if (k !== 'default') {
|
|
16
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
17
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
18
|
-
enumerable: true,
|
|
19
|
-
get: function () { return e[k]; }
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
n.default = e;
|
|
25
|
-
return Object.freeze(n);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
29
|
-
|
|
30
|
-
var WEEKDAYS = ["\u65E5", "\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D"];
|
|
31
|
-
var Calendar = React__namespace.forwardRef(({
|
|
32
|
-
value,
|
|
33
|
-
defaultValue,
|
|
34
|
-
onChange,
|
|
35
|
-
min,
|
|
36
|
-
max,
|
|
37
|
-
disabledDate,
|
|
38
|
-
className = "",
|
|
39
|
-
...rest
|
|
40
|
-
}, ref) => {
|
|
41
|
-
const [inner, setInner] = React__namespace.useState(defaultValue ?? /* @__PURE__ */ new Date());
|
|
42
|
-
const isControlled = value !== void 0;
|
|
43
|
-
const sel = isControlled ? value : inner;
|
|
44
|
-
const [view, setView] = React__namespace.useState(new Date(sel.getFullYear(), sel.getMonth(), 1));
|
|
45
|
-
const first = new Date(view.getFullYear(), view.getMonth(), 1);
|
|
46
|
-
const startDay = first.getDay();
|
|
47
|
-
const daysInMonth = new Date(view.getFullYear(), view.getMonth() + 1, 0).getDate();
|
|
48
|
-
const cells = [];
|
|
49
|
-
for (let i = 0; i < startDay; i++) cells.push(null);
|
|
50
|
-
for (let d = 1; d <= daysInMonth; d++) cells.push(d);
|
|
51
|
-
const isSame = (a, b) => a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
52
|
-
const pick = (d) => {
|
|
53
|
-
const next = new Date(view.getFullYear(), view.getMonth(), d);
|
|
54
|
-
if (min && next < min) return;
|
|
55
|
-
if (max && next > max) return;
|
|
56
|
-
if (disabledDate?.(next)) return;
|
|
57
|
-
if (!isControlled) setInner(next);
|
|
58
|
-
onChange?.(next);
|
|
59
|
-
};
|
|
60
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: `calendar ${className}`, ...rest, children: [
|
|
61
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "calendar-head", children: [
|
|
62
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
63
|
-
"button",
|
|
64
|
-
{
|
|
65
|
-
type: "button",
|
|
66
|
-
className: "btn icon sm ghost",
|
|
67
|
-
onClick: () => setView(new Date(view.getFullYear(), view.getMonth() - 1, 1)),
|
|
68
|
-
"aria-label": "Previous month",
|
|
69
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(chunkQMX67CVT_cjs.Icon, { name: "chevLeft", size: 14 })
|
|
70
|
-
}
|
|
71
|
-
),
|
|
72
|
-
/* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "calendar-title", children: [
|
|
73
|
-
view.getFullYear(),
|
|
74
|
-
" \u5E74 ",
|
|
75
|
-
view.getMonth() + 1,
|
|
76
|
-
" \u6708"
|
|
77
|
-
] }),
|
|
78
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
79
|
-
"button",
|
|
80
|
-
{
|
|
81
|
-
type: "button",
|
|
82
|
-
className: "btn icon sm ghost",
|
|
83
|
-
onClick: () => setView(new Date(view.getFullYear(), view.getMonth() + 1, 1)),
|
|
84
|
-
"aria-label": "Next month",
|
|
85
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(chunkQMX67CVT_cjs.Icon, { name: "chevRight", size: 14 })
|
|
86
|
-
}
|
|
87
|
-
)
|
|
88
|
-
] }),
|
|
89
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "calendar-grid", children: [
|
|
90
|
-
WEEKDAYS.map((w) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "calendar-dow", children: w }, w)),
|
|
91
|
-
cells.map((d, i) => {
|
|
92
|
-
if (d === null) return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "calendar-cell out" }, i);
|
|
93
|
-
const date = new Date(view.getFullYear(), view.getMonth(), d);
|
|
94
|
-
const disabled = min && date < min || max && date > max || (disabledDate?.(date) ?? false);
|
|
95
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
96
|
-
"button",
|
|
97
|
-
{
|
|
98
|
-
type: "button",
|
|
99
|
-
disabled: !!disabled,
|
|
100
|
-
className: `calendar-cell ${isSame(date, sel) ? "selected" : ""} ${isSame(date, /* @__PURE__ */ new Date()) ? "today" : ""} ${disabled ? "disabled" : ""}`,
|
|
101
|
-
onClick: () => pick(d),
|
|
102
|
-
children: d
|
|
103
|
-
},
|
|
104
|
-
i
|
|
105
|
-
);
|
|
106
|
-
})
|
|
107
|
-
] })
|
|
108
|
-
] });
|
|
109
|
-
});
|
|
110
|
-
Calendar.displayName = "Calendar";
|
|
111
|
-
|
|
112
|
-
exports.Calendar = Calendar;
|