@fangxinyan/lumina 0.6.13 → 0.6.15

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.
Files changed (239) hide show
  1. package/dist/Alert.cjs +3 -3
  2. package/dist/Alert.js +2 -2
  3. package/dist/AppShell.cjs +5 -5
  4. package/dist/AppShell.js +1 -1
  5. package/dist/AutoComplete.cjs +5 -5
  6. package/dist/AutoComplete.js +4 -4
  7. package/dist/Avatar.cjs +2 -2
  8. package/dist/Avatar.js +1 -1
  9. package/dist/Badge.cjs +2 -2
  10. package/dist/Badge.js +1 -1
  11. package/dist/Button.cjs +4 -4
  12. package/dist/Button.js +2 -2
  13. package/dist/{Calendar-RUTPKREW.css → Calendar-I6NHCXIB.css} +65 -0
  14. package/dist/Calendar.cjs +3 -3
  15. package/dist/Calendar.d.cts +2 -0
  16. package/dist/Calendar.d.ts +2 -0
  17. package/dist/Calendar.js +2 -2
  18. package/dist/Card.cjs +3 -3
  19. package/dist/Card.js +2 -2
  20. package/dist/Cascader.cjs +5 -5
  21. package/dist/Cascader.js +4 -4
  22. package/dist/Checkbox.cjs +3 -3
  23. package/dist/Checkbox.js +2 -2
  24. package/dist/Collapse.cjs +3 -3
  25. package/dist/Collapse.js +2 -2
  26. package/dist/ColorPicker.cjs +2 -2
  27. package/dist/ColorPicker.js +1 -1
  28. package/dist/CommandPalette.cjs +5 -5
  29. package/dist/CommandPalette.js +4 -4
  30. package/dist/ContextMenu.cjs +2 -2
  31. package/dist/ContextMenu.js +1 -1
  32. package/dist/DatePicker-VDVSIARF.css +60 -0
  33. package/dist/DatePicker.cjs +16 -0
  34. package/dist/DatePicker.d.cts +49 -0
  35. package/dist/DatePicker.d.ts +49 -0
  36. package/dist/DatePicker.js +7 -0
  37. package/dist/DateTimePicker-77ZLZIWO.css +224 -0
  38. package/dist/DateTimePicker.cjs +16 -0
  39. package/dist/DateTimePicker.d.cts +61 -0
  40. package/dist/DateTimePicker.d.ts +61 -0
  41. package/dist/DateTimePicker.js +7 -0
  42. package/dist/Divider.cjs +2 -2
  43. package/dist/Divider.js +1 -1
  44. package/dist/{Drawer-7N3URAJ6.css → Drawer-7KICRM4L.css} +1 -1
  45. package/dist/Drawer.cjs +3 -3
  46. package/dist/Drawer.d.cts +4 -0
  47. package/dist/Drawer.d.ts +4 -0
  48. package/dist/Drawer.js +2 -2
  49. package/dist/Empty.cjs +2 -2
  50. package/dist/Empty.js +1 -1
  51. package/dist/Form.cjs +4 -4
  52. package/dist/Form.js +1 -1
  53. package/dist/Icon.cjs +49 -49
  54. package/dist/Icon.js +1 -1
  55. package/dist/{Image-SGSRTHQX.css → Image-TDCXJISG.css} +1 -1
  56. package/dist/Image.cjs +6 -6
  57. package/dist/Image.d.cts +4 -0
  58. package/dist/Image.d.ts +4 -0
  59. package/dist/Image.js +2 -2
  60. package/dist/Input.cjs +5 -5
  61. package/dist/Input.js +3 -3
  62. package/dist/InputNumber.cjs +5 -5
  63. package/dist/InputNumber.js +4 -4
  64. package/dist/List.cjs +2 -2
  65. package/dist/List.js +1 -1
  66. package/dist/Message.cjs +6 -6
  67. package/dist/Message.js +2 -2
  68. package/dist/{Modal-MCFDYVUQ.css → Modal-ZFWNFEA5.css} +1 -1
  69. package/dist/Modal.cjs +4 -4
  70. package/dist/Modal.d.cts +4 -0
  71. package/dist/Modal.d.ts +4 -0
  72. package/dist/Modal.js +3 -3
  73. package/dist/Pagination.cjs +7 -7
  74. package/dist/Pagination.js +6 -6
  75. package/dist/Popover.cjs +2 -2
  76. package/dist/Popover.js +1 -1
  77. package/dist/Progress.cjs +2 -2
  78. package/dist/Progress.js +1 -1
  79. package/dist/Radio.cjs +3 -3
  80. package/dist/Radio.js +1 -1
  81. package/dist/Select.cjs +6 -6
  82. package/dist/Select.js +5 -5
  83. package/dist/Skeleton.cjs +2 -2
  84. package/dist/Skeleton.js +1 -1
  85. package/dist/Slider.cjs +2 -2
  86. package/dist/Slider.js +1 -1
  87. package/dist/Spin.cjs +2 -2
  88. package/dist/Spin.js +1 -1
  89. package/dist/Splitter.cjs +2 -2
  90. package/dist/Splitter.js +1 -1
  91. package/dist/StatusBar.cjs +3 -3
  92. package/dist/StatusBar.js +1 -1
  93. package/dist/Surface.cjs +4 -4
  94. package/dist/Surface.js +2 -2
  95. package/dist/Switch.cjs +2 -2
  96. package/dist/Switch.js +1 -1
  97. package/dist/Table.cjs +9 -9
  98. package/dist/Table.js +8 -8
  99. package/dist/TablePro.cjs +10 -10
  100. package/dist/TablePro.js +9 -9
  101. package/dist/Tabs.cjs +2 -2
  102. package/dist/Tabs.js +1 -1
  103. package/dist/Tag.cjs +3 -3
  104. package/dist/Tag.js +2 -2
  105. package/dist/Textarea.cjs +4 -4
  106. package/dist/Textarea.js +2 -2
  107. package/dist/Theme.cjs +11 -11
  108. package/dist/Theme.js +1 -1
  109. package/dist/ThemePanel.cjs +13 -13
  110. package/dist/ThemePanel.js +10 -10
  111. package/dist/TimePicker-6URACYEH.css +151 -0
  112. package/dist/TimePicker.cjs +15 -0
  113. package/dist/TimePicker.d.cts +63 -0
  114. package/dist/TimePicker.d.ts +63 -0
  115. package/dist/TimePicker.js +6 -0
  116. package/dist/Timeline.cjs +3 -3
  117. package/dist/Timeline.js +2 -2
  118. package/dist/Tooltip.cjs +2 -2
  119. package/dist/Tooltip.js +1 -1
  120. package/dist/Typography.cjs +7 -7
  121. package/dist/Typography.js +2 -2
  122. package/dist/{chunk-J7VYTDFN.cjs → chunk-262ED6WQ.cjs} +3 -3
  123. package/dist/chunk-26AJ7OY3.cjs +505 -0
  124. package/dist/{chunk-BX45WJRT.js → chunk-3VSHGM54.js} +9 -9
  125. package/dist/{chunk-KRVWQKTZ.js → chunk-3VXGZ3SJ.js} +3 -3
  126. package/dist/{chunk-VJVXXCNL.js → chunk-4HJBF4GY.js} +3 -3
  127. package/dist/chunk-4KDABJSY.cjs +241 -0
  128. package/dist/{chunk-ONHYDQFP.cjs → chunk-4TTRHEGM.cjs} +3 -3
  129. package/dist/{chunk-GVULVTWO.js → chunk-4YSGGZDB.js} +4 -4
  130. package/dist/{chunk-HNP7KEQP.cjs → chunk-5A6KSYWA.cjs} +1 -1
  131. package/dist/{chunk-RFFP6J6O.cjs → chunk-5ERD3W24.cjs} +4 -4
  132. package/dist/{chunk-TTXYZDQ3.js → chunk-5MOYKVB7.js} +2 -2
  133. package/dist/{chunk-X2NY3YQS.cjs → chunk-5QEI7GGA.cjs} +6 -6
  134. package/dist/{chunk-O7OPFKAM.js → chunk-6HF6UF73.js} +2 -2
  135. package/dist/{chunk-DCATZUT3.js → chunk-6K5YI4ZE.js} +2 -2
  136. package/dist/{chunk-EVKLGNVR.js → chunk-6LC4QROE.js} +3 -3
  137. package/dist/{chunk-6Z4PZWND.js → chunk-6LN4VVX7.js} +2 -2
  138. package/dist/{chunk-7RNT6KN4.js → chunk-6MEOLYNQ.js} +1 -1
  139. package/dist/{chunk-UMLRSKBE.js → chunk-6PHPRZTT.js} +4 -4
  140. package/dist/{chunk-4VPRY4EM.cjs → chunk-6Q76VLCE.cjs} +3 -3
  141. package/dist/{chunk-SWMQ2GKT.cjs → chunk-7IO3EOHN.cjs} +3 -3
  142. package/dist/{chunk-B55XILNY.cjs → chunk-7QXP6DXC.cjs} +4 -4
  143. package/dist/{chunk-56GNNOOT.cjs → chunk-7YJV45U6.cjs} +11 -11
  144. package/dist/{chunk-AJ44ZLJY.cjs → chunk-A4Z7PLHV.cjs} +59 -59
  145. package/dist/{chunk-RUE3QE6T.js → chunk-A6O25EP2.js} +2 -2
  146. package/dist/{chunk-ZNR6LWTQ.js → chunk-AAPZLBHQ.js} +1 -1
  147. package/dist/{chunk-Q4IAUKAW.js → chunk-ARUPS7JH.js} +2 -2
  148. package/dist/{chunk-VAOAAWGI.cjs → chunk-ATUPFAPZ.cjs} +3 -3
  149. package/dist/{chunk-GKBCXYDF.cjs → chunk-BNY2NVTL.cjs} +3 -3
  150. package/dist/{chunk-7J26GI3T.cjs → chunk-BT2RXFT4.cjs} +15 -13
  151. package/dist/{chunk-WY6AEPFW.js → chunk-BVQOJKRX.js} +8 -6
  152. package/dist/{chunk-QPZCDZWI.cjs → chunk-BW76ENTW.cjs} +1 -1
  153. package/dist/{chunk-EKNDL2XB.js → chunk-CFZVWY5N.js} +2 -2
  154. package/dist/chunk-CUBKHQ63.js +483 -0
  155. package/dist/chunk-CYBBUXUK.cjs +415 -0
  156. package/dist/{chunk-JST4HJ3I.js → chunk-D7GK6H6V.js} +1 -1
  157. package/dist/{chunk-T7RV2UMU.js → chunk-DSLYWX4O.js} +1 -1
  158. package/dist/{chunk-JKFGLYMM.js → chunk-EQ4FPOQQ.js} +14 -4
  159. package/dist/{chunk-ZZH4UIPN.cjs → chunk-ES7AWMNH.cjs} +1 -1
  160. package/dist/{chunk-ZLMJVSBO.cjs → chunk-FDUQPAQE.cjs} +1 -1
  161. package/dist/{chunk-HHBXCBZP.js → chunk-FDZG27IG.js} +1 -1
  162. package/dist/chunk-FKP5D5IS.js +271 -0
  163. package/dist/{chunk-EEHZRPPF.cjs → chunk-FQJY4D3T.cjs} +1 -1
  164. package/dist/{chunk-LA62SD2F.js → chunk-FYSXJXNW.js} +1 -1
  165. package/dist/{chunk-DEXYWDHF.js → chunk-GNV6W4BN.js} +1 -1
  166. package/dist/{chunk-NZBOHEQA.js → chunk-HBO7ZDEQ.js} +1 -1
  167. package/dist/{chunk-BAWP2QVY.js → chunk-I777JTTG.js} +1 -1
  168. package/dist/chunk-I7TOBKJO.js +219 -0
  169. package/dist/{chunk-IZGHMMX7.js → chunk-IOAOG5L7.js} +3 -3
  170. package/dist/{chunk-QQROR2RU.cjs → chunk-IOUAZYK2.cjs} +1 -1
  171. package/dist/{chunk-CQKQ7KS2.js → chunk-IPSNC5VZ.js} +2 -2
  172. package/dist/{chunk-7X7FXV5E.cjs → chunk-IVFVLRWJ.cjs} +14 -14
  173. package/dist/{chunk-LM5XXSGE.js → chunk-IZHH6CVY.js} +1 -1
  174. package/dist/{chunk-GGNBMIZ2.js → chunk-JFL2WMJZ.js} +2 -2
  175. package/dist/{chunk-XRIXQM3Z.cjs → chunk-JMFHL7GN.cjs} +1 -1
  176. package/dist/chunk-KHRYPNUV.cjs +293 -0
  177. package/dist/{chunk-LFPFFSN2.js → chunk-KMPFESEV.js} +1 -1
  178. package/dist/{chunk-TAHZH6DJ.js → chunk-KYV75JPQ.js} +1 -1
  179. package/dist/{chunk-2A2XM7D5.cjs → chunk-LEMMFFEY.cjs} +4 -4
  180. package/dist/{chunk-MZIZGYA4.cjs → chunk-M4NJTJKV.cjs} +1 -1
  181. package/dist/{chunk-HYXA7S43.js → chunk-MOZ52KN6.js} +1 -1
  182. package/dist/{chunk-E5MSFY5H.cjs → chunk-MPOO5VPW.cjs} +1 -1
  183. package/dist/{chunk-MPJLGYFV.cjs → chunk-MYW7LNB2.cjs} +1 -1
  184. package/dist/chunk-N7CHFKRS.js +393 -0
  185. package/dist/{chunk-VBTASJ3Y.cjs → chunk-N7OQNSII.cjs} +1 -1
  186. package/dist/{chunk-VGERRI4S.js → chunk-OTSDPQPV.js} +2 -2
  187. package/dist/{chunk-7NAN7OVX.cjs → chunk-P2OQTJZP.cjs} +1 -1
  188. package/dist/{chunk-HAA5C5YW.js → chunk-P64NPZBG.js} +2 -2
  189. package/dist/{chunk-QP6RNHGR.cjs → chunk-PBT4UKPL.cjs} +3 -3
  190. package/dist/{chunk-FUR5SDP7.cjs → chunk-PKNRTFNE.cjs} +1 -1
  191. package/dist/{chunk-FPXBY2MY.cjs → chunk-POU3W5J3.cjs} +1 -1
  192. package/dist/{chunk-SOY3LB7W.cjs → chunk-PSQ3HNZP.cjs} +1 -1
  193. package/dist/{chunk-BK4XKZUO.js → chunk-PU7VXDAS.js} +1 -1
  194. package/dist/{chunk-OCQC2ZSV.cjs → chunk-QMX67CVT.cjs} +1 -1
  195. package/dist/{chunk-R3JCW3ES.js → chunk-QNN3YV2P.js} +2 -2
  196. package/dist/{chunk-V5HMQGFD.js → chunk-R3DTXVP2.js} +1 -1
  197. package/dist/{chunk-EQGNKCBY.cjs → chunk-RFI5R42I.cjs} +4 -4
  198. package/dist/{chunk-FROWMHDP.cjs → chunk-RMFSX7DO.cjs} +18 -8
  199. package/dist/{chunk-TCWGIRAW.js → chunk-RR2BKV65.js} +1 -1
  200. package/dist/{chunk-YHFGMI7T.cjs → chunk-RSSOX4RQ.cjs} +8 -8
  201. package/dist/{chunk-3XV4LGQ7.cjs → chunk-RZEFKXL3.cjs} +3 -3
  202. package/dist/{chunk-GDWAQGOH.cjs → chunk-S2ZGXBUH.cjs} +1 -1
  203. package/dist/{chunk-M63HWVOS.js → chunk-S7IHWY24.js} +2 -2
  204. package/dist/{chunk-NLX2RB4L.cjs → chunk-SOQ56ZI2.cjs} +1 -1
  205. package/dist/{chunk-RV37BGW3.cjs → chunk-SW2HMNCA.cjs} +4 -4
  206. package/dist/{chunk-UVL5SIAQ.cjs → chunk-TBNPJPYG.cjs} +1 -1
  207. package/dist/{chunk-QVWCUKEY.js → chunk-TJECLLN4.js} +1 -1
  208. package/dist/{chunk-E2OC4CUE.js → chunk-TYLDISRK.js} +1 -1
  209. package/dist/{chunk-23HN42SP.cjs → chunk-ULUD3FED.cjs} +9 -6
  210. package/dist/{chunk-LINUXKS7.cjs → chunk-V5KUC5VH.cjs} +1 -1
  211. package/dist/{chunk-U2543OZS.cjs → chunk-VA2I7ZAL.cjs} +1 -1
  212. package/dist/{chunk-7TWL3SJ5.cjs → chunk-VS3I5OKA.cjs} +8 -8
  213. package/dist/{chunk-A7BI7YWZ.js → chunk-WMGMIE2D.js} +8 -5
  214. package/dist/{chunk-CCBEHIRU.cjs → chunk-X5MYHDEQ.cjs} +6 -6
  215. package/dist/{chunk-QSGH4FCS.cjs → chunk-X7XP6GEI.cjs} +1 -1
  216. package/dist/{chunk-UROQO2HR.js → chunk-XCXUGHDF.js} +1 -1
  217. package/dist/{chunk-2M5WJENK.js → chunk-YAFDVNXT.js} +1 -1
  218. package/dist/{chunk-PDYM26IC.cjs → chunk-ZBWUIR2J.cjs} +6 -6
  219. package/dist/{chunk-5GKALAMP.js → chunk-ZD3L4V3H.js} +2 -2
  220. package/dist/{chunk-XJTDCWKP.js → chunk-ZR4IMROK.js} +1 -1
  221. package/dist/{chunk-5MCFW2HC.js → chunk-ZTCRD2FL.js} +1 -1
  222. package/dist/index.cjs +214 -199
  223. package/dist/index.d.cts +4 -1
  224. package/dist/index.d.ts +4 -1
  225. package/dist/index.js +51 -48
  226. package/dist/styles.css +445 -3
  227. package/dist/{tokens-OJLK3XMZ.css → tokens-RYJ3DFTU.css} +3 -0
  228. package/dist/tokens.css +3 -0
  229. package/docs/llms/calendar.md +2 -1
  230. package/docs/llms/datepicker.md +69 -0
  231. package/docs/llms/datetimepicker.md +83 -0
  232. package/docs/llms/drawer.md +13 -0
  233. package/docs/llms/image.md +14 -0
  234. package/docs/llms/modal.md +13 -0
  235. package/docs/llms/timepicker.md +81 -0
  236. package/docs/llms.md +5 -2
  237. package/package.json +7 -3
  238. package/dist/chunk-56U4P7QA.cjs +0 -112
  239. package/dist/chunk-J3LUTXVO.js +0 -90
package/dist/tokens.css CHANGED
@@ -13,6 +13,7 @@
13
13
  --fg-subtle: #9ca7ba;
14
14
  --border: rgba(130, 148, 175, 0.14);
15
15
  --divider: rgba(130, 148, 175, 0.18);
16
+ --mask-bg: color-mix(in oklch, black 18%, transparent);
16
17
 
17
18
  /* ---- Shadows ---- */
18
19
  --shadow-dark: rgba(163, 177, 198, 0.55);
@@ -139,6 +140,7 @@
139
140
  --fg-subtle: #9ca7ba;
140
141
  --border: rgba(130, 148, 175, 0.14);
141
142
  --divider: rgba(130, 148, 175, 0.18);
143
+ --mask-bg: color-mix(in oklch, black 18%, transparent);
142
144
  --shadow-dark: rgba(163, 177, 198, 0.55);
143
145
  --shadow-light: rgba(255, 255, 255, 0.95);
144
146
  --shadow-offset: calc(6px * var(--d) * var(--shadow-scale));
@@ -161,6 +163,7 @@
161
163
  --fg-subtle: #5f6a82;
162
164
  --border: rgba(0, 0, 0, 0.35);
163
165
  --divider: rgba(255, 255, 255, 0.06);
166
+ --mask-bg: color-mix(in oklch, black 55%, transparent);
164
167
  /* 强 dark shadow 提供深度;light 高光几乎不可见,去掉白圈效果 */
165
168
  --shadow-dark: rgba(0, 0, 0, 0.55);
166
169
  --shadow-light: rgba(130, 145, 180, 0.06);
@@ -1,6 +1,6 @@
1
1
  # Calendar 日历
2
2
 
3
- > 查看与选择日期。
3
+ > 查看与选择日期,支持快速切换年份和月份。
4
4
 
5
5
  ## 导入
6
6
 
@@ -35,6 +35,7 @@ import { Calendar } from "@fangxinyan/lumina";
35
35
  | Prop | 类型 | 默认 | 说明 |
36
36
  | --- | --- | --- | --- |
37
37
  | value / defaultValue | `Date` | — | 受控/初始日期 |
38
+ | viewDate | `Date` | — | 外部日期变化时同步可视月份 |
38
39
  | onChange | `(date: Date) => void` | — | 选择回调 |
39
40
  | min / max | `Date` | — | 可选范围 |
40
41
  | disabledDate | `(date: Date) => boolean` | — | 自定义禁用判断,返回 true 的日期不可选 |
@@ -0,0 +1,69 @@
1
+ # DatePicker 日期选择
2
+
3
+ > 输入框触发的日期选择器,复用 Calendar 并支持范围、禁用日期和格式化。
4
+
5
+ ## 导入
6
+
7
+ ```tsx
8
+ import { DatePicker } from "@fangxinyan/lumina";
9
+ ```
10
+
11
+ ## 示例
12
+
13
+ ### 基础用法
14
+
15
+ ```tsx
16
+ <DatePicker defaultValue={new Date(2026, 4, 25)} />
17
+ ```
18
+
19
+ ### 受控
20
+
21
+ value 使用 Date | null,onChange 同时返回 Date 和格式化字符串。
22
+
23
+ ```tsx
24
+ const [date, setDate] = useState<Date | null>(new Date());
25
+ <DatePicker value={date} onChange={setDate} allowClear />
26
+ ```
27
+
28
+ ### 限制范围
29
+
30
+ min / max 与 disabledDate 会同步作用于 Calendar 单元格和手动输入。
31
+
32
+ ```tsx
33
+ <DatePicker
34
+ value={workday}
35
+ onChange={setWorkday}
36
+ min={new Date(2026, 4, 1)}
37
+ max={new Date(2026, 4, 31)}
38
+ disabledDate={(date) => date.getDay() === 0 || date.getDay() === 6}
39
+ />
40
+ ```
41
+
42
+ ### 格式与尺寸
43
+
44
+ ```tsx
45
+ <DatePicker size="sm" format="YYYY/MM/DD" />
46
+ <DatePicker format="YYYY年MM月DD日" />
47
+ <DatePicker size="lg" disabled />
48
+ ```
49
+
50
+ ## API
51
+
52
+ **DatePicker**
53
+
54
+ | Prop | 类型 | 默认 | 说明 |
55
+ | --- | --- | --- | --- |
56
+ | value / defaultValue | `Date | null` | — | 受控/初始日期 |
57
+ | onChange | `(date: Date | null, dateString: string) => void` | — | 选择或清空时触发 |
58
+ | format | `"YYYY-MM-DD" | "YYYY/MM/DD" | "YYYY年MM月DD日" | ((date) => string)` | `"YYYY-MM-DD"` | 显示格式或自定义格式化函数 |
59
+ | min / max | `Date` | — | 可选日期范围 |
60
+ | disabledDate | `(date: Date) => boolean` | — | 自定义禁用日期 |
61
+ | size | `"sm" | "md" | "lg"` | `"md"` | 输入框尺寸 |
62
+ | allowClear | `boolean` | `false` | 允许清空 |
63
+ | open / defaultOpen / onOpenChange | `—` | — | 受控浮层显隐 |
64
+ | popupClassName / dropdownClassName | `string` | — | 浮层 className |
65
+ | disabled / readOnly / invalid / placeholder | `—` | — | 常规输入状态 |
66
+
67
+
68
+ ---
69
+ [← 回到索引](../llms.md)
@@ -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)
@@ -44,6 +44,17 @@ placement 控制滑出方向;top / bottom 用 size 控高度。
44
44
  <Drawer mask={false} />
45
45
  ```
46
46
 
47
+ ### 遮罩定制
48
+
49
+ 默认遮罩使用中性 --mask-bg,不跟随 --bg-sunken 的色相;maskClassName / maskStyle 可定制遮罩层。
50
+
51
+ ```tsx
52
+ <Drawer
53
+ maskClassName="settings-drawer-mask"
54
+ maskStyle={{ background: "var(--mask-bg)", backdropFilter: "none" }}
55
+ />
56
+ ```
57
+
47
58
  ## API
48
59
 
49
60
  **Drawer**
@@ -58,6 +69,8 @@ placement 控制滑出方向;top / bottom 用 size 控高度。
58
69
  | extra | `ReactNode` | — | 标题右侧的附加操作区 |
59
70
  | mask | `boolean` | `true` | 是否渲染遮罩 |
60
71
  | maskClosable | `boolean` | `true` | 点击遮罩关闭 |
72
+ | maskClassName | `string` | — | 遮罩层 className |
73
+ | maskStyle | `CSSProperties` | — | 遮罩层内联样式 |
61
74
  | keyboard | `boolean` | `true` | Esc 关闭 |
62
75
  | closable | `boolean` | `true` | 右上角 × |
63
76
  | closeIcon | `ReactNode` | — | 自定义关闭图标 |
@@ -16,6 +16,18 @@ import { Image, ImageGrid, SpriteImage, LayeredImage } from "@fangxinyan/lumina"
16
16
  <Image src={url} width={240} height={160} />
17
17
  ```
18
18
 
19
+ ### 预览遮罩
20
+
21
+ 全屏预览默认使用中性 --mask-bg,previewClassName / previewStyle 可单独控制预览蒙层。
22
+
23
+ ```tsx
24
+ <Image
25
+ src={url}
26
+ previewClassName="asset-preview-mask"
27
+ previewStyle={{ background: "var(--mask-bg)", backdropFilter: "none" }}
28
+ />
29
+ ```
30
+
19
31
  ### 图标 / 原始资源
20
32
 
21
33
  variant="icon" 会默认去掉外层 padding,适合 1:1 装备、物品、头像缩略图;variant="raw" 保留原始图片比例。
@@ -68,6 +80,8 @@ LayeredImage 将多张图片叠在同一个盒子里,适合头像 + 头像框、
68
80
  | padding | `number | string` | — | 外层留白,raw/icon 默认 0 |
69
81
  | objectFit / objectPosition | `CSSProperties` | — | 底层 img 的 object-fit / object-position |
70
82
  | preview | `boolean` | `true` | 支持点击全屏预览 |
83
+ | previewClassName | `string` | — | 预览蒙层 className |
84
+ | previewStyle | `CSSProperties` | — | 预览蒙层内联样式 |
71
85
  | hover | `boolean` | `true` | 悬浮放大 |
72
86
  | placeholder | `ReactNode` | — | 占位/错误时内容 |
73
87
  | imgProps | `ImgHTMLAttributes` | — | 透传到底层 img 的属性 |
@@ -34,6 +34,17 @@ Modal.confirm({
34
34
  Modal.warning({ title: "容量不足", content: "请先清理缓存。" });
35
35
  ```
36
36
 
37
+ ### 遮罩定制
38
+
39
+ 默认遮罩使用中性 --mask-bg,不跟随 --bg-sunken 的色相;maskClassName / maskStyle 可定制遮罩层。
40
+
41
+ ```tsx
42
+ <Modal
43
+ maskClassName="settings-mask"
44
+ maskStyle={{ background: "var(--mask-bg)", backdropFilter: "none" }}
45
+ />
46
+ ```
47
+
37
48
  ### 确认操作 (footer 自定义)
38
49
 
39
50
  用 footer 自定义底部按钮。传 null 可以去掉 footer。
@@ -115,6 +126,8 @@ bodyClassName / bodyStyle / bodyProps 可直接作用到正文容器;bodyOverf
115
126
  | closable | `boolean` | `true` | 显示右上角 × |
116
127
  | closeIcon | `ReactNode` | — | 自定义关闭图标 |
117
128
  | maskClosable | `boolean` | `true` | 点击遮罩关闭 |
129
+ | maskClassName | `string` | — | 遮罩层 className |
130
+ | maskStyle | `CSSProperties` | — | 遮罩层内联样式 |
118
131
  | escClosable | `boolean` | `true` | Esc 关闭 |
119
132
  | width | `number | string` | `440` | 宽度 |
120
133
  | destroyOnClose | `boolean` | `false` | 关闭时卸载子树 |
@@ -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.13`
6
+ - **版本**: `0.6.15`
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.13",
3
+ "version": "0.6.15",
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",
@@ -1,112 +0,0 @@
1
- 'use strict';
2
-
3
- var chunkOCQC2ZSV_cjs = require('./chunk-OCQC2ZSV.cjs');
4
- require('./tokens-OJLK3XMZ.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(chunkOCQC2ZSV_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(chunkOCQC2ZSV_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;
@@ -1,90 +0,0 @@
1
- import { Icon } from './chunk-HHBXCBZP.js';
2
- import './tokens-OJLK3XMZ.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 };