one-design-next 0.0.43 → 0.0.44

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.
@@ -215,7 +215,9 @@ export interface Conversation {
215
215
  title: string;
216
216
  preview?: string;
217
217
  timestamp?: number;
218
- status?: 'generating' | 'unread' | 'error';
218
+ /** 对话类型。`'human'` 为人工客服会话;默认视为 AI。 */
219
+ type?: 'ai' | 'human';
220
+ status?: 'generating' | 'waiting' | 'unread' | 'error';
219
221
  }
220
222
  export interface MessageSnapshot {
221
223
  content: string;
@@ -1,10 +1,13 @@
1
1
  /// <reference types="react" />
2
2
  import './style';
3
- type StatusIndicator = 'generating' | 'unread' | 'error';
3
+ type StatusIndicator = 'generating' | 'waiting' | 'unread' | 'error';
4
+ type ConversationType = 'ai' | 'human';
4
5
  export interface ChatItemProps {
5
6
  id: string;
6
7
  title: string;
7
8
  active?: boolean;
9
+ /** 对话类型。`'human'` 时标题后展示客服 icon;默认 `'ai'`。 */
10
+ type?: ConversationType;
8
11
  status?: StatusIndicator;
9
12
  onClick?: (id: string) => void;
10
13
  onRename?: (id: string, newTitle: string) => void;
@@ -20,7 +23,7 @@ export interface ChatItemProps {
20
23
  defaultDeleteOpen?: boolean;
21
24
  onDeleteOpenChange?: (open: boolean) => void;
22
25
  }
23
- export declare function ChatItem({ id, title, active, status, onClick, onRename, onDelete, actionMenuZIndex, renaming: renamingProp, defaultRenaming, onRenamingChange, menuOpen: menuOpenProp, defaultMenuOpen, onMenuOpenChange, deleteOpen: deleteOpenProp, defaultDeleteOpen, onDeleteOpenChange, }: ChatItemProps): import("react").JSX.Element;
26
+ export declare function ChatItem({ id, title, active, type, status, onClick, onRename, onDelete, actionMenuZIndex, renaming: renamingProp, defaultRenaming, onRenamingChange, menuOpen: menuOpenProp, defaultMenuOpen, onMenuOpenChange, deleteOpen: deleteOpenProp, defaultDeleteOpen, onDeleteOpenChange, }: ChatItemProps): import("react").JSX.Element;
24
27
  export declare namespace ChatItem {
25
28
  var displayName: string;
26
29
  }
@@ -8,7 +8,7 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
8
8
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
9
9
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
10
10
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
11
- import { useState, useRef, useEffect, useId } from 'react';
11
+ import { useState, useRef, useEffect, useLayoutEffect } from 'react';
12
12
  import HoverFill from "../hover-fill";
13
13
  import Icon from "../icon";
14
14
  import Dialog from "../dialog";
@@ -16,54 +16,99 @@ import Dropdown from "../dropdown";
16
16
  import "./style";
17
17
  var STATUS_ARIA_LABEL = {
18
18
  generating: '生成中',
19
+ waiting: '等待处理',
19
20
  unread: '未读更新',
20
21
  error: '生成出错'
21
22
  };
22
- function ChatItemGeneratingJelly(_ref) {
23
- var _ref$size = _ref.size,
24
- size = _ref$size === void 0 ? 14 : _ref$size,
25
- _ref$speed = _ref.speed,
26
- speed = _ref$speed === void 0 ? 1.75 : _ref$speed;
27
- var rawId = useId();
28
- var filterId = "odn-chat-item-jelly-ooze-".concat(rawId.replace(/:/g, ''));
29
- var style = {
30
- '--uib-size': "".concat(size, "px"),
31
- '--uib-color': 'currentColor',
32
- '--uib-speed': "".concat(speed, "s"),
33
- filter: "url('#".concat(filterId, "')")
34
- };
35
- return /*#__PURE__*/React.createElement("span", {
36
- "data-odn-chat-item-jelly": true,
37
- style: style,
38
- "aria-hidden": "true"
39
- }, /*#__PURE__*/React.createElement("span", {
40
- "data-odn-chat-item-jelly-dot": true
41
- }), /*#__PURE__*/React.createElement("span", {
42
- "data-odn-chat-item-jelly-traveler": true
43
- }), /*#__PURE__*/React.createElement("svg", {
44
- width: "0",
45
- height: "0",
46
- style: {
47
- position: 'absolute'
23
+ var ELLIPSIS = '…';
24
+
25
+ /**
26
+ * 有 trailing(客服 icon / status)时,用 DOM 实测把标题裁到可用宽度。
27
+ * 解决 CSS text-overflow 按字符边界截断后,省略号右侧留白把 status 顶开的问题。
28
+ * 量准时:截断标题宽 ≈ label − trailing − gap,整组仍铺满行,trailing 贴右缘。
29
+ */
30
+ function useFittedTitle(title, enabled, labelRef, titleRef, trailingRef) {
31
+ var _useState = useState(title),
32
+ _useState2 = _slicedToArray(_useState, 2),
33
+ fitted = _useState2[0],
34
+ setFitted = _useState2[1];
35
+ useLayoutEffect(function () {
36
+ var _document$fonts;
37
+ if (!enabled) {
38
+ setFitted(title);
39
+ return;
48
40
  }
49
- }, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("filter", {
50
- id: filterId
51
- }, /*#__PURE__*/React.createElement("feGaussianBlur", {
52
- in: "SourceGraphic",
53
- stdDeviation: size / 9,
54
- result: "blur"
55
- }), /*#__PURE__*/React.createElement("feColorMatrix", {
56
- in: "blur",
57
- mode: "matrix",
58
- values: "1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7",
59
- result: "ooze"
60
- }), /*#__PURE__*/React.createElement("feBlend", {
61
- in: "SourceGraphic",
62
- in2: "ooze"
63
- })))));
41
+ var label = labelRef.current;
42
+ var titleEl = titleRef.current;
43
+ if (!label || !titleEl) return;
44
+ var cancelled = false;
45
+ var probe = document.createElement('span');
46
+ probe.setAttribute('aria-hidden', 'true');
47
+ probe.style.cssText = 'position:absolute;visibility:hidden;pointer-events:none;white-space:nowrap;left:-9999px;top:0;';
48
+ var syncProbeFont = function syncProbeFont() {
49
+ var cs = getComputedStyle(titleEl);
50
+ probe.style.fontFamily = cs.fontFamily;
51
+ probe.style.fontSize = cs.fontSize;
52
+ probe.style.fontWeight = cs.fontWeight;
53
+ probe.style.fontStyle = cs.fontStyle;
54
+ probe.style.letterSpacing = cs.letterSpacing;
55
+ probe.style.fontFeatureSettings = cs.fontFeatureSettings;
56
+ probe.style.fontVariationSettings = cs.fontVariationSettings;
57
+ };
58
+ var measure = function measure(text) {
59
+ probe.textContent = text;
60
+ return probe.getBoundingClientRect().width;
61
+ };
62
+ var fit = function fit() {
63
+ var _trailing$getBounding;
64
+ if (cancelled) return;
65
+ syncProbeFont();
66
+ if (!probe.isConnected) document.body.appendChild(probe);
67
+ var trailing = trailingRef.current;
68
+ var gap = trailing ? Number.parseFloat(getComputedStyle(label).columnGap || getComputedStyle(label).gap) || 0 : 0;
69
+ var trailingWidth = (_trailing$getBounding = trailing === null || trailing === void 0 ? void 0 : trailing.getBoundingClientRect().width) !== null && _trailing$getBounding !== void 0 ? _trailing$getBounding : 0;
70
+ // 用浮点宽度,避免 offsetWidth 取整导致少算 1px、过早截断
71
+ var maxWidth = Math.max(0, label.getBoundingClientRect().width - trailingWidth - gap);
72
+ if (measure(title) <= maxWidth + 0.5) {
73
+ setFitted(title);
74
+ return;
75
+ }
76
+ var lo = 0;
77
+ var hi = title.length;
78
+ var best = ELLIPSIS;
79
+ while (lo <= hi) {
80
+ var mid = lo + hi >> 1;
81
+ var candidate = "".concat(title.slice(0, mid)).concat(ELLIPSIS);
82
+ if (measure(candidate) <= maxWidth + 0.5) {
83
+ best = candidate;
84
+ lo = mid + 1;
85
+ } else {
86
+ hi = mid - 1;
87
+ }
88
+ }
89
+ setFitted(best);
90
+ };
91
+ fit();
92
+ void ((_document$fonts = document.fonts) === null || _document$fonts === void 0 ? void 0 : _document$fonts.ready.then(function () {
93
+ if (!cancelled) fit();
94
+ }));
95
+ var ro = new ResizeObserver(fit);
96
+ ro.observe(label);
97
+ var trailing = trailingRef.current;
98
+ if (trailing) ro.observe(trailing);
99
+ // hover 时 btn padding-right 变化会改变 label 宽度
100
+ var btn = label.closest('[data-odn-chat-item-btn]');
101
+ if (btn) ro.observe(btn);
102
+ return function () {
103
+ cancelled = true;
104
+ ro.disconnect();
105
+ probe.remove();
106
+ };
107
+ }, [title, enabled, labelRef, titleRef, trailingRef]);
108
+ return enabled ? fitted : title;
64
109
  }
65
- function ChatItemStatus(_ref2) {
66
- var status = _ref2.status;
110
+ function ChatItemStatus(_ref) {
111
+ var status = _ref.status;
67
112
  var label = STATUS_ARIA_LABEL[status];
68
113
  if (status === 'generating') {
69
114
  return /*#__PURE__*/React.createElement("span", {
@@ -71,7 +116,19 @@ function ChatItemStatus(_ref2) {
71
116
  "data-odn-chat-item-status-generating": true,
72
117
  "aria-label": label,
73
118
  role: "status"
74
- }, /*#__PURE__*/React.createElement(ChatItemGeneratingJelly, null));
119
+ }, /*#__PURE__*/React.createElement(Icon, {
120
+ name: "loading",
121
+ spin: true,
122
+ size: 12
123
+ }));
124
+ }
125
+ if (status === 'waiting') {
126
+ return /*#__PURE__*/React.createElement("span", {
127
+ "data-odn-chat-item-status": true,
128
+ "data-odn-chat-item-status-waiting": true,
129
+ "aria-label": label,
130
+ role: "status"
131
+ }, "\u5F85\u56DE\u590D");
75
132
  }
76
133
  if (status === 'error') {
77
134
  return /*#__PURE__*/React.createElement("span", {
@@ -94,10 +151,10 @@ function ChatItemStatus(_ref2) {
94
151
  }));
95
152
  }
96
153
  function useControllableState(controlled, defaultValue, onChange) {
97
- var _useState = useState(defaultValue),
98
- _useState2 = _slicedToArray(_useState, 2),
99
- internal = _useState2[0],
100
- setInternal = _useState2[1];
154
+ var _useState3 = useState(defaultValue),
155
+ _useState4 = _slicedToArray(_useState3, 2),
156
+ internal = _useState4[0],
157
+ setInternal = _useState4[1];
101
158
  var value = controlled !== null && controlled !== void 0 ? controlled : internal;
102
159
  var setValue = function setValue(next) {
103
160
  onChange === null || onChange === void 0 || onChange(next);
@@ -105,35 +162,37 @@ function useControllableState(controlled, defaultValue, onChange) {
105
162
  };
106
163
  return [value, setValue];
107
164
  }
108
- export function ChatItem(_ref3) {
109
- var id = _ref3.id,
110
- title = _ref3.title,
111
- active = _ref3.active,
112
- status = _ref3.status,
113
- _onClick = _ref3.onClick,
114
- onRename = _ref3.onRename,
115
- onDelete = _ref3.onDelete,
116
- actionMenuZIndex = _ref3.actionMenuZIndex,
117
- renamingProp = _ref3.renaming,
118
- _ref3$defaultRenaming = _ref3.defaultRenaming,
119
- defaultRenaming = _ref3$defaultRenaming === void 0 ? false : _ref3$defaultRenaming,
120
- onRenamingChange = _ref3.onRenamingChange,
121
- menuOpenProp = _ref3.menuOpen,
122
- _ref3$defaultMenuOpen = _ref3.defaultMenuOpen,
123
- defaultMenuOpen = _ref3$defaultMenuOpen === void 0 ? false : _ref3$defaultMenuOpen,
124
- onMenuOpenChange = _ref3.onMenuOpenChange,
125
- deleteOpenProp = _ref3.deleteOpen,
126
- _ref3$defaultDeleteOp = _ref3.defaultDeleteOpen,
127
- defaultDeleteOpen = _ref3$defaultDeleteOp === void 0 ? false : _ref3$defaultDeleteOp,
128
- onDeleteOpenChange = _ref3.onDeleteOpenChange;
165
+ export function ChatItem(_ref2) {
166
+ var id = _ref2.id,
167
+ title = _ref2.title,
168
+ active = _ref2.active,
169
+ _ref2$type = _ref2.type,
170
+ type = _ref2$type === void 0 ? 'ai' : _ref2$type,
171
+ status = _ref2.status,
172
+ _onClick = _ref2.onClick,
173
+ onRename = _ref2.onRename,
174
+ onDelete = _ref2.onDelete,
175
+ actionMenuZIndex = _ref2.actionMenuZIndex,
176
+ renamingProp = _ref2.renaming,
177
+ _ref2$defaultRenaming = _ref2.defaultRenaming,
178
+ defaultRenaming = _ref2$defaultRenaming === void 0 ? false : _ref2$defaultRenaming,
179
+ onRenamingChange = _ref2.onRenamingChange,
180
+ menuOpenProp = _ref2.menuOpen,
181
+ _ref2$defaultMenuOpen = _ref2.defaultMenuOpen,
182
+ defaultMenuOpen = _ref2$defaultMenuOpen === void 0 ? false : _ref2$defaultMenuOpen,
183
+ onMenuOpenChange = _ref2.onMenuOpenChange,
184
+ deleteOpenProp = _ref2.deleteOpen,
185
+ _ref2$defaultDeleteOp = _ref2.defaultDeleteOpen,
186
+ defaultDeleteOpen = _ref2$defaultDeleteOp === void 0 ? false : _ref2$defaultDeleteOp,
187
+ onDeleteOpenChange = _ref2.onDeleteOpenChange;
129
188
  var _useControllableState = useControllableState(renamingProp, defaultRenaming, onRenamingChange),
130
189
  _useControllableState2 = _slicedToArray(_useControllableState, 2),
131
190
  renaming = _useControllableState2[0],
132
191
  setRenaming = _useControllableState2[1];
133
- var _useState3 = useState(title),
134
- _useState4 = _slicedToArray(_useState3, 2),
135
- draft = _useState4[0],
136
- setDraft = _useState4[1];
192
+ var _useState5 = useState(title),
193
+ _useState6 = _slicedToArray(_useState5, 2),
194
+ draft = _useState6[0],
195
+ setDraft = _useState6[1];
137
196
  var _useControllableState3 = useControllableState(deleteOpenProp, defaultDeleteOpen, onDeleteOpenChange),
138
197
  _useControllableState4 = _slicedToArray(_useControllableState3, 2),
139
198
  deleteOpen = _useControllableState4[0],
@@ -143,6 +202,13 @@ export function ChatItem(_ref3) {
143
202
  menuOpen = _useControllableState6[0],
144
203
  setMenuOpen = _useControllableState6[1];
145
204
  var inputRef = useRef(null);
205
+ var labelRef = useRef(null);
206
+ var titleRef = useRef(null);
207
+ var trailingRef = useRef(null);
208
+ var showStatus = Boolean(status && !active);
209
+ var showTypeIcon = type === 'human';
210
+ var fitTitle = showTypeIcon || showStatus;
211
+ var displayTitle = useFittedTitle(title, fitTitle, labelRef, titleRef, trailingRef);
146
212
  useEffect(function () {
147
213
  if (!renaming) setDraft(title);
148
214
  }, [title, renaming]);
@@ -203,13 +269,27 @@ export function ChatItem(_ref3) {
203
269
  "data-odn-chat-item-btn": true,
204
270
  "data-odn-chat-item-active": active || undefined
205
271
  }, /*#__PURE__*/React.createElement("span", {
206
- "data-odn-chat-item-label": true
272
+ "data-odn-chat-item-label": true,
273
+ ref: labelRef
207
274
  }, /*#__PURE__*/React.createElement("span", {
275
+ ref: titleRef,
208
276
  "data-odn-chat-item-title": true,
209
- "data-odn-chat-item-title-bold": active ? '' : undefined
210
- }, title), status && !active && /*#__PURE__*/React.createElement(ChatItemStatus, {
277
+ "data-odn-chat-item-title-bold": active ? '' : undefined,
278
+ "data-odn-chat-item-title-fitted": fitTitle ? '' : undefined,
279
+ title: title
280
+ }, displayTitle), (showTypeIcon || showStatus) && /*#__PURE__*/React.createElement("span", {
281
+ "data-odn-chat-item-trailing": true,
282
+ ref: trailingRef
283
+ }, showTypeIcon && /*#__PURE__*/React.createElement("span", {
284
+ "data-odn-chat-item-type-icon": true,
285
+ "aria-label": "\u4EBA\u5DE5\u5BA2\u670D\u4F1A\u8BDD",
286
+ role: "img"
287
+ }, /*#__PURE__*/React.createElement(Icon, {
288
+ name: "support-bold",
289
+ size: 12
290
+ })), showStatus && status && /*#__PURE__*/React.createElement(ChatItemStatus, {
211
291
  status: status
212
- }))), /*#__PURE__*/React.createElement(Dropdown, {
292
+ })))), /*#__PURE__*/React.createElement(Dropdown, {
213
293
  trigger: "click",
214
294
  placement: "bottomRight",
215
295
  zIndex: actionMenuZIndex,
@@ -98,12 +98,15 @@
98
98
  [data-odn-chat-item-label] {
99
99
  display: flex;
100
100
  align-items: center;
101
- gap: 6px;
101
+ gap: 4px;
102
+ flex: 1 1 auto;
102
103
  min-width: 0;
104
+ max-width: 100%;
103
105
  }
104
106
 
105
107
  [data-odn-chat-item-title] {
106
- flex: 1 1 auto;
108
+ /* 0 1 auto:短标题不撑开(icon 贴字);长标题可收缩省略,trailing 被顶到右缘 */
109
+ flex: 0 1 auto;
107
110
  min-width: 0;
108
111
  font-size: 14px;
109
112
  overflow: hidden;
@@ -111,10 +114,34 @@
111
114
  white-space: nowrap;
112
115
  }
113
116
 
117
+ /* JS 已裁到可用宽度:按内容收缩,省略号后无字符边界留白;量准时整组仍铺满行 */
118
+ [data-odn-chat-item-title-fitted] {
119
+ flex: 0 0 auto;
120
+ overflow: visible;
121
+ text-overflow: clip;
122
+ }
123
+
114
124
  [data-odn-chat-item-title-bold] {
115
125
  font-weight: 500;
116
126
  }
117
127
 
128
+ [data-odn-chat-item-trailing] {
129
+ flex-shrink: 0;
130
+ display: inline-flex;
131
+ align-items: center;
132
+ gap: 6px;
133
+ }
134
+
135
+ [data-odn-chat-item-type-icon] {
136
+ flex-shrink: 0;
137
+ display: flex;
138
+ align-items: center;
139
+ justify-content: center;
140
+ width: 12px;
141
+ height: 12px;
142
+ color: var(--odn-color-black-8);
143
+ }
144
+
118
145
  [data-odn-chat-item-status] {
119
146
  flex-shrink: 0;
120
147
  width: 14px;
@@ -135,6 +162,19 @@
135
162
  color: var(--odn-color-black-8);
136
163
  }
137
164
 
165
+ [data-odn-chat-item-status-waiting] {
166
+ width: auto;
167
+ height: 16px;
168
+ color: #fff;
169
+ font-size: 11px;
170
+ font-weight: 600;
171
+ line-height: 16px;
172
+ white-space: nowrap;
173
+ background: var(--odn-color-orange-6);
174
+ padding: 0 3px;
175
+ border-radius: 4px;
176
+ }
177
+
138
178
  [data-odn-chat-item-status-error] {
139
179
  color: var(--odn-color-error);
140
180
  }
@@ -190,73 +230,6 @@
190
230
  color: var(--odn-color-black-12);
191
231
  }
192
232
 
193
- /* ChatItem 的 Dropdown 面板:宽度根据内容自适应(hug),不使用默认 128px */
194
- [data-odn-chat-item-jelly] {
195
- position: relative;
196
- display: inline-flex;
197
- align-items: center;
198
- justify-content: center;
199
- flex-shrink: 0;
200
- width: var(--uib-size);
201
- height: var(--uib-size);
202
- }
203
- [data-odn-chat-item-jelly]::before, [data-odn-chat-item-jelly]::after,
204
- [data-odn-chat-item-jelly] [data-odn-chat-item-jelly-dot] {
205
- content: "";
206
- position: absolute;
207
- width: 33%;
208
- height: 33%;
209
- background-color: var(--uib-color);
210
- border-radius: 100%;
211
- will-change: transform;
212
- }
213
- [data-odn-chat-item-jelly]::before {
214
- right: 0;
215
- bottom: 6%;
216
- animation: odn-chat-item-jelly-grow var(--uib-speed) ease calc(var(--uib-speed) * -0.666) infinite;
217
- }
218
- [data-odn-chat-item-jelly]::after {
219
- left: 0;
220
- bottom: 6%;
221
- animation: odn-chat-item-jelly-grow var(--uib-speed) ease calc(var(--uib-speed) * -0.333) infinite;
222
- }
223
-
224
- [data-odn-chat-item-jelly-dot] {
225
- top: 6%;
226
- left: 30%;
227
- animation: odn-chat-item-jelly-grow var(--uib-speed) ease infinite;
228
- }
229
-
230
- [data-odn-chat-item-jelly-traveler] {
231
- position: absolute;
232
- top: 6%;
233
- left: 30%;
234
- width: 33%;
235
- height: 33%;
236
- background-color: var(--uib-color);
237
- border-radius: 100%;
238
- animation: odn-chat-item-jelly-triangulate var(--uib-speed) ease infinite;
239
- }
240
-
241
- @keyframes odn-chat-item-jelly-grow {
242
- 0%, 85%, 100% {
243
- transform: scale(1.5);
244
- }
245
- 50%, 60% {
246
- transform: scale(0);
247
- }
248
- }
249
- @keyframes odn-chat-item-jelly-triangulate {
250
- 0%, 100% {
251
- transform: none;
252
- }
253
- 33.333% {
254
- transform: translate(120%, 175%);
255
- }
256
- 66.666% {
257
- transform: translate(-95%, 175%);
258
- }
259
- }
260
233
  [data-odn-dropdown-content].odn-chat-item-action-menu {
261
234
  min-width: 0;
262
235
  width: max-content;
@@ -12,6 +12,7 @@ export interface FabProps {
12
12
  hoverBgOpacity?: number;
13
13
  speed?: number;
14
14
  hoverSpeed?: number;
15
+ badge?: boolean;
15
16
  }
16
17
  declare const Fab: React.ForwardRefExoticComponent<FabProps & React.RefAttributes<HTMLButtonElement>>;
17
18
  export default Fab;
package/dist/fab/index.js CHANGED
@@ -61,7 +61,8 @@ var Fab = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
61
61
  _ref3$speed = _ref3.speed,
62
62
  speed = _ref3$speed === void 0 ? 1.49 : _ref3$speed,
63
63
  _ref3$hoverSpeed = _ref3.hoverSpeed,
64
- hoverSpeed = _ref3$hoverSpeed === void 0 ? 2.77 : _ref3$hoverSpeed;
64
+ hoverSpeed = _ref3$hoverSpeed === void 0 ? 2.77 : _ref3$hoverSpeed,
65
+ badge = _ref3.badge;
65
66
  var _useState = useState(false),
66
67
  _useState2 = _slicedToArray(_useState, 2),
67
68
  hovered = _useState2[0],
@@ -132,6 +133,7 @@ var Fab = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
132
133
  position: 'absolute',
133
134
  inset: 0,
134
135
  borderRadius: 'inherit',
136
+ overflow: 'hidden',
135
137
  width: '100%',
136
138
  height: '100%',
137
139
  opacity: live.opacity
@@ -139,6 +141,9 @@ var Fab = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
139
141
  }), /*#__PURE__*/React.createElement("div", {
140
142
  className: "odn-fab-glow",
141
143
  "aria-hidden": "true"
144
+ }), badge && /*#__PURE__*/React.createElement("span", {
145
+ "data-odn-fab-badge": true,
146
+ "aria-label": "\u6709\u5F85\u5904\u7406\u4F1A\u8BDD"
142
147
  }), icon, /*#__PURE__*/React.createElement("span", {
143
148
  className: "odn-fab-label"
144
149
  }, label));
@@ -1,6 +1,6 @@
1
1
  [data-odn-fab] {
2
2
  position: relative;
3
- overflow: hidden;
3
+ overflow: visible;
4
4
  display: flex;
5
5
  align-items: center;
6
6
  justify-content: center;
@@ -46,6 +46,19 @@
46
46
  filter: blur(var(--fab-glow-hover-blur, 76px));
47
47
  }
48
48
 
49
+ [data-odn-fab-badge] {
50
+ position: absolute;
51
+ top: -4px;
52
+ left: -4px;
53
+ z-index: 20;
54
+ width: 16px;
55
+ height: 16px;
56
+ border-radius: 50%;
57
+ background: var(--odn-color-orange-6);
58
+ box-shadow: 0 0 0 2px #fff;
59
+ pointer-events: none;
60
+ }
61
+
49
62
  .odn-fab-icon {
50
63
  position: relative;
51
64
  z-index: 10;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "one-design-next",
3
- "version": "0.0.43",
3
+ "version": "0.0.44",
4
4
  "description": "One Design Next from TAD@tencent.com",
5
5
  "packageManager": "pnpm@11.8.0",
6
6
  "module": "dist/index.js",