one-design-next 0.0.115 → 0.0.116

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.
@@ -29,7 +29,7 @@ import { useChipManager } from "./hooks/useChipManager";
29
29
  import { useChipSelectionMarker } from "./hooks/useChipSelectionMarker";
30
30
  import { chipHasEditableParams, ComposerInlineRef } from "./inline-ref";
31
31
  import { resolveHintTarget } from "./segments";
32
- import { COMPOSER_HINT_ATTR, createLineRoot, createLineRootWithText, ensureCaretAnchorAfter, ensureLineRoots, getPlainText, isEditorEmpty, isLineRoot, LINE_ATTR_NAME, normalizeEditorDom, probeTrigger, stripInvisibleChars, ZWSP } from "./utils";
32
+ import { COMPOSER_HINT_ACCEPT_ATTR, COMPOSER_HINT_ACCEPT_SELECTOR, COMPOSER_HINT_ATTR, createLineRoot, createLineRootWithText, ensureCaretAnchorAfter, ensureLineRoots, getPlainText, isEditorEmpty, isLineRoot, LINE_ATTR_NAME, normalizeEditorDom, probeTrigger, stripInvisibleChars, ZWSP } from "./utils";
33
33
 
34
34
  /** Composer editor 触发态对外信号——告诉父组件该弹浮层选 skill 了。 */
35
35
 
@@ -98,6 +98,34 @@ var findDirectHint = function findDirectHint(line) {
98
98
  return null;
99
99
  };
100
100
 
101
+ /**
102
+ * hint 末尾的「TAB 采纳」小块:点它 = 按 Tab 采纳这段模板文案。
103
+ *
104
+ * 与 hint 文本是同级节点(见 `COMPOSER_HINT_ACCEPT_ATTR` 的说明),由
105
+ * `syncHintNode` 一起插入 / 移除,不进 value / 剪贴板 / segments。
106
+ * 视觉在 `style/index.scss`(`[data-odn-composer-hint-accept]`)。
107
+ */
108
+ var createHintAcceptNode = function createHintAcceptNode() {
109
+ var accept = document.createElement('span');
110
+ accept.setAttribute(COMPOSER_HINT_ACCEPT_ATTR, '');
111
+ accept.contentEditable = 'false';
112
+ /* 刻意不加 role="button" / aria-label / title:
113
+ * - 它不可聚焦、也没有 Enter/Space 激活逻辑,挂 button 语义等于给读屏用户
114
+ * 一个按不动的控件(无障碍反而变成障碍)。真正的键盘路径就是它写着的
115
+ * Tab 键本身,可见文案已经说清动作。
116
+ * - aria-label 会盖掉可见文案,反而违反「可见标签即无障碍名」。
117
+ * - title 是浏览器原生 tooltip:延迟出现、样式不可控、会盖住灰字。 */
118
+
119
+ var key = document.createElement('span');
120
+ key.setAttribute('data-odn-composer-hint-accept-key', '');
121
+ key.textContent = 'TAB';
122
+ var label = document.createElement('span');
123
+ label.setAttribute('data-odn-composer-hint-accept-label', '');
124
+ label.textContent = '采纳';
125
+ accept.append(key, label);
126
+ return accept;
127
+ };
128
+
101
129
  /**
102
130
  * insertContent 的插入点:最后一个行容器的内容末尾。
103
131
  *
@@ -359,12 +387,18 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
359
387
  * 就不存在了,caret 只能落在整个 host 之后(= 提示文本末尾)。
360
388
  *
361
389
  * 它不归 React 管(editor 的 children 由 contenteditable 自治),由 fireChange
362
- * 按结构谓词增删/挪位;`getPlainText` 会整棵子树跳过,所以不进 value / 剪贴板。 */
390
+ * 按结构谓词增删/挪位;`getPlainText` 会整棵子树跳过,所以不进 value / 剪贴板。
391
+ *
392
+ * 末尾的「TAB 采纳」小块是 hint 文本的**兄弟节点**(不是子节点):hint 的
393
+ * textContent 必须保持纯提示文案(采纳时直接落成正文,调试面板也按它读)。 */
363
394
  var hintNodeRef = useRef(null);
395
+ var hintAcceptNodeRef = useRef(null);
364
396
  var removeHintNode = useCallback(function () {
365
- var _hintNodeRef$current;
397
+ var _hintNodeRef$current, _hintAcceptNodeRef$cu;
366
398
  (_hintNodeRef$current = hintNodeRef.current) === null || _hintNodeRef$current === void 0 || _hintNodeRef$current.remove();
367
399
  hintNodeRef.current = null;
400
+ (_hintAcceptNodeRef$cu = hintAcceptNodeRef.current) === null || _hintAcceptNodeRef$cu === void 0 || _hintAcceptNodeRef$cu.remove();
401
+ hintAcceptNodeRef.current = null;
368
402
  }, []);
369
403
  var syncHintNode = useCallback(function (target) {
370
404
  var _Array$from$find, _blankTail;
@@ -384,6 +418,11 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
384
418
  hintNodeRef.current = node;
385
419
  }
386
420
  if (node.textContent !== target.text) node.textContent = target.text;
421
+ var accept = hintAcceptNodeRef.current;
422
+ if (!accept || !accept.isConnected) {
423
+ accept = createHintAcceptNode();
424
+ hintAcceptNodeRef.current = accept;
425
+ }
387
426
 
388
427
  /* 落位:命中 chip 之后、**紧随其后的不可见锚点文本(ZWSP)之后**。
389
428
  *
@@ -398,8 +437,9 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
398
437
  var cur = host.nextSibling;
399
438
  while (cur) {
400
439
  var _cur$textContent;
401
- // 跳过 hint 自身:上一轮若把它排到了锚点前面,这里顺手挪回末尾
402
- if (cur === node) {
440
+ // 跳过 hint 自身与它的「TAB 采纳」小块:上一轮若排到了锚点前面,
441
+ // 这里顺手挪回末尾
442
+ if (cur === node || cur === accept) {
403
443
  cur = cur.nextSibling;
404
444
  continue;
405
445
  }
@@ -426,6 +466,12 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
426
466
  if (node.parentNode !== parent || node.previousSibling !== anchor) {
427
467
  parent.insertBefore(node, anchor.nextSibling);
428
468
  }
469
+ /* 「TAB 采纳」小块紧跟 hint 文案之后(同一套行内流),顺序必须是
470
+ * hint → 小块:caret 的合法落点只到 hint 之前,块本身
471
+ * contentEditable=false,不会成为落点。 */
472
+ if (accept.parentNode !== parent || accept.previousSibling !== node) {
473
+ parent.insertBefore(accept, node.nextSibling);
474
+ }
429
475
  }, [removeHintNode]);
430
476
 
431
477
  /** 把 caret 直接落到 hint 之前(= chip 右侧);没有 hint 时不动。 */
@@ -530,26 +576,45 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
530
576
  recomputeTriggerRef.current = recomputeTrigger;
531
577
 
532
578
  /* ─────────────────────────────────────
533
- * Tab 采纳 hint
579
+ * 采纳 hint(Tab / 点击「TAB 采纳」小块)
534
580
  *
535
581
  * hint 只是结构投影(不进 value);caret 恰好停在 chip 与 hint 之间
536
582
  * (= 内容末尾)时按 Tab,表示用户接受这段模板,于是把提示文案落成正文:
537
583
  * chip 之后出现内容 → 结构谓词不再命中 → 灰字自动移除,onChange 抛出的
538
584
  * value 里带上这段文案,与用户自己敲进去的效果一致。
585
+ *
586
+ * 鼠标点末尾的「TAB 采纳」小块走**同一条链路**,只是带 `force`:
587
+ * 不要求点击前 caret 就停在 hint 之前,先把 caret 归位到 chip 右侧再落。
539
588
  * ───────────────────────────────────── */
540
- var acceptHintAsText = useCallback(function () {
589
+ var acceptHintAsText = useCallback(function (options) {
541
590
  var _hint$textContent;
542
591
  var el = editorRef.current;
543
592
  var hint = hintNodeRef.current;
544
593
  var sel = window.getSelection();
545
- if (!el || !hint || !hint.isConnected || !sel || sel.rangeCount === 0) {
546
- return false;
594
+ if (!el || !hint || !hint.isConnected || !sel) return false;
595
+ var range;
596
+ if (options !== null && options !== void 0 && options.force) {
597
+ /* 点击路径:mousedown 已被 preventDefault,焦点 / caret 都还没进来,
598
+ * 先聚焦再把 caret 落到 hint 之前(= 内容末尾),避免原生落点乱跳。 */
599
+ el.focus({
600
+ preventScroll: true
601
+ });
602
+ var target = caretBeforeHintIn(el);
603
+ if (!target) return false;
604
+ range = document.createRange();
605
+ range.setStart(target.node, target.offset);
606
+ range.collapse(true);
607
+ sel.removeAllRanges();
608
+ sel.addRange(range);
609
+ lastEditorRangeRef.current = range.cloneRange();
610
+ } else {
611
+ if (sel.rangeCount === 0) return false;
612
+ range = sel.getRangeAt(0);
613
+ if (!range.collapsed || !el.contains(range.startContainer)) return false;
614
+ /* 只认「chip 之后、hint 之前」这一个落点;caret 在别处时 Tab 仍归浏览器,
615
+ * 避免在任意位置误吞焦点切换。 */
616
+ if (!isCaretBeforeHint(range, el)) return false;
547
617
  }
548
- var range = sel.getRangeAt(0);
549
- if (!range.collapsed || !el.contains(range.startContainer)) return false;
550
- /* 只认「chip 之后、hint 之前」这一个落点;caret 在别处时 Tab 仍归浏览器,
551
- * 避免在任意位置误吞焦点切换。 */
552
- if (!isCaretBeforeHint(range, el)) return false;
553
618
  var text = (_hint$textContent = hint.textContent) !== null && _hint$textContent !== void 0 ? _hint$textContent : '';
554
619
  if (!text) return false;
555
620
 
@@ -566,6 +631,7 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
566
631
  caret.collapse(true);
567
632
  sel.removeAllRanges();
568
633
  sel.addRange(caret);
634
+ lastEditorRangeRef.current = caret.cloneRange();
569
635
  }
570
636
  fireChange();
571
637
  recomputeTrigger();
@@ -1061,6 +1127,17 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
1061
1127
  if (e.button !== 0 || disabled) return;
1062
1128
  // shift+click 是扩选,不劫持
1063
1129
  if (e.shiftKey) return;
1130
+
1131
+ /* 「TAB 采纳」小块:点它等价于按 Tab(同一条采纳链路),且不要求点击前
1132
+ * caret 就停在 hint 之前。在 mousedown 阶段接管 + preventDefault,
1133
+ * 原生 caret 一帧都不会落到 hint 之后。 */
1134
+ if (e.target instanceof Element && e.target.closest(COMPOSER_HINT_ACCEPT_SELECTOR)) {
1135
+ e.preventDefault();
1136
+ acceptHintAsText({
1137
+ force: true
1138
+ });
1139
+ return;
1140
+ }
1064
1141
  var el = editorRef.current;
1065
1142
  var hint = hintNodeRef.current;
1066
1143
  if (!el || !hint || !hint.isConnected) return;
@@ -1091,7 +1168,7 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
1091
1168
  });
1092
1169
  placeCaretBeforeHint();
1093
1170
  requestScrollCaretIntoView();
1094
- }, [disabled, handlePointerInput, placeCaretBeforeHint, requestScrollCaretIntoView]);
1171
+ }, [acceptHintAsText, disabled, handlePointerInput, placeCaretBeforeHint, requestScrollCaretIntoView]);
1095
1172
  var writeClipboardPayload = useCallback(function (e, payload) {
1096
1173
  if (!payload) return false;
1097
1174
  e.clipboardData.setData(COMPOSER_CLIPBOARD_MIME, JSON.stringify(payload));
@@ -309,6 +309,74 @@
309
309
  white-space: pre-wrap;
310
310
  }
311
311
 
312
+ /* ------------------------------------------------------------------
313
+ * hint 末尾的「TAB 采纳」小块(点击 = 按 Tab 采纳,见 editor.tsx)
314
+ *
315
+ * 与 hint 文本是同级节点,一起增删。它不是正文:contentEditable=false、
316
+ * getPlainText 整棵跳过,点它走 force 版 acceptHintAsText。
317
+ * 尺寸对齐 Figma 9857:75425(62 × 22 / 圆角 6 / 内层键帽 28 × 16):
318
+ * - 编辑器固定 font-size 14 / line-height 24,块高 22 + top 1 → 视觉居中
319
+ * 且不撑高行盒(改编辑器行高时要同步调这个 1px)
320
+ * - 底色 black-2(5%)、键帽 bg-elevated + black-5(12%) 1px 描边
321
+ * ----------------------------------------------------------------- */
322
+ [data-odn-composer] [data-odn-composer-hint-accept] {
323
+ display: inline-flex;
324
+ align-items: center;
325
+ justify-content: center;
326
+ gap: 3px;
327
+ box-sizing: border-box;
328
+ height: 22px;
329
+ margin: 1px 0 0 4px;
330
+ padding: 0 4px 0 3px;
331
+ border-radius: 6px;
332
+ background: var(--odn-color-black-2);
333
+ color: var(--odn-color-solid-black-9);
334
+ font-size: 12px;
335
+ line-height: 20px;
336
+ white-space: nowrap;
337
+ vertical-align: top;
338
+ cursor: pointer;
339
+ user-select: none;
340
+ pointer-events: auto;
341
+ transition: background 0.15s ease-out, color 0.15s ease-out;
342
+ /* 底部 5% 太淡,hover 抬到 12%(约 2.4 倍)并加深文字,让「可点」更明确;
343
+ * active 再深一档。 */
344
+ }
345
+ [data-odn-composer] [data-odn-composer-hint-accept]:hover {
346
+ background: var(--odn-color-black-5);
347
+ color: var(--odn-color-solid-black-10);
348
+ }
349
+ [data-odn-composer] [data-odn-composer-hint-accept]:active {
350
+ background: var(--odn-color-black-6);
351
+ }
352
+
353
+ [data-odn-composer] [data-odn-composer-hint-accept-key] {
354
+ display: inline-flex;
355
+ align-items: center;
356
+ justify-content: center;
357
+ box-sizing: border-box;
358
+ height: 16px;
359
+ padding: 0 4px;
360
+ border: 1px solid var(--odn-color-black-5);
361
+ border-radius: 4px;
362
+ /* 与 composer box 同为「浮在底层之上的面」,跟随主题变量而不是写死白色 */
363
+ background: var(--odn-color-bg-elevated);
364
+ font-size: 10px;
365
+ line-height: 10px;
366
+ letter-spacing: 0;
367
+ }
368
+
369
+ [data-odn-composer] [data-odn-composer-hint-accept-label] {
370
+ font-size: 12px;
371
+ line-height: 20px;
372
+ }
373
+
374
+ /* 禁用态:hint 仍按内容结构展示,但小块不可点(与 editor 冻结一致) */
375
+ [data-odn-composer] [data-odn-composer-editor][data-odn-composer-editor-disabled] [data-odn-composer-hint-accept] {
376
+ cursor: not-allowed;
377
+ pointer-events: none;
378
+ }
379
+
312
380
  /* ------------------------------------------------------------------
313
381
  * Block 行模型(caret-rewrite step 1/5)
314
382
  * editor 直接子节点都是 [data-composer-line] div,每行渲染为独立 block。
@@ -22,6 +22,15 @@ export declare const LINE_ATTR_NAME = "data-composer-line";
22
22
  */
23
23
  export declare const COMPOSER_HINT_ATTR = "data-odn-composer-skill-hint";
24
24
  export declare const COMPOSER_HINT_SELECTOR = "[data-odn-composer-skill-hint]";
25
+ /**
26
+ * 派生 hint 末尾的「TAB 采纳」小块(可点击采纳)。
27
+ *
28
+ * 与 hint 文本是**兄弟节点**(不是子节点):hint 自身的 `textContent` 必须
29
+ * 保持纯提示文案——采纳时直接把这段文字落成正文,且 `getPlainText` /
30
+ * 调试面板都按 textContent 读它。小块同样不是正文,遍历时整棵跳过。
31
+ */
32
+ export declare const COMPOSER_HINT_ACCEPT_ATTR = "data-odn-composer-hint-accept";
33
+ export declare const COMPOSER_HINT_ACCEPT_SELECTOR = "[data-odn-composer-hint-accept]";
25
34
  /** 是否是行容器。 */
26
35
  export declare function isLineRoot(node: Node | null | undefined): node is HTMLDivElement;
27
36
  /** 创建一个新的空行容器。 */
@@ -39,6 +39,16 @@ export var LINE_ATTR_NAME = 'data-composer-line';
39
39
  export var COMPOSER_HINT_ATTR = 'data-odn-composer-skill-hint';
40
40
  export var COMPOSER_HINT_SELECTOR = "[".concat(COMPOSER_HINT_ATTR, "]");
41
41
 
42
+ /**
43
+ * 派生 hint 末尾的「TAB 采纳」小块(可点击采纳)。
44
+ *
45
+ * 与 hint 文本是**兄弟节点**(不是子节点):hint 自身的 `textContent` 必须
46
+ * 保持纯提示文案——采纳时直接把这段文字落成正文,且 `getPlainText` /
47
+ * 调试面板都按 textContent 读它。小块同样不是正文,遍历时整棵跳过。
48
+ */
49
+ export var COMPOSER_HINT_ACCEPT_ATTR = 'data-odn-composer-hint-accept';
50
+ export var COMPOSER_HINT_ACCEPT_SELECTOR = "[".concat(COMPOSER_HINT_ACCEPT_ATTR, "]");
51
+
42
52
  /** 是否是行容器。 */
43
53
  export function isLineRoot(node) {
44
54
  var _hasAttribute, _ref;
@@ -292,8 +302,8 @@ export function getPlainText(editor) {
292
302
  var out = '';
293
303
  var visit = function visit(node) {
294
304
  if (node instanceof HTMLElement) {
295
- // 派生 hint 整棵子树都不是正文,直接跳过(含其内部文本节点)
296
- if (node.hasAttribute(COMPOSER_HINT_ATTR)) return;
305
+ // 派生 hint(含末尾的「TAB 采纳」小块)整棵子树都不是正文,直接跳过
306
+ if (node.hasAttribute(COMPOSER_HINT_ATTR) || node.hasAttribute(COMPOSER_HINT_ACCEPT_ATTR)) return;
297
307
  var id = node.dataset[chipIdAttr];
298
308
  if (id) {
299
309
  out += createMarker(id);
@@ -7,6 +7,7 @@ import Icon from "../icon";
7
7
  import Input from "../input";
8
8
  import Popover from "../popover";
9
9
  import { highlightQueryText } from "../stream-text/highlight-query-text";
10
+ import Tooltip from "../tooltip";
10
11
  import "./style";
11
12
  function skillMatchesQuery(skill, query) {
12
13
  var _skill$description;
@@ -367,8 +368,15 @@ export var SkillSlot = /*#__PURE__*/forwardRef(function SkillSlot(_ref2, ref) {
367
368
  };
368
369
  var renderBarItem = function renderBarItem(skill) {
369
370
  var disabled = !!skill.disabled;
370
- var barButton = /*#__PURE__*/React.createElement("button", {
371
+
372
+ /* bar 无行内描述:整条 bar 由外层 Tooltip.Group 共用一层浮层(暗色,见 style)。
373
+ * 这里只把「本项的描述」交给 Group,hover 绑定由 Group 自己挂到 button 上。 */
374
+ return /*#__PURE__*/React.createElement(Tooltip, {
371
375
  key: skill.id,
376
+ popup: skill.description ? /*#__PURE__*/React.createElement("span", {
377
+ "data-odn-skill-slot-desc-full": true
378
+ }, skill.description) : null
379
+ }, /*#__PURE__*/React.createElement("button", {
372
380
  type: "button",
373
381
  "data-odn-skill-slot-item": true,
374
382
  "data-odn-skill-slot-item-disabled": disabled || undefined,
@@ -379,21 +387,8 @@ export var SkillSlot = /*#__PURE__*/forwardRef(function SkillSlot(_ref2, ref) {
379
387
  }
380
388
  }, /*#__PURE__*/React.createElement(Icon, {
381
389
  name: skill.icon,
382
- size: 14
383
- }), skill.label);
384
-
385
- /* bar 无行内描述:整颗 chip hover 0.5s 后向上 Popover 出全文 */
386
- if (skill.description) {
387
- return /*#__PURE__*/React.createElement(Popover, {
388
- key: skill.id,
389
- placement: "top",
390
- mouseEnterDelay: 0.5,
391
- popup: /*#__PURE__*/React.createElement("span", {
392
- "data-odn-skill-slot-desc-full": true
393
- }, skill.description)
394
- }, barButton);
395
- }
396
- return barButton;
390
+ size: 16
391
+ }), skill.label));
397
392
  };
398
393
  var listBody = skills.map(function (skill, index) {
399
394
  if (variant === 'card') return renderCardItem(skill);
@@ -461,10 +456,27 @@ export var SkillSlot = /*#__PURE__*/forwardRef(function SkillSlot(_ref2, ref) {
461
456
  } : {}), variant !== 'menu' && itemWidth !== undefined && itemWidth !== null ? {
462
457
  '--odn-skill-slot-item-width': "".concat(itemWidth, "px")
463
458
  } : {}), style);
464
- if (variant !== 'menu') {
459
+
460
+ /* bar:整条 bar 是一组 Tooltip(与 preview-panel 右上角按钮同款手感)——
461
+ * 共用一层浮层,已展开时在块之间横移是 0 延迟换文案 + 浮层跟着滑,
462
+ * 移出整组 200ms 后才收起,不会一块一块地闪断。
463
+ * 容器本身就是 Tooltip.Group 的 Tag,data-* / className / style 一并落上去。 */
464
+ if (variant === 'bar') {
465
+ return /*#__PURE__*/React.createElement(Tooltip.Group, {
466
+ as: "div",
467
+ "data-odn-skill-slot": true,
468
+ "data-odn-skill-slot-variant": "bar",
469
+ className: className,
470
+ style: rootStyle,
471
+ placement: "top",
472
+ mouseEnterDelay: 0.1,
473
+ popupClassName: "odn-skill-slot-bar-popup"
474
+ }, listBody);
475
+ }
476
+ if (variant === 'card') {
465
477
  return /*#__PURE__*/React.createElement("div", {
466
478
  "data-odn-skill-slot": true,
467
- "data-odn-skill-slot-variant": variant,
479
+ "data-odn-skill-slot-variant": "card",
468
480
  className: className,
469
481
  style: rootStyle
470
482
  }, listBody);
@@ -237,39 +237,71 @@
237
237
  margin: 0;
238
238
  }
239
239
 
240
- /* ---- variant: bar ---- */
240
+ /* ---- variant: bar ----
241
+ * 白底胶囊 chip:999 圆角,14/22 文案 + 16 icon,块间距 12。
242
+ * 设计稿:默认态**无描边**(描边在稿里是隐藏的),hover 才浮出黑-3 细描边,
243
+ * 底色/文字不变——所以预置 1px 透明描边占位,避免 hover 时宽度跳 2px。 */
241
244
  [data-odn-skill-slot][data-odn-skill-slot-variant=bar] {
242
245
  display: flex;
243
246
  flex-wrap: wrap;
244
- gap: 8px;
247
+ gap: 12px;
245
248
  }
246
249
 
247
250
  [data-odn-skill-slot][data-odn-skill-slot-variant=bar] [data-odn-skill-slot-item] {
248
251
  display: inline-flex;
249
252
  align-items: center;
250
- gap: 6px;
251
- height: 32px;
253
+ gap: 4px;
254
+ height: 36px;
252
255
  padding: 0 12px;
253
- border-radius: var(--odn-border-radius);
254
- border: 1px solid var(--odn-color-black-6);
255
- background: var(--odn-color-bg-elevated);
256
- font-size: 13px;
257
- color: var(--odn-color-black-10);
256
+ border-radius: 999px;
257
+ border: 1px solid transparent;
258
+ background: var(--odn-color-white);
259
+ box-sizing: border-box;
260
+ /* 不参与压缩:容器放不下就整块换行。否则窄容器里 flex 会把块挤到
261
+ * 比文案还窄,14/22 的文案折成两行、溢出固定 36px 的胶囊。 */
262
+ flex: 0 0 auto;
263
+ white-space: nowrap;
264
+ font-size: 14px;
265
+ font-weight: 400;
266
+ line-height: 22px;
267
+ color: var(--odn-color-black-12);
258
268
  transition: border-color 0.15s, background 0.15s, color 0.15s;
259
269
  }
260
270
  [data-odn-skill-slot][data-odn-skill-slot-variant=bar] [data-odn-skill-slot-item]:not([data-odn-skill-slot-item-disabled]):hover {
261
- border-color: var(--odn-color-black-7);
262
- background: var(--odn-color-black-3);
263
- color: var(--odn-color-black-12);
271
+ border-color: var(--odn-color-black-3);
264
272
  }
265
273
  [data-odn-skill-slot][data-odn-skill-slot-variant=bar] [data-odn-skill-slot-item]:not([data-odn-skill-slot-item-disabled]):active {
266
- background: var(--odn-color-black-4);
274
+ border-color: var(--odn-color-black-4);
267
275
  }
268
276
  [data-odn-skill-slot][data-odn-skill-slot-variant=bar] [data-odn-skill-slot-item]:not([data-odn-skill-slot-item-disabled]):focus-visible {
269
277
  outline: none;
270
278
  border-color: var(--odn-color-brand-6);
271
- background: var(--odn-color-black-3);
272
- color: var(--odn-color-black-12);
279
+ }
280
+
281
+ /* bar chip hover 的全文提示:暗色浮层(设计稿「文字提示」:向上、多行)。
282
+ * 整条 bar 走 Tooltip.Group,浮层是 tooltip;popupClassName 落在
283
+ * [data-odn-popup-content] 上,用 [data-type] 兜住 pop-base 的
284
+ * popover 白底 / tooltip #404040 两套默认值。 */
285
+ [data-odn-popup][data-type] [data-odn-popup-content].odn-skill-slot-bar-popup {
286
+ max-width: 400px;
287
+ padding: 4px 8px;
288
+ border-radius: 4px;
289
+ background-color: var(--odn-color-solid-black-11);
290
+ color: var(--odn-color-white);
291
+ font-size: 14px;
292
+ font-weight: 400;
293
+ line-height: 22px;
294
+ }
295
+
296
+ [data-odn-popup][data-type] [data-odn-popup-content].odn-skill-slot-bar-popup [data-odn-popup-arrow-fill] {
297
+ fill: var(--odn-color-solid-black-11);
298
+ }
299
+
300
+ /* 浮层纯视觉遮挡,不接收鼠标:pointer-events 可继承,给外层一次即可。
301
+ * 多行 bar 里浮层会压在上一行的块上,若吃掉事件,块↔块之间就换不过去,
302
+ * 也会挡住下层页面/输入框。 */
303
+ [data-odn-popup]:has(> [data-odn-popup-content].odn-skill-slot-bar-popup) {
304
+ pointer-events: none;
273
305
  }
274
306
 
275
307
  /* ---- variant: card ---- */
@@ -366,4 +398,12 @@
366
398
  color: var(--odn-color-black-9);
367
399
  word-break: break-word;
368
400
  white-space: pre-wrap;
401
+ }
402
+
403
+ /* bar 的全文浮层里换成暗底白字 14/22(宽度由 .odn-skill-slot-bar-popup 的 400 兜住) */
404
+ .odn-skill-slot-bar-popup [data-odn-skill-slot-desc-full] {
405
+ max-width: 100%;
406
+ font-size: 14px;
407
+ line-height: 22px;
408
+ color: var(--odn-color-white);
369
409
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "one-design-next",
3
- "version": "0.0.115",
3
+ "version": "0.0.116",
4
4
  "description": "One Design Next from TAD@tencent.com",
5
5
  "license": "MIT",
6
6
  "type": "module",