@hsu-react/ui 2.4.7 → 2.4.9

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 (36) hide show
  1. package/es/components/Chat/ChatHistory/_components/HistoryGroup/index.module.scss +2 -1
  2. package/es/components/Chat/ChatInput/index.d.ts +10 -0
  3. package/es/components/Chat/ChatInput/index.js +7 -2
  4. package/es/components/Chat/ChatList/_components/Assistant/AssistantItem/_components/QuoteList/index.module.scss +2 -1
  5. package/es/components/Pagination/index.module.scss +2 -1
  6. package/es/components/Panel/ListPanel/_components/ColumnMgt/index.module.scss +2 -1
  7. package/es/components/SecondConf/index.module.scss +3 -1
  8. package/es/components/TabBar/index.module.scss +4 -1
  9. package/es/styles/antd-overload.scss +27 -1
  10. package/es/styles/tokens.js +10 -1
  11. package/es/styles/tokens.json +1 -1
  12. package/es/styles/tokens.scss +1 -1
  13. package/lib/components/Chat/ChatHistory/_components/HistoryGroup/index.module.scss +2 -1
  14. package/lib/components/Chat/ChatInput/index.d.ts +10 -0
  15. package/lib/components/Chat/ChatInput/index.js +6 -2
  16. package/lib/components/Chat/ChatList/_components/Assistant/AssistantItem/_components/QuoteList/index.module.scss +2 -1
  17. package/lib/components/Pagination/index.module.scss +2 -1
  18. package/lib/components/Panel/ListPanel/_components/ColumnMgt/index.module.scss +2 -1
  19. package/lib/components/SecondConf/index.module.scss +3 -1
  20. package/lib/components/TabBar/index.module.scss +4 -1
  21. package/lib/styles/antd-overload.scss +27 -1
  22. package/lib/styles/tokens.js +10 -1
  23. package/lib/styles/tokens.json +1 -1
  24. package/lib/styles/tokens.scss +1 -1
  25. package/package.json +1 -1
  26. package/src/components/Chat/ChatHistory/_components/HistoryGroup/index.module.scss +2 -1
  27. package/src/components/Chat/ChatInput/index.tsx +15 -1
  28. package/src/components/Chat/ChatList/_components/Assistant/AssistantItem/_components/QuoteList/index.module.scss +2 -1
  29. package/src/components/Pagination/index.module.scss +2 -1
  30. package/src/components/Panel/ListPanel/_components/ColumnMgt/index.module.scss +2 -1
  31. package/src/components/SecondConf/index.module.scss +3 -1
  32. package/src/components/TabBar/index.module.scss +4 -1
  33. package/src/styles/antd-overload.scss +27 -1
  34. package/src/styles/tokens.json +1 -1
  35. package/src/styles/tokens.scss +1 -1
  36. package/src/styles/tokens.ts +10 -1
@@ -8,7 +8,8 @@
8
8
 
9
9
  font-size: 14px;
10
10
  font-weight: bold;
11
- color: var(--vita-subtle-foreground);
11
+ // 分组标题(「今天」「近 7 天」),与侧栏菜单的分组标题同一件事
12
+ color: var(--vita-muted-foreground);
12
13
 
13
14
  cursor: default;
14
15
  }
@@ -51,6 +51,16 @@ export interface ChatInputProps {
51
51
  onFileInterceptClick?: (e: React.MouseEvent<HTMLSpanElement>) => void;
52
52
  buttonGroup?: ButtonProps[];
53
53
  uploadEnabled?: boolean;
54
+ /**
55
+ * Disable sending. The send button turns disabled and Enter no longer submits;
56
+ * the textarea stays editable so a half-typed message is never lost.
57
+ *
58
+ * The component already disables the send button during its own uploads
59
+ * (`isUpload`), but consumers that run their own upload flow
60
+ * (`uploadEnabled={false}`) had no way in: they could only intercept `onSend`
61
+ * and pop a warning, leaving the button looking perfectly clickable.
62
+ */
63
+ disabled?: boolean;
54
64
  }
55
65
  declare const ChatInput: React.FC<ChatInputProps>;
56
66
  export default ChatInput;
@@ -43,7 +43,9 @@ var ChatInput = function ChatInput(props) {
43
43
  onFileInterceptClick = props.onFileInterceptClick,
44
44
  buttonGroup = props.buttonGroup,
45
45
  _props$uploadEnabled = props.uploadEnabled,
46
- uploadEnabled = _props$uploadEnabled === void 0 ? true : _props$uploadEnabled;
46
+ uploadEnabled = _props$uploadEnabled === void 0 ? true : _props$uploadEnabled,
47
+ _props$disabled = props.disabled,
48
+ disabled = _props$disabled === void 0 ? false : _props$disabled;
47
49
  var _useState = useState(""),
48
50
  _useState2 = _slicedToArray(_useState, 2),
49
51
  value = _useState2[0],
@@ -145,6 +147,9 @@ var ChatInput = function ChatInput(props) {
145
147
 
146
148
  // Handle sending
147
149
  var handleSend = function handleSend() {
150
+ if (disabled) {
151
+ return;
152
+ }
148
153
  if (value.trim() !== "") {
149
154
  setValue("");
150
155
  onSend === null || onSend === void 0 || onSend(value);
@@ -239,7 +244,7 @@ var ChatInput = function ChatInput(props) {
239
244
  value: value,
240
245
  onSend: handleSend,
241
246
  sendIcon: sendIcon,
242
- disabled: isUpload
247
+ disabled: isUpload || disabled
243
248
  })
244
249
  })]
245
250
  })]
@@ -108,7 +108,8 @@
108
108
  transition: background-color 0.3s, color 0.3s;
109
109
 
110
110
  &:hover {
111
- color: #fff;
111
+ // 同 TabBar:主色实底上的前景色走配对令牌
112
+ color: var(--vita-primary-foreground);
112
113
 
113
114
  background-color: var(--vita-primary);
114
115
  }
@@ -95,7 +95,8 @@
95
95
  border-color: var(--vita-primary, #1890ff);
96
96
 
97
97
  > a {
98
- color: #ffffff;
98
+ // 同 TabBar:主色实底上的前景色走配对令牌
99
+ color: var(--vita-primary-foreground);
99
100
  }
100
101
  }
101
102
 
@@ -10,7 +10,8 @@
10
10
  font-size: 12px;
11
11
  font-weight: normal;
12
12
 
13
- color: var(--vita-subtle-foreground);
13
+ // 说明文字,不是占位符
14
+ color: var(--vita-muted-foreground);
14
15
  }
15
16
  }
16
17
 
@@ -29,7 +29,9 @@
29
29
 
30
30
  .text {
31
31
  font-size: 16px;
32
- color: var(--vita-subtle-foreground);
32
+ // 二次确认的正文,是这个弹窗里唯一要读的内容,不能用占位档。
33
+ // 与上面 .title 的层级差已经由 20px/bold 对 16px/normal 拉开了
34
+ color: var(--vita-muted-foreground);
33
35
  }
34
36
  }
35
37
  }
@@ -51,7 +51,10 @@
51
51
  &.active {
52
52
  background: var(--vita-primary);
53
53
 
54
- color: #fff;
54
+ // 压在主色实底上的前景色走配对令牌,不要写死白:--vita-primary 是可配置的,
55
+ // 消费方把它换成近白的中性色时(shadcn 那种 primary/primary-foreground 配法),
56
+ // 写死的白就是白压白。默认值仍是 #ffffff,彩色品牌色的消费方不受影响
57
+ color: var(--vita-primary-foreground);
55
58
 
56
59
  z-index: 2;
57
60
  }
@@ -127,7 +127,14 @@ textarea,
127
127
  line-height: 1.4;
128
128
  text-transform: uppercase;
129
129
 
130
- color: var(--vita-subtle-foreground);
130
+ // 注释写的就是 muted,值却落在 subtle —— 那一档是「占位 / 禁用文字」,
131
+ // 浅色下 #a1a1aa 压白只有 2.6:1。这是分组导航的标题,是要被读的内容,
132
+ // 而且 11px 粗体在 WCAG 里仍按正文算(大字号要 18.66px 粗体起),得够 4.5:1。
133
+ // muted(#71717a) 约 4.8:1,字号与字重维持不变。
134
+ //
135
+ // 同一类错在 tokens.ts 的 colorTextTertiary 上刚修过一次:可读的归 muted,
136
+ // 只有占位/禁用留在 subtle。这里是被本文件的单类选择器盖掉的第二处。
137
+ color: var(--vita-muted-foreground);
131
138
  }
132
139
 
133
140
  // Items within a group use more restrained left-aligned indentation (closer to CF)
@@ -193,3 +200,22 @@ textarea,
193
200
  .ant-modal-mask {
194
201
  pointer-events: auto !important;
195
202
  }
203
+
204
+ // =============================================================
205
+ // Alert 圆角:补 antd 没注入的那个变量
206
+ //
207
+ // antd 的 Alert 样式写的是 `border-radius: var(--ant-alert-border-radius)`,但在
208
+ // CSS-var 模式下它**从不注入**这个变量 —— 实测该变量读出来是「未定义」,
209
+ // 于是圆角回退成 0,四角是直的。
210
+ //
211
+ // 走组件令牌修不了:`Alert: { borderRadiusLG }` 注入的是 `--ant-border-radius-lg`
212
+ // (Alert 一次都没引用),改成 `borderRadius` 也一样不生成该变量(两种都实测过)。
213
+ // 对照组是 Table —— 它的 `--ant-table-border-radius` 同样未定义,但圆角正常 8px,
214
+ // 因为 Table 的圆角来自本库自己的 scss,不依赖 antd 那条规则。
215
+ //
216
+ // 所以只能在样式层直接给。`.ant-alert-banner` 自带 `border-radius: 0`,
217
+ // 且选择器更具体,通栏提示条不受影响。
218
+ // =============================================================
219
+ .ant-alert {
220
+ border-radius: var(--vita-radius);
221
+ }
@@ -114,7 +114,16 @@ export var toAntdTheme = function toAntdTheme(options) {
114
114
  colorInfo: primary,
115
115
  colorText: t.foreground,
116
116
  colorTextSecondary: t.mutedForeground,
117
- colorTextTertiary: t.subtleForeground,
117
+ // antd 有四档文字色,本套令牌只有三档,压缩时分界线要放对:
118
+ // tertiary 在 antd 里是**描述性的可读文字**(面包屑、表单 extra、Descriptions 的
119
+ // 标签都吃它),quaternary 才是占位与禁用。原来两档都指向 subtleForeground,
120
+ // 于是面包屑拿到了占位级的对比度 —— 浅色下 #a1a1aa 压白只有 2.56:1,
121
+ // 14px 正文按 WCAG AA 要 4.5:1,连大字号的 3:1 都不到(消费方实测)。
122
+ //
123
+ // 压深 subtleForeground 治不了:要够 4.5:1 得到 #767676,那已经和
124
+ // mutedForeground(#71717a, 4.83:1) 几乎同色,第三档等于不存在。
125
+ // 所以按语义分流 —— 可读的归 muted,只有占位/禁用留在 subtle。
126
+ colorTextTertiary: t.mutedForeground,
118
127
  colorTextQuaternary: t.subtleForeground,
119
128
  colorBgContainer: t.surface,
120
129
  colorBgElevated: t.surface,
@@ -27,7 +27,7 @@
27
27
  "hover": "#f4f4f5",
28
28
  "success": "#16a34a",
29
29
  "warning": "#f59e0b",
30
- "error": "#ef4444",
30
+ "error": "#dc2626",
31
31
  "shadow1": "0 1px 2px 0 rgba(9, 9, 11, 0.05)",
32
32
  "shadow2": "0 4px 6px -1px rgba(9, 9, 11, 0.08), 0 2px 4px -2px rgba(9, 9, 11, 0.06)",
33
33
  "shadow3": "0 10px 15px -3px rgba(9, 9, 11, 0.1), 0 4px 6px -4px rgba(9, 9, 11, 0.08)"
@@ -33,7 +33,7 @@
33
33
  --vita-hover: #f4f4f5; // 行 / 项 hover 背景
34
34
  --vita-success: #16a34a;
35
35
  --vita-warning: #f59e0b;
36
- --vita-error: #ef4444;
36
+ --vita-error: #dc2626;
37
37
  --vita-shadow-1: 0 1px 2px 0 rgba(9, 9, 11, 0.05); // 浮层阴影 - 弱
38
38
  --vita-shadow-2: 0 4px 6px -1px rgba(9, 9, 11, 0.08), 0 2px 4px -2px rgba(9, 9, 11, 0.06); // 浮层阴影 - 中
39
39
  --vita-shadow-3: 0 10px 15px -3px rgba(9, 9, 11, 0.1), 0 4px 6px -4px rgba(9, 9, 11, 0.08); // 浮层阴影 - 强
@@ -8,7 +8,8 @@
8
8
 
9
9
  font-size: 14px;
10
10
  font-weight: bold;
11
- color: var(--vita-subtle-foreground);
11
+ // 分组标题(「今天」「近 7 天」),与侧栏菜单的分组标题同一件事
12
+ color: var(--vita-muted-foreground);
12
13
 
13
14
  cursor: default;
14
15
  }
@@ -51,6 +51,16 @@ export interface ChatInputProps {
51
51
  onFileInterceptClick?: (e: React.MouseEvent<HTMLSpanElement>) => void;
52
52
  buttonGroup?: ButtonProps[];
53
53
  uploadEnabled?: boolean;
54
+ /**
55
+ * Disable sending. The send button turns disabled and Enter no longer submits;
56
+ * the textarea stays editable so a half-typed message is never lost.
57
+ *
58
+ * The component already disables the send button during its own uploads
59
+ * (`isUpload`), but consumers that run their own upload flow
60
+ * (`uploadEnabled={false}`) had no way in: they could only intercept `onSend`
61
+ * and pop a warning, leaving the button looking perfectly clickable.
62
+ */
63
+ disabled?: boolean;
54
64
  }
55
65
  declare const ChatInput: React.FC<ChatInputProps>;
56
66
  export default ChatInput;
@@ -34,7 +34,8 @@ const ChatInput = props => {
34
34
  wrapperClassName,
35
35
  onFileInterceptClick,
36
36
  buttonGroup,
37
- uploadEnabled = true
37
+ uploadEnabled = true,
38
+ disabled = false
38
39
  } = props;
39
40
  const [value, setValue] = (0, _react.useState)("");
40
41
  const [isUpload, setIsUpload] = (0, _react.useState)(false);
@@ -111,6 +112,9 @@ const ChatInput = props => {
111
112
 
112
113
  // Handle sending
113
114
  const handleSend = () => {
115
+ if (disabled) {
116
+ return;
117
+ }
114
118
  if (value.trim() !== "") {
115
119
  setValue("");
116
120
  onSend?.(value);
@@ -198,7 +202,7 @@ const ChatInput = props => {
198
202
  value: value,
199
203
  onSend: handleSend,
200
204
  sendIcon: sendIcon,
201
- disabled: isUpload
205
+ disabled: isUpload || disabled
202
206
  })
203
207
  })]
204
208
  })]
@@ -108,7 +108,8 @@
108
108
  transition: background-color 0.3s, color 0.3s;
109
109
 
110
110
  &:hover {
111
- color: #fff;
111
+ // 同 TabBar:主色实底上的前景色走配对令牌
112
+ color: var(--vita-primary-foreground);
112
113
 
113
114
  background-color: var(--vita-primary);
114
115
  }
@@ -95,7 +95,8 @@
95
95
  border-color: var(--vita-primary, #1890ff);
96
96
 
97
97
  > a {
98
- color: #ffffff;
98
+ // 同 TabBar:主色实底上的前景色走配对令牌
99
+ color: var(--vita-primary-foreground);
99
100
  }
100
101
  }
101
102
 
@@ -10,7 +10,8 @@
10
10
  font-size: 12px;
11
11
  font-weight: normal;
12
12
 
13
- color: var(--vita-subtle-foreground);
13
+ // 说明文字,不是占位符
14
+ color: var(--vita-muted-foreground);
14
15
  }
15
16
  }
16
17
 
@@ -29,7 +29,9 @@
29
29
 
30
30
  .text {
31
31
  font-size: 16px;
32
- color: var(--vita-subtle-foreground);
32
+ // 二次确认的正文,是这个弹窗里唯一要读的内容,不能用占位档。
33
+ // 与上面 .title 的层级差已经由 20px/bold 对 16px/normal 拉开了
34
+ color: var(--vita-muted-foreground);
33
35
  }
34
36
  }
35
37
  }
@@ -51,7 +51,10 @@
51
51
  &.active {
52
52
  background: var(--vita-primary);
53
53
 
54
- color: #fff;
54
+ // 压在主色实底上的前景色走配对令牌,不要写死白:--vita-primary 是可配置的,
55
+ // 消费方把它换成近白的中性色时(shadcn 那种 primary/primary-foreground 配法),
56
+ // 写死的白就是白压白。默认值仍是 #ffffff,彩色品牌色的消费方不受影响
57
+ color: var(--vita-primary-foreground);
55
58
 
56
59
  z-index: 2;
57
60
  }
@@ -127,7 +127,14 @@ textarea,
127
127
  line-height: 1.4;
128
128
  text-transform: uppercase;
129
129
 
130
- color: var(--vita-subtle-foreground);
130
+ // 注释写的就是 muted,值却落在 subtle —— 那一档是「占位 / 禁用文字」,
131
+ // 浅色下 #a1a1aa 压白只有 2.6:1。这是分组导航的标题,是要被读的内容,
132
+ // 而且 11px 粗体在 WCAG 里仍按正文算(大字号要 18.66px 粗体起),得够 4.5:1。
133
+ // muted(#71717a) 约 4.8:1,字号与字重维持不变。
134
+ //
135
+ // 同一类错在 tokens.ts 的 colorTextTertiary 上刚修过一次:可读的归 muted,
136
+ // 只有占位/禁用留在 subtle。这里是被本文件的单类选择器盖掉的第二处。
137
+ color: var(--vita-muted-foreground);
131
138
  }
132
139
 
133
140
  // Items within a group use more restrained left-aligned indentation (closer to CF)
@@ -193,3 +200,22 @@ textarea,
193
200
  .ant-modal-mask {
194
201
  pointer-events: auto !important;
195
202
  }
203
+
204
+ // =============================================================
205
+ // Alert 圆角:补 antd 没注入的那个变量
206
+ //
207
+ // antd 的 Alert 样式写的是 `border-radius: var(--ant-alert-border-radius)`,但在
208
+ // CSS-var 模式下它**从不注入**这个变量 —— 实测该变量读出来是「未定义」,
209
+ // 于是圆角回退成 0,四角是直的。
210
+ //
211
+ // 走组件令牌修不了:`Alert: { borderRadiusLG }` 注入的是 `--ant-border-radius-lg`
212
+ // (Alert 一次都没引用),改成 `borderRadius` 也一样不生成该变量(两种都实测过)。
213
+ // 对照组是 Table —— 它的 `--ant-table-border-radius` 同样未定义,但圆角正常 8px,
214
+ // 因为 Table 的圆角来自本库自己的 scss,不依赖 antd 那条规则。
215
+ //
216
+ // 所以只能在样式层直接给。`.ant-alert-banner` 自带 `border-radius: 0`,
217
+ // 且选择器更具体,通栏提示条不受影响。
218
+ // =============================================================
219
+ .ant-alert {
220
+ border-radius: var(--vita-radius);
221
+ }
@@ -99,7 +99,16 @@ const toAntdTheme = options => {
99
99
  colorInfo: primary,
100
100
  colorText: t.foreground,
101
101
  colorTextSecondary: t.mutedForeground,
102
- colorTextTertiary: t.subtleForeground,
102
+ // antd 有四档文字色,本套令牌只有三档,压缩时分界线要放对:
103
+ // tertiary 在 antd 里是**描述性的可读文字**(面包屑、表单 extra、Descriptions 的
104
+ // 标签都吃它),quaternary 才是占位与禁用。原来两档都指向 subtleForeground,
105
+ // 于是面包屑拿到了占位级的对比度 —— 浅色下 #a1a1aa 压白只有 2.56:1,
106
+ // 14px 正文按 WCAG AA 要 4.5:1,连大字号的 3:1 都不到(消费方实测)。
107
+ //
108
+ // 压深 subtleForeground 治不了:要够 4.5:1 得到 #767676,那已经和
109
+ // mutedForeground(#71717a, 4.83:1) 几乎同色,第三档等于不存在。
110
+ // 所以按语义分流 —— 可读的归 muted,只有占位/禁用留在 subtle。
111
+ colorTextTertiary: t.mutedForeground,
103
112
  colorTextQuaternary: t.subtleForeground,
104
113
  colorBgContainer: t.surface,
105
114
  colorBgElevated: t.surface,
@@ -27,7 +27,7 @@
27
27
  "hover": "#f4f4f5",
28
28
  "success": "#16a34a",
29
29
  "warning": "#f59e0b",
30
- "error": "#ef4444",
30
+ "error": "#dc2626",
31
31
  "shadow1": "0 1px 2px 0 rgba(9, 9, 11, 0.05)",
32
32
  "shadow2": "0 4px 6px -1px rgba(9, 9, 11, 0.08), 0 2px 4px -2px rgba(9, 9, 11, 0.06)",
33
33
  "shadow3": "0 10px 15px -3px rgba(9, 9, 11, 0.1), 0 4px 6px -4px rgba(9, 9, 11, 0.08)"
@@ -33,7 +33,7 @@
33
33
  --vita-hover: #f4f4f5; // 行 / 项 hover 背景
34
34
  --vita-success: #16a34a;
35
35
  --vita-warning: #f59e0b;
36
- --vita-error: #ef4444;
36
+ --vita-error: #dc2626;
37
37
  --vita-shadow-1: 0 1px 2px 0 rgba(9, 9, 11, 0.05); // 浮层阴影 - 弱
38
38
  --vita-shadow-2: 0 4px 6px -1px rgba(9, 9, 11, 0.08), 0 2px 4px -2px rgba(9, 9, 11, 0.06); // 浮层阴影 - 中
39
39
  --vita-shadow-3: 0 10px 15px -3px rgba(9, 9, 11, 0.1), 0 4px 6px -4px rgba(9, 9, 11, 0.08); // 浮层阴影 - 强
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hsu-react/ui",
3
- "version": "2.4.7",
3
+ "version": "2.4.9",
4
4
  "description": "一套基于 React + Ant Design 的中后台业务组件库",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -8,7 +8,8 @@
8
8
 
9
9
  font-size: 14px;
10
10
  font-weight: bold;
11
- color: var(--vita-subtle-foreground);
11
+ // 分组标题(「今天」「近 7 天」),与侧栏菜单的分组标题同一件事
12
+ color: var(--vita-muted-foreground);
12
13
 
13
14
  cursor: default;
14
15
  }
@@ -67,6 +67,16 @@ export interface ChatInputProps {
67
67
  onFileInterceptClick?: (e: React.MouseEvent<HTMLSpanElement>) => void;
68
68
  buttonGroup?: ButtonProps[];
69
69
  uploadEnabled?: boolean;
70
+ /**
71
+ * Disable sending. The send button turns disabled and Enter no longer submits;
72
+ * the textarea stays editable so a half-typed message is never lost.
73
+ *
74
+ * The component already disables the send button during its own uploads
75
+ * (`isUpload`), but consumers that run their own upload flow
76
+ * (`uploadEnabled={false}`) had no way in: they could only intercept `onSend`
77
+ * and pop a warning, leaving the button looking perfectly clickable.
78
+ */
79
+ disabled?: boolean;
70
80
  }
71
81
 
72
82
  const ChatInput: React.FC<ChatInputProps> = (props) => {
@@ -88,6 +98,7 @@ const ChatInput: React.FC<ChatInputProps> = (props) => {
88
98
  onFileInterceptClick,
89
99
  buttonGroup,
90
100
  uploadEnabled = true,
101
+ disabled = false,
91
102
  } = props;
92
103
 
93
104
  const [value, setValue] = useState<string>("");
@@ -178,6 +189,9 @@ const ChatInput: React.FC<ChatInputProps> = (props) => {
178
189
 
179
190
  // Handle sending
180
191
  const handleSend = () => {
192
+ if (disabled) {
193
+ return;
194
+ }
181
195
  if (value.trim() !== "") {
182
196
  setValue("");
183
197
  onSend?.(value);
@@ -275,7 +289,7 @@ const ChatInput: React.FC<ChatInputProps> = (props) => {
275
289
  value={value}
276
290
  onSend={handleSend}
277
291
  sendIcon={sendIcon}
278
- disabled={isUpload}
292
+ disabled={isUpload || disabled}
279
293
  />
280
294
  )}
281
295
  </>
@@ -108,7 +108,8 @@
108
108
  transition: background-color 0.3s, color 0.3s;
109
109
 
110
110
  &:hover {
111
- color: #fff;
111
+ // 同 TabBar:主色实底上的前景色走配对令牌
112
+ color: var(--vita-primary-foreground);
112
113
 
113
114
  background-color: var(--vita-primary);
114
115
  }
@@ -95,7 +95,8 @@
95
95
  border-color: var(--vita-primary, #1890ff);
96
96
 
97
97
  > a {
98
- color: #ffffff;
98
+ // 同 TabBar:主色实底上的前景色走配对令牌
99
+ color: var(--vita-primary-foreground);
99
100
  }
100
101
  }
101
102
 
@@ -10,7 +10,8 @@
10
10
  font-size: 12px;
11
11
  font-weight: normal;
12
12
 
13
- color: var(--vita-subtle-foreground);
13
+ // 说明文字,不是占位符
14
+ color: var(--vita-muted-foreground);
14
15
  }
15
16
  }
16
17
 
@@ -29,7 +29,9 @@
29
29
 
30
30
  .text {
31
31
  font-size: 16px;
32
- color: var(--vita-subtle-foreground);
32
+ // 二次确认的正文,是这个弹窗里唯一要读的内容,不能用占位档。
33
+ // 与上面 .title 的层级差已经由 20px/bold 对 16px/normal 拉开了
34
+ color: var(--vita-muted-foreground);
33
35
  }
34
36
  }
35
37
  }
@@ -51,7 +51,10 @@
51
51
  &.active {
52
52
  background: var(--vita-primary);
53
53
 
54
- color: #fff;
54
+ // 压在主色实底上的前景色走配对令牌,不要写死白:--vita-primary 是可配置的,
55
+ // 消费方把它换成近白的中性色时(shadcn 那种 primary/primary-foreground 配法),
56
+ // 写死的白就是白压白。默认值仍是 #ffffff,彩色品牌色的消费方不受影响
57
+ color: var(--vita-primary-foreground);
55
58
 
56
59
  z-index: 2;
57
60
  }
@@ -127,7 +127,14 @@ textarea,
127
127
  line-height: 1.4;
128
128
  text-transform: uppercase;
129
129
 
130
- color: var(--vita-subtle-foreground);
130
+ // 注释写的就是 muted,值却落在 subtle —— 那一档是「占位 / 禁用文字」,
131
+ // 浅色下 #a1a1aa 压白只有 2.6:1。这是分组导航的标题,是要被读的内容,
132
+ // 而且 11px 粗体在 WCAG 里仍按正文算(大字号要 18.66px 粗体起),得够 4.5:1。
133
+ // muted(#71717a) 约 4.8:1,字号与字重维持不变。
134
+ //
135
+ // 同一类错在 tokens.ts 的 colorTextTertiary 上刚修过一次:可读的归 muted,
136
+ // 只有占位/禁用留在 subtle。这里是被本文件的单类选择器盖掉的第二处。
137
+ color: var(--vita-muted-foreground);
131
138
  }
132
139
 
133
140
  // Items within a group use more restrained left-aligned indentation (closer to CF)
@@ -193,3 +200,22 @@ textarea,
193
200
  .ant-modal-mask {
194
201
  pointer-events: auto !important;
195
202
  }
203
+
204
+ // =============================================================
205
+ // Alert 圆角:补 antd 没注入的那个变量
206
+ //
207
+ // antd 的 Alert 样式写的是 `border-radius: var(--ant-alert-border-radius)`,但在
208
+ // CSS-var 模式下它**从不注入**这个变量 —— 实测该变量读出来是「未定义」,
209
+ // 于是圆角回退成 0,四角是直的。
210
+ //
211
+ // 走组件令牌修不了:`Alert: { borderRadiusLG }` 注入的是 `--ant-border-radius-lg`
212
+ // (Alert 一次都没引用),改成 `borderRadius` 也一样不生成该变量(两种都实测过)。
213
+ // 对照组是 Table —— 它的 `--ant-table-border-radius` 同样未定义,但圆角正常 8px,
214
+ // 因为 Table 的圆角来自本库自己的 scss,不依赖 antd 那条规则。
215
+ //
216
+ // 所以只能在样式层直接给。`.ant-alert-banner` 自带 `border-radius: 0`,
217
+ // 且选择器更具体,通栏提示条不受影响。
218
+ // =============================================================
219
+ .ant-alert {
220
+ border-radius: var(--vita-radius);
221
+ }
@@ -27,7 +27,7 @@
27
27
  "hover": "#f4f4f5",
28
28
  "success": "#16a34a",
29
29
  "warning": "#f59e0b",
30
- "error": "#ef4444",
30
+ "error": "#dc2626",
31
31
  "shadow1": "0 1px 2px 0 rgba(9, 9, 11, 0.05)",
32
32
  "shadow2": "0 4px 6px -1px rgba(9, 9, 11, 0.08), 0 2px 4px -2px rgba(9, 9, 11, 0.06)",
33
33
  "shadow3": "0 10px 15px -3px rgba(9, 9, 11, 0.1), 0 4px 6px -4px rgba(9, 9, 11, 0.08)"
@@ -33,7 +33,7 @@
33
33
  --vita-hover: #f4f4f5; // 行 / 项 hover 背景
34
34
  --vita-success: #16a34a;
35
35
  --vita-warning: #f59e0b;
36
- --vita-error: #ef4444;
36
+ --vita-error: #dc2626;
37
37
  --vita-shadow-1: 0 1px 2px 0 rgba(9, 9, 11, 0.05); // 浮层阴影 - 弱
38
38
  --vita-shadow-2: 0 4px 6px -1px rgba(9, 9, 11, 0.08), 0 2px 4px -2px rgba(9, 9, 11, 0.06); // 浮层阴影 - 中
39
39
  --vita-shadow-3: 0 10px 15px -3px rgba(9, 9, 11, 0.1), 0 4px 6px -4px rgba(9, 9, 11, 0.08); // 浮层阴影 - 强
@@ -145,7 +145,16 @@ export const toAntdTheme = (options?: {
145
145
 
146
146
  colorText: t.foreground,
147
147
  colorTextSecondary: t.mutedForeground,
148
- colorTextTertiary: t.subtleForeground,
148
+ // antd 有四档文字色,本套令牌只有三档,压缩时分界线要放对:
149
+ // tertiary 在 antd 里是**描述性的可读文字**(面包屑、表单 extra、Descriptions 的
150
+ // 标签都吃它),quaternary 才是占位与禁用。原来两档都指向 subtleForeground,
151
+ // 于是面包屑拿到了占位级的对比度 —— 浅色下 #a1a1aa 压白只有 2.56:1,
152
+ // 14px 正文按 WCAG AA 要 4.5:1,连大字号的 3:1 都不到(消费方实测)。
153
+ //
154
+ // 压深 subtleForeground 治不了:要够 4.5:1 得到 #767676,那已经和
155
+ // mutedForeground(#71717a, 4.83:1) 几乎同色,第三档等于不存在。
156
+ // 所以按语义分流 —— 可读的归 muted,只有占位/禁用留在 subtle。
157
+ colorTextTertiary: t.mutedForeground,
149
158
  colorTextQuaternary: t.subtleForeground,
150
159
 
151
160
  colorBgContainer: t.surface,