@icen.ai/ui 0.4.0 → 0.5.0

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 (55) hide show
  1. package/dist/behaviors/back-top.mjs +84 -0
  2. package/dist/behaviors/command-palette.mjs +177 -0
  3. package/dist/behaviors/date-picker.mjs +228 -0
  4. package/dist/behaviors/input.mjs +170 -1
  5. package/dist/behaviors/notification.mjs +754 -0
  6. package/dist/behaviors/select.mjs +151 -22
  7. package/dist/behaviors/split-pane.mjs +102 -0
  8. package/dist/behaviors/upload.mjs +165 -14
  9. package/dist/components/back-top.css +88 -0
  10. package/dist/components/back-top.mjs +3 -0
  11. package/dist/components/badge.css +131 -0
  12. package/dist/components/badge.mjs +2 -0
  13. package/dist/components/breadcrumb.css +57 -0
  14. package/dist/components/card.css +68 -0
  15. package/dist/components/command-palette.css +246 -0
  16. package/dist/components/command-palette.mjs +3 -0
  17. package/dist/components/content.css +214 -0
  18. package/dist/components/copy.css +93 -0
  19. package/dist/components/copy.mjs +3 -0
  20. package/dist/components/date-picker.css +244 -0
  21. package/dist/components/date-picker.mjs +3 -0
  22. package/dist/components/empty.css +73 -3
  23. package/dist/components/feedback.css +239 -1
  24. package/dist/components/form.css +119 -0
  25. package/dist/components/form.mjs +2 -0
  26. package/dist/components/input.css +24 -1
  27. package/dist/components/media.css +144 -1
  28. package/dist/components/nav.css +99 -0
  29. package/dist/components/notification.css +387 -0
  30. package/dist/components/notification.mjs +3 -0
  31. package/dist/components/panel.css +100 -5
  32. package/dist/components/pill.css +70 -0
  33. package/dist/components/scroll-area.css +112 -0
  34. package/dist/components/scroll-area.mjs +2 -0
  35. package/dist/components/segmented.css +75 -0
  36. package/dist/components/select.css +97 -2
  37. package/dist/components/sidebar.css +118 -0
  38. package/dist/components/slider.css +113 -0
  39. package/dist/components/split-pane.css +112 -0
  40. package/dist/components/split-pane.mjs +3 -0
  41. package/dist/components/stat.css +129 -6
  42. package/dist/components/steps.css +97 -0
  43. package/dist/components/switch.css +142 -0
  44. package/dist/components/table.css +86 -3
  45. package/dist/components/tabs.css +122 -1
  46. package/dist/components/tag.css +164 -0
  47. package/dist/components/tag.mjs +2 -0
  48. package/dist/components/toast.css +114 -0
  49. package/dist/components/toolbar.css +101 -0
  50. package/dist/components/toolbar.mjs +2 -0
  51. package/dist/components/upload.css +61 -4
  52. package/dist/index.mjs +1858 -69
  53. package/dist/registry.json +64 -1
  54. package/dist/ui.css +4320 -278
  55. package/package.json +1 -1
@@ -375,3 +375,217 @@
375
375
  transition: none;
376
376
  }
377
377
  }
378
+
379
+ /* ── list 增强 ── */
380
+
381
+ /* 列表项带前置图标/头像 */
382
+ .list-item-leading {
383
+ display: inline-flex;
384
+ align-items: center;
385
+ justify-content: center;
386
+ flex-shrink: 0;
387
+ margin-right: var(--density-space-sm);
388
+ }
389
+ .list-item-leading svg { width: 16px; height: 16px; color: var(--token-text-faint); }
390
+ .list-item-content {
391
+ flex: 1;
392
+ min-width: 0;
393
+ display: flex;
394
+ flex-direction: column;
395
+ gap: 1px;
396
+ }
397
+ .list-item-title {
398
+ font-size: var(--density-font-size-md);
399
+ color: var(--token-text);
400
+ overflow: hidden;
401
+ text-overflow: ellipsis;
402
+ white-space: nowrap;
403
+ }
404
+ .list-item-meta {
405
+ font-size: var(--density-font-size-xs);
406
+ color: var(--token-text-faint);
407
+ }
408
+ .list-item-trailing {
409
+ flex-shrink: 0;
410
+ margin-left: var(--density-space-sm);
411
+ font-size: var(--density-font-size-xs);
412
+ color: var(--token-text-faint);
413
+ }
414
+ .list-item--selectable {
415
+ cursor: pointer;
416
+ }
417
+ .list-item.is-selected {
418
+ background: var(--token-accent-subtle);
419
+ }
420
+ .list-item.is-selected .list-item-title { color: var(--token-accent); font-weight: 500; }
421
+
422
+ /* 列表项 flex 布局(leading + content + trailing) */
423
+ .list-item--flex {
424
+ display: flex;
425
+ align-items: center;
426
+ }
427
+
428
+ /* 斑马列表 */
429
+ .list--striped .list-item:nth-child(odd) {
430
+ background: color-mix(in srgb, var(--token-bg-soft) 40%, transparent);
431
+ }
432
+
433
+ /* ── timeline 增强 ── */
434
+
435
+ /* 右侧时间线(dot 在右) */
436
+ .timeline--right .timeline-item { flex-direction: row-reverse; }
437
+ .timeline--right .timeline-item:not(:last-child)::after {
438
+ left: auto;
439
+ right: 13.5px;
440
+ }
441
+ .timeline--right .timeline-body { text-align: right; }
442
+ .timeline--right .timeline-time { margin-left: 0; margin-right: auto; }
443
+
444
+ /* 交替时间线(奇左偶右) */
445
+ .timeline--alternate .timeline-item:nth-child(even) { flex-direction: row-reverse; }
446
+ .timeline--alternate .timeline-item:nth-child(even):not(:last-child)::after {
447
+ left: auto; right: 13.5px;
448
+ }
449
+ .timeline--alternate .timeline-item:nth-child(even) .timeline-body { text-align: right; }
450
+ .timeline--alternate .timeline-item:nth-child(even) .timeline-time {
451
+ margin-left: 0; margin-right: auto;
452
+ }
453
+
454
+ /* 自定义 dot 尺寸 */
455
+ .timeline-dot--sm { width: 20px; height: 20px; }
456
+ .timeline-dot--sm svg { width: 10px; height: 10px; }
457
+ .timeline-dot--sm ~ .timeline-item:not(:last-child)::after,
458
+ .timeline--sm .timeline-item:not(:last-child)::after { left: 10px; top: 24px; }
459
+
460
+ /* 时间线自定义内容槽(放标签、卡片等) */
461
+ .timeline-extra {
462
+ margin-top: var(--density-space-xs);
463
+ padding: var(--density-space-sm);
464
+ background: var(--token-bg-soft);
465
+ border-radius: var(--radius-sm);
466
+ font-size: var(--density-font-size-sm);
467
+ }
468
+
469
+ /* ── desc 增强 ── */
470
+
471
+ /* 行内描述(label: value 在同一行) */
472
+ .desc--inline .desc-item {
473
+ display: flex;
474
+ align-items: baseline;
475
+ gap: var(--density-space-sm);
476
+ padding: 4px 0;
477
+ }
478
+ .desc--inline .desc-item dt {
479
+ flex-shrink: 0;
480
+ min-width: 80px;
481
+ }
482
+ .desc--inline .desc-item dd {
483
+ flex: 1;
484
+ }
485
+
486
+ /* 垂直描述(label 在上,value 在下) */
487
+ .desc--vertical .desc-item {
488
+ display: flex;
489
+ flex-direction: column;
490
+ gap: 2px;
491
+ }
492
+
493
+ /* 可复制描述值 */
494
+ .desc-copy {
495
+ display: inline-flex;
496
+ align-items: center;
497
+ gap: var(--density-space-xs);
498
+ }
499
+ .desc-copy-btn {
500
+ display: inline-flex;
501
+ align-items: center;
502
+ padding: 2px;
503
+ border: 0;
504
+ border-radius: var(--radius-xs);
505
+ background: transparent;
506
+ color: var(--token-text-faint);
507
+ cursor: pointer;
508
+ transition: color var(--icen-tx-fast), background-color var(--icen-tx-fast);
509
+ }
510
+ .desc-copy-btn:hover { color: var(--token-accent); background: var(--token-fill-1); }
511
+ .desc-copy-btn svg { width: 12px; height: 12px; }
512
+
513
+ /* ── tree 增强 ── */
514
+
515
+ /* 带连接线的树 */
516
+ .tree--lined ul {
517
+ position: relative;
518
+ margin-left: 7px;
519
+ padding-left: 0;
520
+ border-left: 1px solid var(--token-outline-soft);
521
+ }
522
+ .tree--lined .tree-node {
523
+ position: relative;
524
+ }
525
+ .tree--lined ul > li > .tree-node::before {
526
+ content: '';
527
+ position: absolute;
528
+ left: -8px;
529
+ top: 50%;
530
+ width: 8px;
531
+ height: 1px;
532
+ background: var(--token-outline-soft);
533
+ }
534
+
535
+ /* 树节点复选框(checkbox tree) */
536
+ .tree-checkbox {
537
+ width: 14px;
538
+ height: 14px;
539
+ flex-shrink: 0;
540
+ margin-right: 2px;
541
+ }
542
+
543
+ /* 树拖拽视觉态 */
544
+ .tree-node.is-dragging {
545
+ opacity: 0.5;
546
+ }
547
+ .tree-node.is-drop-target {
548
+ box-shadow: inset 0 -2px var(--token-accent);
549
+ }
550
+
551
+ /* 树搜索高亮 */
552
+ .tree-label mark {
553
+ background: color-mix(in srgb, var(--token-warning) 30%, transparent);
554
+ color: inherit;
555
+ border-radius: 2px;
556
+ padding: 0 1px;
557
+ }
558
+
559
+ /* ── kbd 增强 ── */
560
+
561
+ /* 大号 kbd(展示用) */
562
+ .kbd--lg {
563
+ height: 28px;
564
+ min-width: 28px;
565
+ padding: 0 var(--density-space-sm);
566
+ font-size: var(--density-font-size-md);
567
+ }
568
+
569
+ /* kbd 按下态(动画反馈) */
570
+ .kbd.is-pressed {
571
+ transform: translateY(1px);
572
+ box-shadow: none;
573
+ }
574
+
575
+ /* ── code-inline 增强 ── */
576
+ .code-inline--success { color: var(--token-success); }
577
+ .code-inline--warning { color: var(--token-warning); }
578
+ .code-inline--error { color: var(--token-error); }
579
+
580
+ /* 代码块(多行,非行内) */
581
+ .code-block {
582
+ padding: var(--density-space-sm) var(--density-space-md);
583
+ background: var(--token-bg-soft);
584
+ border: 1px solid var(--token-outline-soft);
585
+ border-radius: var(--radius-md);
586
+ font-family: var(--font-mono);
587
+ font-size: var(--density-font-size-sm);
588
+ color: var(--token-text);
589
+ overflow-x: auto;
590
+ line-height: 1.6;
591
+ }
@@ -0,0 +1,93 @@
1
+ /*
2
+ * @icen.ai/ui — Component: copy(复制按钮,与 behaviors/copy 配套)
3
+ *
4
+ * 完整契约:
5
+ * 文本变体(成功后文本 1.4s 内变「已复制」再还原):
6
+ * <button class="copy-btn" data-copy="复制的文本">复制</button>
7
+ * <button class="copy-btn copy-btn--ghost" data-copy="…">复制链接</button>
8
+ *
9
+ * 图标变体(带 data-copy-icon,仅加 .done 类;由 CSS 显隐子 svg):
10
+ * <button class="copy-btn copy-btn--icon" data-copy="…" data-copy-icon aria-label="复制">
11
+ * <svg class="copy-icon-clipboard">…</svg>
12
+ * <svg class="copy-icon-check" hidden>…</svg>
13
+ * </button>
14
+ *
15
+ * behavior 自动处理:
16
+ * - 文本变体:成功后 textContent = '已复制' + 加 .done 类,1.4s 后还原
17
+ * - 图标变体(带 data-copy-icon):仅加 .done 类(不改文本),由 CSS 切换 svg 显隐
18
+ *
19
+ * 与 toast.ok 区别:copy 是"原地反馈"(按钮自身闪烁),toast 是"全局通知"。
20
+ */
21
+
22
+ .copy-btn {
23
+ display: inline-flex;
24
+ align-items: center;
25
+ justify-content: center;
26
+ gap: var(--density-space-xs);
27
+ height: var(--density-input-height-sm);
28
+ padding: 0 var(--density-space-sm);
29
+ background: var(--token-control);
30
+ color: var(--token-text-muted);
31
+ border: 1px solid var(--token-outline-soft);
32
+ border-radius: var(--radius-sm);
33
+ font: inherit;
34
+ font-size: var(--density-font-size-sm);
35
+ cursor: pointer;
36
+ -webkit-tap-highlight-color: transparent;
37
+ transition:
38
+ color var(--icen-tx-fast),
39
+ border-color var(--icen-tx-fast),
40
+ background-color var(--icen-tx-fast);
41
+ }
42
+ .copy-btn:hover {
43
+ color: var(--token-text);
44
+ border-color: var(--icen-hover-border);
45
+ }
46
+ .copy-btn:focus-visible {
47
+ outline: none;
48
+ box-shadow: var(--icen-ring);
49
+ }
50
+ .copy-btn:disabled,
51
+ .copy-btn[aria-disabled='true'] {
52
+ opacity: var(--icen-disabled-opacity);
53
+ cursor: not-allowed;
54
+ pointer-events: none;
55
+ }
56
+
57
+ /* ghost 变体:透明底,纯描边 / hover 才显底 */
58
+ .copy-btn--ghost {
59
+ background: transparent;
60
+ border-color: var(--token-line-soft);
61
+ }
62
+ .copy-btn--ghost:hover {
63
+ background: var(--token-fill-1);
64
+ border-color: var(--token-accent);
65
+ }
66
+
67
+ /* ── 成功闪烁态(behavior 1.4s 后移除)── */
68
+ .copy-btn.done {
69
+ color: var(--token-success);
70
+ border-color: color-mix(in srgb, var(--token-success) 40%, transparent);
71
+ background: color-mix(in srgb, var(--token-success) 10%, transparent);
72
+ }
73
+
74
+ /* ── 图标变体:方形按钮,仅放 svg ── */
75
+ .copy-btn--icon {
76
+ width: 28px;
77
+ height: 28px;
78
+ padding: 0;
79
+ }
80
+ .copy-btn--icon svg {
81
+ width: 14px;
82
+ height: 14px;
83
+ flex-shrink: 0;
84
+ }
85
+
86
+ /* .done 时显隐切换:剪贴板 → 对勾 */
87
+ .copy-btn[data-copy-icon] .copy-icon-check { display: none; }
88
+ .copy-btn[data-copy-icon].done .copy-icon-clipboard { display: none; }
89
+ .copy-btn[data-copy-icon].done .copy-icon-check { display: inline-block; }
90
+
91
+ @media (prefers-reduced-motion: reduce) {
92
+ .copy-btn { transition: none; }
93
+ }
@@ -0,0 +1,3 @@
1
+ // @icen.ai/ui — kit: copy(CSS + behavior 一行入口;构建产物,勿手改)
2
+ import './copy.css';
3
+ export * from '../behaviors/copy.mjs';
@@ -0,0 +1,244 @@
1
+ /*
2
+ * @icen.ai/ui — Component: date-picker(日期选择,与 behaviors/date-picker 配套)
3
+ *
4
+ * 契约:
5
+ * <div class="date-picker" data-date-picker data-date-picker-input="id">
6
+ * <button class="date-picker-trigger" type="button" aria-haspopup="dialog">
7
+ * <span class="date-picker-value">2026-07-29</span>
8
+ * <svg class="date-picker-icon">…日历 svg…</svg>
9
+ * </button>
10
+ * <input type="hidden" id="id" name="date" value="2026-07-29" />
11
+ * </div>
12
+ *
13
+ * 或直接挂到普通 input(behavior 自动包裹触发器外观):
14
+ * <input class="date-picker-input" data-date-picker value="2026-07-29" />
15
+ *
16
+ * behavior 渲染面板(portal 到 body):
17
+ * <div class="date-picker-panel" role="dialog">
18
+ * <div class="date-picker-head">
19
+ * <button class="date-picker-nav" data-prev>‹</button>
20
+ * <span class="date-picker-title">2026 年 7 月</span>
21
+ * <button class="date-picker-nav" data-next>›</button>
22
+ * </div>
23
+ * <div class="date-picker-weekdays">
24
+ * <span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span><span>日</span>
25
+ * </div>
26
+ * <div class="date-picker-grid">
27
+ * <button class="date-picker-cell [.is-outside] [.is-today] [.is-selected] [.is-disabled]">15</button>
28
+ * …
29
+ * </div>
30
+ * <div class="date-picker-foot">
31
+ * <button class="date-picker-today">今天</button>
32
+ * <button class="date-picker-clear">清除</button>
33
+ * </div>
34
+ * </div>
35
+ *
36
+ * 可选 data-*:
37
+ * data-date-picker-format="yyyy-mm-dd" 显示格式
38
+ * data-date-picker-min="2026-01-01" 最小可选日期
39
+ * data-date-picker-max="2026-12-31" 最大可选日期
40
+ * data-date-picker-week-start="0" 周首日(0=周日,1=周一,默认 1)
41
+ */
42
+
43
+ .date-picker {
44
+ display: inline-block;
45
+ position: relative;
46
+ }
47
+
48
+ .date-picker-trigger {
49
+ display: inline-flex;
50
+ align-items: center;
51
+ gap: var(--density-space-xs);
52
+ width: 100%;
53
+ height: var(--density-input-height-md);
54
+ padding: 0 var(--density-space-sm);
55
+ background: var(--token-control);
56
+ border: 1px solid var(--token-outline-soft);
57
+ border-radius: var(--radius-md);
58
+ box-shadow: var(--token-shadow-inset);
59
+ color: var(--token-text);
60
+ font: inherit;
61
+ font-size: var(--density-font-size-md);
62
+ cursor: pointer;
63
+ -webkit-tap-highlight-color: transparent;
64
+ transition: border-color var(--icen-tx-fast), box-shadow var(--icen-tx-fast);
65
+ }
66
+ .date-picker-trigger:hover { border-color: var(--icen-hover-border); }
67
+ .date-picker-trigger.is-open {
68
+ border-color: var(--icen-control-focus-border);
69
+ box-shadow: var(--icen-control-focus-shadow);
70
+ }
71
+ .date-picker-trigger:focus-visible {
72
+ outline: none;
73
+ border-color: var(--icen-control-focus-border);
74
+ box-shadow: var(--icen-control-focus-shadow);
75
+ }
76
+ .date-picker-value {
77
+ flex: 1;
78
+ min-width: 0;
79
+ text-align: left;
80
+ overflow: hidden;
81
+ text-overflow: ellipsis;
82
+ white-space: nowrap;
83
+ font-variant-numeric: tabular-nums;
84
+ }
85
+ .date-picker-value.is-empty { color: color-mix(in srgb, var(--token-text-faint) 60%, transparent); }
86
+ .date-picker-icon { display: inline-flex; color: var(--token-text-faint); flex-shrink: 0; }
87
+ .date-picker-icon svg { width: 14px; height: 14px; }
88
+
89
+ /* 尺寸 */
90
+ .date-picker-trigger.date-picker-trigger--sm { height: var(--density-input-height-sm); font-size: var(--density-font-size-sm); }
91
+ .date-picker-trigger.date-picker-trigger--lg { height: var(--density-input-height-lg); font-size: var(--density-font-size-lg); }
92
+
93
+ /* ── 面板 ── */
94
+ .date-picker-panel {
95
+ position: fixed;
96
+ z-index: var(--z-popover);
97
+ width: 280px;
98
+ padding: var(--density-space-sm);
99
+ background: var(--token-card-strong);
100
+ border: 1px solid var(--token-outline);
101
+ border-radius: var(--radius-md);
102
+ box-shadow: var(--token-shadow-overlay);
103
+ font-size: var(--density-font-size-sm);
104
+ animation: icen-dp-in var(--icen-tx-fast);
105
+ }
106
+ @keyframes icen-dp-in {
107
+ from { opacity: 0; transform: scale(0.96) translateY(-4px); }
108
+ to { opacity: 1; transform: scale(1) translateY(0); }
109
+ }
110
+
111
+ .date-picker-head {
112
+ display: flex;
113
+ align-items: center;
114
+ justify-content: space-between;
115
+ margin-bottom: var(--density-space-sm);
116
+ }
117
+ .date-picker-title {
118
+ font-weight: 600;
119
+ color: var(--token-text);
120
+ font-variant-numeric: tabular-nums;
121
+ flex: 1;
122
+ text-align: center;
123
+ }
124
+ .date-picker-nav {
125
+ display: inline-flex;
126
+ align-items: center;
127
+ justify-content: center;
128
+ width: 24px;
129
+ height: 24px;
130
+ padding: 0;
131
+ border: 0;
132
+ border-radius: var(--radius-xs);
133
+ background: transparent;
134
+ color: var(--token-text-muted);
135
+ font-size: var(--density-font-size-md);
136
+ cursor: pointer;
137
+ -webkit-tap-highlight-color: transparent;
138
+ transition: color var(--icen-tx-fast), background-color var(--icen-tx-fast);
139
+ }
140
+ .date-picker-nav:hover { color: var(--token-text); background: var(--token-fill-1); }
141
+ .date-picker-nav:focus-visible {
142
+ outline: none;
143
+ box-shadow: var(--icen-ring);
144
+ }
145
+
146
+ .date-picker-weekdays {
147
+ display: grid;
148
+ grid-template-columns: repeat(7, 1fr);
149
+ gap: 2px;
150
+ margin-bottom: 4px;
151
+ }
152
+ .date-picker-weekdays > span {
153
+ display: flex;
154
+ align-items: center;
155
+ justify-content: center;
156
+ height: 24px;
157
+ font-size: var(--density-font-size-xs);
158
+ color: var(--token-text-faint);
159
+ font-weight: 500;
160
+ }
161
+
162
+ .date-picker-grid {
163
+ display: grid;
164
+ grid-template-columns: repeat(7, 1fr);
165
+ gap: 2px;
166
+ }
167
+ .date-picker-cell {
168
+ display: flex;
169
+ align-items: center;
170
+ justify-content: center;
171
+ height: 30px;
172
+ padding: 0;
173
+ border: 0;
174
+ border-radius: var(--radius-sm);
175
+ background: transparent;
176
+ color: var(--token-text);
177
+ font: inherit;
178
+ font-size: var(--density-font-size-sm);
179
+ font-variant-numeric: tabular-nums;
180
+ cursor: pointer;
181
+ -webkit-tap-highlight-color: transparent;
182
+ transition: background-color var(--icen-tx-fast), color var(--icen-tx-fast);
183
+ }
184
+ .date-picker-cell:hover { background: var(--token-fill-1); }
185
+ .date-picker-cell.is-today {
186
+ border: 1px solid var(--token-accent);
187
+ color: var(--token-accent);
188
+ font-weight: 600;
189
+ }
190
+ .date-picker-cell.is-selected {
191
+ background: var(--token-accent);
192
+ color: var(--token-on-accent, #fff);
193
+ font-weight: 600;
194
+ }
195
+ .date-picker-cell.is-selected.is-today { border-color: var(--token-on-accent, #fff); }
196
+ .date-picker-cell.is-outside {
197
+ color: var(--token-text-faint);
198
+ opacity: 0.55;
199
+ }
200
+ .date-picker-cell.is-disabled {
201
+ color: var(--token-text-faint);
202
+ opacity: 0.35;
203
+ cursor: not-allowed;
204
+ pointer-events: none;
205
+ }
206
+ .date-picker-cell:focus-visible {
207
+ outline: none;
208
+ box-shadow: var(--icen-ring);
209
+ }
210
+
211
+ .date-picker-foot {
212
+ display: flex;
213
+ justify-content: space-between;
214
+ gap: var(--density-space-xs);
215
+ margin-top: var(--density-space-sm);
216
+ padding-top: var(--density-space-sm);
217
+ border-top: 1px solid var(--token-line-soft);
218
+ }
219
+ .date-picker-today,
220
+ .date-picker-clear {
221
+ padding: 4px var(--density-space-sm);
222
+ border: 0;
223
+ border-radius: var(--radius-xs);
224
+ background: transparent;
225
+ color: var(--token-accent);
226
+ font: inherit;
227
+ font-size: var(--density-font-size-xs);
228
+ cursor: pointer;
229
+ -webkit-tap-highlight-color: transparent;
230
+ transition: background-color var(--icen-tx-fast);
231
+ }
232
+ .date-picker-today:hover,
233
+ .date-picker-clear:hover { background: var(--token-fill-1); }
234
+ .date-picker-today:focus-visible,
235
+ .date-picker-clear:focus-visible {
236
+ outline: none;
237
+ box-shadow: var(--icen-ring);
238
+ }
239
+ .date-picker-clear { color: var(--token-text-muted); }
240
+
241
+ @media (prefers-reduced-motion: reduce) {
242
+ .date-picker-panel { animation: none; }
243
+ .date-picker-cell { transition: none; }
244
+ }
@@ -0,0 +1,3 @@
1
+ // @icen.ai/ui — kit: date-picker(CSS + behavior 一行入口;构建产物,勿手改)
2
+ import './date-picker.css';
3
+ export * from '../behaviors/date-picker.mjs';
@@ -1,16 +1,25 @@
1
1
  /*
2
- * @icen.ai/ui — Component: empty(空状态 / 无数据 / 404 占位)
2
+ * @icen.ai/ui — Component: empty(空状态 / 无数据 / 404 / 错误 / 维护中)
3
3
  *
4
4
  * 完整契约:
5
- * <div class="empty [.empty--sm|.empty--lg]">
5
+ * <div class="empty [.empty--sm|.empty--lg]
6
+ * [.empty--error|.empty--404|.empty--search|.empty--maintenance|.empty--network]">
6
7
  * <div class="empty-icon">…svg…</div> ← 可选,缺省显示默认占位
7
8
  * <h3 class="empty-title">暂无数据</h3>
8
9
  * <p class="empty-desc">描述文案(可选)</p>
9
10
  * <div class="empty-action"> ← 可选:操作按钮位
10
11
  * <button class="btn btn-primary">…</button>
12
+ * <button class="btn">…</button>
11
13
  * </div>
12
14
  * </div>
13
15
  *
16
+ * 类型预设(改图标底色与基调):
17
+ * .empty--error 错误(红底图标)
18
+ * .empty--404 404(中性大字)
19
+ * .empty--search 搜索无结果
20
+ * .empty--maintenance 维护中(warning 底)
21
+ * .empty--network 网络错误(info 底)
22
+ *
14
23
  * 规格源自 opengal src/presentation/ui/data/display.tsx 的 EmptyState。
15
24
  */
16
25
 
@@ -25,6 +34,7 @@
25
34
  .empty--sm { padding: var(--density-space-md); }
26
35
  .empty--lg { padding: 64px var(--density-space-md); }
27
36
 
37
+ /* ── 图标 ── */
28
38
  .empty-icon {
29
39
  width: 48px;
30
40
  height: 48px;
@@ -44,6 +54,28 @@
44
54
  .empty--lg .empty-icon svg { width: 32px; height: 32px; }
45
55
  .empty--sm .empty-icon svg { width: 18px; height: 18px; }
46
56
 
57
+ /* ── 类型预设 ── */
58
+ .empty--error .empty-icon {
59
+ background: color-mix(in srgb, var(--token-error) 10%, transparent);
60
+ border-color: color-mix(in srgb, var(--token-error) 20%, transparent);
61
+ color: var(--token-error);
62
+ }
63
+ .empty--maintenance .empty-icon {
64
+ background: color-mix(in srgb, var(--token-warning) 10%, transparent);
65
+ border-color: color-mix(in srgb, var(--token-warning) 20%, transparent);
66
+ color: var(--token-warning);
67
+ }
68
+ .empty--network .empty-icon {
69
+ background: color-mix(in srgb, var(--token-info) 10%, transparent);
70
+ border-color: color-mix(in srgb, var(--token-info) 20%, transparent);
71
+ color: var(--token-info);
72
+ }
73
+ .empty--search .empty-icon {
74
+ background: var(--token-fill-1);
75
+ color: var(--token-text-muted);
76
+ }
77
+
78
+ /* ── 标题与描述 ── */
47
79
  .empty-title {
48
80
  font-size: var(--density-font-size-md);
49
81
  font-weight: 500;
@@ -51,15 +83,53 @@
51
83
  margin: 0;
52
84
  line-height: 1.4;
53
85
  }
86
+ .empty--error .empty-title { color: var(--token-error); }
54
87
  .empty-desc {
55
88
  font-size: var(--density-font-size-sm);
56
89
  color: var(--token-text-muted);
57
90
  margin: 4px 0 0;
58
- max-width: 240px;
91
+ max-width: 280px;
59
92
  line-height: 1.5;
60
93
  }
94
+
95
+ /* ── 操作区 ── */
61
96
  .empty-action {
62
97
  margin-top: var(--density-space-md);
63
98
  display: flex;
64
99
  gap: var(--density-space-xs);
100
+ flex-wrap: wrap;
101
+ justify-content: center;
102
+ }
103
+
104
+ /* ── 404 大数字 ── */
105
+ .empty--404 .empty-title {
106
+ font-size: 72px;
107
+ font-weight: 800;
108
+ font-family: var(--font-heading);
109
+ line-height: 1;
110
+ letter-spacing: -0.02em;
111
+ color: var(--token-text-faint);
112
+ margin-bottom: var(--density-space-sm);
113
+ }
114
+ .empty--404 .empty-icon { display: none; }
115
+
116
+ /* ── 插画背景(使用方可用渐变背景替代图标) ── */
117
+ .empty--illustrated {
118
+ background: radial-gradient(ellipse at center,
119
+ color-mix(in srgb, var(--token-accent) 6%, transparent) 0%,
120
+ transparent 70%);
121
+ border-radius: var(--radius-lg);
122
+ }
123
+
124
+ /* ── 内嵌模式(empty 嵌入卡片/面板内时无 padding) ── */
125
+ .empty--inline {
126
+ padding: var(--density-space-md) var(--density-space-sm);
127
+ }
128
+
129
+ @media (max-width: 480px) {
130
+ .empty--404 .empty-title { font-size: 56px; }
131
+ }
132
+
133
+ @media (prefers-reduced-motion: reduce) {
134
+ .empty { animation: none; }
65
135
  }