@aura-react-comp/x 0.0.0-stage → 0.1.1

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 (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +80 -2
  3. package/esm/actions/index.d.ts +28 -0
  4. package/esm/actions/index.js +37 -0
  5. package/esm/actions/index.less +59 -0
  6. package/esm/attachments/index.d.ts +41 -0
  7. package/esm/attachments/index.js +48 -0
  8. package/esm/attachments/index.less +22 -0
  9. package/esm/bubble/index.d.ts +42 -0
  10. package/esm/bubble/index.js +80 -0
  11. package/esm/bubble/index.less +164 -0
  12. package/esm/code-highlighter/index.d.ts +39 -0
  13. package/esm/code-highlighter/index.js +165 -0
  14. package/esm/code-highlighter/index.less +76 -0
  15. package/esm/code-highlighter/prism-theme.d.ts +13 -0
  16. package/esm/code-highlighter/prism-theme.js +75 -0
  17. package/esm/conversations/index.d.ts +35 -0
  18. package/esm/conversations/index.js +89 -0
  19. package/esm/conversations/index.less +138 -0
  20. package/esm/file-card/index.d.ts +40 -0
  21. package/esm/file-card/index.js +126 -0
  22. package/esm/file-card/index.less +161 -0
  23. package/esm/folder/index.d.ts +66 -0
  24. package/esm/folder/index.js +345 -0
  25. package/esm/folder/index.less +158 -0
  26. package/esm/folder/tree-utils.d.ts +30 -0
  27. package/esm/folder/tree-utils.js +147 -0
  28. package/esm/folder/types.d.ts +51 -0
  29. package/esm/folder/types.js +1 -0
  30. package/esm/index.d.ts +40 -0
  31. package/esm/index.js +20 -0
  32. package/esm/markdown-content/index.d.ts +34 -0
  33. package/esm/markdown-content/index.js +117 -0
  34. package/esm/markdown-content/index.less +124 -0
  35. package/esm/mermaid/index.d.ts +47 -0
  36. package/esm/mermaid/index.js +235 -0
  37. package/esm/mermaid/index.less +155 -0
  38. package/esm/notification/index.d.ts +59 -0
  39. package/esm/notification/index.js +148 -0
  40. package/esm/prompts/index.d.ts +27 -0
  41. package/esm/prompts/index.js +50 -0
  42. package/esm/prompts/index.less +95 -0
  43. package/esm/sender/index.d.ts +48 -0
  44. package/esm/sender/index.js +88 -0
  45. package/esm/sender/index.less +75 -0
  46. package/esm/sources/index.d.ts +40 -0
  47. package/esm/sources/index.js +154 -0
  48. package/esm/sources/index.less +219 -0
  49. package/esm/style.css +1565 -0
  50. package/esm/suggestion/index.d.ts +21 -0
  51. package/esm/suggestion/index.js +36 -0
  52. package/esm/suggestion/index.less +44 -0
  53. package/esm/think/index.d.ts +20 -0
  54. package/esm/think/index.js +48 -0
  55. package/esm/think/index.less +92 -0
  56. package/esm/thought-chain/index.d.ts +34 -0
  57. package/esm/thought-chain/index.js +105 -0
  58. package/esm/thought-chain/index.less +174 -0
  59. package/esm/use-x-chat/index.d.ts +85 -0
  60. package/esm/use-x-chat/index.js +178 -0
  61. package/esm/use-x-stream/index.d.ts +43 -0
  62. package/esm/use-x-stream/index.js +112 -0
  63. package/esm/use-x-stream/parse-sse.d.ts +19 -0
  64. package/esm/use-x-stream/parse-sse.js +91 -0
  65. package/esm/utils/color.d.ts +9 -0
  66. package/esm/utils/color.js +45 -0
  67. package/esm/welcome/index.d.ts +22 -0
  68. package/esm/welcome/index.js +36 -0
  69. package/esm/welcome/index.less +57 -0
  70. package/esm/x-provider/index.d.ts +48 -0
  71. package/esm/x-provider/index.js +66 -0
  72. package/package.json +70 -3
@@ -0,0 +1,165 @@
1
+ import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';
2
+ import { Highlight } from 'prism-react-renderer';
3
+ import { classNames, prefixCls } from '@aura-react-comp/shared';
4
+ import { auraCodeTheme } from "./prism-theme";
5
+
6
+ /** 复制按钮的成功态展示时长 */
7
+ import { jsx as _jsx } from "react/jsx-runtime";
8
+ import { jsxs as _jsxs } from "react/jsx-runtime";
9
+ const COPIED_RESET_DELAY = 1500;
10
+ /** 复制图标(继承 currentColor) */
11
+ const CopyGlyph = () => /*#__PURE__*/_jsxs("svg", {
12
+ viewBox: "0 0 16 16",
13
+ fill: "none",
14
+ stroke: "currentColor",
15
+ strokeWidth: "1.3",
16
+ strokeLinecap: "round",
17
+ strokeLinejoin: "round",
18
+ "aria-hidden": "true",
19
+ focusable: "false",
20
+ children: [/*#__PURE__*/_jsx("rect", {
21
+ x: "5.5",
22
+ y: "5.5",
23
+ width: "8",
24
+ height: "8",
25
+ rx: "1.5"
26
+ }), /*#__PURE__*/_jsx("path", {
27
+ d: "M10.5 5.5V4a1.5 1.5 0 0 0-1.5-1.5H4A1.5 1.5 0 0 0 2.5 4v5A1.5 1.5 0 0 0 4 10.5h1.5"
28
+ })]
29
+ });
30
+
31
+ /**
32
+ * 复制文本:优先 Clipboard API,不可用时(非安全上下文)回退到
33
+ * 临时 textarea + `document.execCommand`。
34
+ */
35
+ async function writeToClipboard(text) {
36
+ if (typeof navigator !== 'undefined' && navigator.clipboard?.writeText) {
37
+ await navigator.clipboard.writeText(text);
38
+ return;
39
+ }
40
+ if (typeof document === 'undefined') throw new Error('clipboard unavailable');
41
+ const area = document.createElement('textarea');
42
+ area.value = text;
43
+ area.setAttribute('readonly', '');
44
+ area.style.position = 'fixed';
45
+ area.style.opacity = '0';
46
+ document.body.appendChild(area);
47
+ area.select();
48
+ try {
49
+ const ok = document.execCommand('copy');
50
+ if (!ok) throw new Error('execCommand copy returned false');
51
+ } finally {
52
+ document.body.removeChild(area);
53
+ }
54
+ }
55
+
56
+ /**
57
+ * CodeHighlighter — 代码高亮。
58
+ *
59
+ * 基于 `prism-react-renderer`:等宽字体 + 语法着色 + 头部语言标识与一键复制。
60
+ * 配色走 `var(--aura-*)` 令牌,亮暗主题自动跟随,无需传入主题对象。
61
+ */
62
+ export const CodeHighlighter = /*#__PURE__*/forwardRef(({
63
+ lang = 'text',
64
+ children,
65
+ header,
66
+ copiedText = '已复制',
67
+ onCopy,
68
+ className,
69
+ style
70
+ }, ref) => {
71
+ const code = children ?? '';
72
+ const rootRef = useRef(null);
73
+ const timerRef = useRef(null);
74
+ const [copied, setCopied] = useState(false);
75
+
76
+ // 不定依赖数组:每次提交都重新取根节点,避免 ref 晚挂载时拿到 null
77
+ useImperativeHandle(ref, () => ({
78
+ nativeElement: rootRef.current
79
+ }));
80
+
81
+ // 卸载时清掉未完成的成功态定时器,避免对已卸载组件 setState
82
+ useEffect(() => () => {
83
+ if (timerRef.current !== null) window.clearTimeout(timerRef.current);
84
+ }, []);
85
+ const handleCopy = useCallback(async () => {
86
+ try {
87
+ await writeToClipboard(code);
88
+ } catch {
89
+ // 复制失败(权限 / 非安全上下文):保持原状,不打断阅读
90
+ return;
91
+ }
92
+ setCopied(true);
93
+ onCopy?.(code);
94
+ if (timerRef.current !== null) window.clearTimeout(timerRef.current);
95
+ timerRef.current = window.setTimeout(() => setCopied(false), COPIED_RESET_DELAY);
96
+ }, [code, onCopy]);
97
+ const resolvedHeader = (() => {
98
+ if (header === false) return null;
99
+ if (typeof header === 'function') {
100
+ const custom = header({
101
+ lang,
102
+ code
103
+ });
104
+ return custom === false ? null : custom;
105
+ }
106
+ if (header !== undefined) return header;
107
+ return /*#__PURE__*/_jsxs("div", {
108
+ className: prefixCls('x-code-highlighter-header'),
109
+ children: [/*#__PURE__*/_jsx("span", {
110
+ className: prefixCls('x-code-highlighter-lang'),
111
+ children: lang
112
+ }), /*#__PURE__*/_jsxs("button", {
113
+ type: "button",
114
+ className: prefixCls('x-code-highlighter-copy'),
115
+ onClick: handleCopy,
116
+ "aria-label": copied ? copiedText : '复制代码',
117
+ children: [/*#__PURE__*/_jsx(CopyGlyph, {}), /*#__PURE__*/_jsx("span", {
118
+ children: copied ? copiedText : '复制'
119
+ })]
120
+ })]
121
+ });
122
+ })();
123
+ return /*#__PURE__*/_jsxs("div", {
124
+ ref: rootRef,
125
+ className: classNames(prefixCls('x-code-highlighter'), className),
126
+ style: style,
127
+ children: [resolvedHeader, /*#__PURE__*/_jsx(Highlight, {
128
+ theme: auraCodeTheme,
129
+ code: code,
130
+ language: lang.toLowerCase(),
131
+ children: ({
132
+ className: prismClassName,
133
+ style: prismStyle,
134
+ tokens,
135
+ getLineProps,
136
+ getTokenProps
137
+ }) => /*#__PURE__*/_jsx("pre", {
138
+ className: classNames(prefixCls('x-code-highlighter-pre'), prismClassName),
139
+ style: prismStyle,
140
+ children: /*#__PURE__*/_jsx("code", {
141
+ children: tokens.map((line, lineIndex) => {
142
+ const lineProps = getLineProps({
143
+ line
144
+ });
145
+ return (
146
+ /*#__PURE__*/
147
+ // 行用 block 的 <span> 而非 <div>:<pre> / <code> 的内容模型
148
+ // 只接受短语内容,塞 div 是无效 HTML(读屏与结构校验都会报)
149
+ _jsx("span", {
150
+ ...lineProps,
151
+ className: classNames(prefixCls('x-code-highlighter-line'), lineProps.className),
152
+ children: line.map((token, tokenIndex) => /*#__PURE__*/_jsx("span", {
153
+ ...getTokenProps({
154
+ token
155
+ })
156
+ }, tokenIndex))
157
+ }, lineIndex)
158
+ );
159
+ })
160
+ })
161
+ })
162
+ })]
163
+ });
164
+ });
165
+ CodeHighlighter.displayName = 'CodeHighlighter';
@@ -0,0 +1,76 @@
1
+ /* CodeHighlighter — 代码高亮(头部 + Prism 着色代码区) */
2
+
3
+ .aura-x-code-highlighter {
4
+ overflow: hidden;
5
+ border: 1px solid var(--aura-x-bubble-border);
6
+ border-radius: var(--aura-radius-md);
7
+ background: var(--aura-x-code-bg);
8
+ }
9
+
10
+ /* ===== 头部 ===== */
11
+
12
+ .aura-x-code-highlighter-header {
13
+ display: flex;
14
+ gap: var(--aura-spacing-2);
15
+ align-items: center;
16
+ justify-content: space-between;
17
+ padding: var(--aura-spacing-1) var(--aura-spacing-2) var(--aura-spacing-1)
18
+ var(--aura-spacing-3);
19
+ border-bottom: 1px solid var(--aura-border);
20
+ background: var(--aura-x-stage-bg);
21
+ }
22
+
23
+ .aura-x-code-highlighter-lang {
24
+ color: var(--aura-text-secondary);
25
+ font-size: var(--aura-font-size-xs);
26
+ letter-spacing: 0.4px;
27
+ text-transform: lowercase;
28
+ }
29
+
30
+ .aura-x-code-highlighter-copy {
31
+ display: inline-flex;
32
+ gap: var(--aura-spacing-1);
33
+ align-items: center;
34
+ padding: var(--aura-spacing-1) var(--aura-spacing-2);
35
+ border: none;
36
+ border-radius: var(--aura-radius-sm);
37
+ background: transparent;
38
+ color: var(--aura-text-secondary);
39
+ font-size: var(--aura-font-size-xs);
40
+ cursor: pointer;
41
+ transition:
42
+ background var(--aura-duration-fast) var(--aura-easing),
43
+ color var(--aura-duration-fast) var(--aura-easing);
44
+ }
45
+
46
+ .aura-x-code-highlighter-copy:hover {
47
+ background: var(--aura-x-accent-soft);
48
+ color: var(--aura-x-accent);
49
+ }
50
+
51
+ .aura-x-code-highlighter-copy:focus-visible {
52
+ outline: none;
53
+ box-shadow: var(--aura-x-focus-ring);
54
+ }
55
+
56
+ .aura-x-code-highlighter-copy > svg {
57
+ width: 13px;
58
+ height: 13px;
59
+ }
60
+
61
+ /* ===== 代码区 ===== */
62
+
63
+ .aura-x-code-highlighter-pre {
64
+ margin: 0;
65
+ padding: var(--aura-spacing-3);
66
+ overflow-x: auto;
67
+ background: transparent;
68
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
69
+ font-size: var(--aura-font-size-sm);
70
+ line-height: 1.65;
71
+ }
72
+
73
+ .aura-x-code-highlighter-line {
74
+ display: block;
75
+ min-height: 1.65em;
76
+ }
@@ -0,0 +1,13 @@
1
+ import type { PrismTheme } from 'prism-react-renderer';
2
+ /**
3
+ * Aura 代码高亮主题。
4
+ *
5
+ * 与 antdx 的差异:**不绑定某一套亮/暗主题**,而是把 token 颜色写成
6
+ * `var(--aura-*)` 引用。prism-react-renderer 只是把这些值塞进行内 `style`,
7
+ * 浏览器解析时仍会走 CSS 变量,于是主题切换(`data-theme`)自动生效,
8
+ * 无需在 JS 侧判断明暗、也不需要维护两份配色表。
9
+ *
10
+ * 颜色取语义令牌而非硬编码色值,与 `MarkdownContent` 的代码块观感保持一致
11
+ * (底色同为 `--aura-x-code-bg`,字体栈同为 ui-monospace 一系)。
12
+ */
13
+ export declare const auraCodeTheme: PrismTheme;
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Aura 代码高亮主题。
3
+ *
4
+ * 与 antdx 的差异:**不绑定某一套亮/暗主题**,而是把 token 颜色写成
5
+ * `var(--aura-*)` 引用。prism-react-renderer 只是把这些值塞进行内 `style`,
6
+ * 浏览器解析时仍会走 CSS 变量,于是主题切换(`data-theme`)自动生效,
7
+ * 无需在 JS 侧判断明暗、也不需要维护两份配色表。
8
+ *
9
+ * 颜色取语义令牌而非硬编码色值,与 `MarkdownContent` 的代码块观感保持一致
10
+ * (底色同为 `--aura-x-code-bg`,字体栈同为 ui-monospace 一系)。
11
+ */
12
+ export const auraCodeTheme = {
13
+ plain: {
14
+ color: 'var(--aura-text)',
15
+ backgroundColor: 'transparent'
16
+ },
17
+ styles: [{
18
+ types: ['comment', 'prolog', 'doctype', 'cdata'],
19
+ style: {
20
+ color: 'var(--aura-text-tertiary)',
21
+ fontStyle: 'italic'
22
+ }
23
+ }, {
24
+ types: ['punctuation'],
25
+ style: {
26
+ color: 'var(--aura-text-secondary)'
27
+ }
28
+ }, {
29
+ types: ['namespace'],
30
+ style: {
31
+ opacity: 0.7
32
+ }
33
+ }, {
34
+ types: ['tag', 'constant', 'symbol', 'deleted'],
35
+ style: {
36
+ color: 'var(--aura-error)'
37
+ }
38
+ }, {
39
+ types: ['property', 'attr-name'],
40
+ style: {
41
+ color: 'var(--aura-primary-700)'
42
+ }
43
+ }, {
44
+ types: ['boolean', 'number'],
45
+ style: {
46
+ color: 'var(--aura-primary-600)'
47
+ }
48
+ }, {
49
+ types: ['selector', 'string', 'char', 'builtin', 'inserted', 'attr-value'],
50
+ style: {
51
+ color: 'var(--aura-success)'
52
+ }
53
+ }, {
54
+ types: ['operator', 'entity', 'url'],
55
+ style: {
56
+ color: 'var(--aura-text-secondary)'
57
+ }
58
+ }, {
59
+ types: ['atrule', 'keyword'],
60
+ style: {
61
+ color: 'var(--aura-primary-700)',
62
+ fontWeight: '600'
63
+ }
64
+ }, {
65
+ types: ['function', 'class-name'],
66
+ style: {
67
+ color: 'var(--aura-info)'
68
+ }
69
+ }, {
70
+ types: ['regex', 'important', 'variable'],
71
+ style: {
72
+ color: 'var(--aura-warning)'
73
+ }
74
+ }]
75
+ };
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ export interface ConversationItem {
3
+ key: React.Key;
4
+ label: React.ReactNode;
5
+ icon?: React.ReactNode;
6
+ timestamp?: React.ReactNode;
7
+ }
8
+ export interface ConversationMenuItem {
9
+ key: React.Key;
10
+ label: React.ReactNode;
11
+ danger?: boolean;
12
+ }
13
+ export interface ConversationMenuConfig {
14
+ /** 菜单触发按钮的图标(默认 …) */
15
+ icon?: React.ReactNode;
16
+ items: ConversationMenuItem[];
17
+ onClick: (item: ConversationItem, menuItemKey: React.Key) => void;
18
+ }
19
+ export interface ConversationsProps {
20
+ items: ConversationItem[];
21
+ /** 当前激活会话 */
22
+ activeKey?: React.Key;
23
+ onActiveChange?: (key: React.Key) => void;
24
+ /** 每条会话的操作菜单(重命名 / 置顶 / 删除等),传入后显示 … 触发按钮 */
25
+ menu?: (item: ConversationItem) => ConversationMenuConfig;
26
+ className?: string;
27
+ style?: React.CSSProperties;
28
+ }
29
+ /**
30
+ * Conversations — 会话管理列表。
31
+ *
32
+ * 多会话应用的侧栏:激活高亮、时间戳、可选操作菜单(重命名 / 删除等,
33
+ * 由 `menu` 配置注入,组件只负责展示与回调)。
34
+ */
35
+ export declare const Conversations: React.FC<ConversationsProps>;
@@ -0,0 +1,89 @@
1
+ import React, { useRef, useState } from 'react';
2
+ import { classNames, prefixCls } from '@aura-react-comp/shared';
3
+ import { jsx as _jsx } from "react/jsx-runtime";
4
+ import { jsxs as _jsxs } from "react/jsx-runtime";
5
+ /**
6
+ * Conversations — 会话管理列表。
7
+ *
8
+ * 多会话应用的侧栏:激活高亮、时间戳、可选操作菜单(重命名 / 删除等,
9
+ * 由 `menu` 配置注入,组件只负责展示与回调)。
10
+ */
11
+ export const Conversations = ({
12
+ items,
13
+ activeKey,
14
+ onActiveChange,
15
+ menu,
16
+ className,
17
+ style
18
+ }) => {
19
+ // 同一时刻至多展开一个操作菜单
20
+ const [openMenuKey, setOpenMenuKey] = useState(null);
21
+ const openKeyRef = useRef(null);
22
+ openKeyRef.current = openMenuKey;
23
+ return /*#__PURE__*/_jsx("div", {
24
+ className: classNames(prefixCls('x-conversations'), className),
25
+ style: style,
26
+ onClick: () => setOpenMenuKey(null),
27
+ children: /*#__PURE__*/_jsx("ul", {
28
+ className: prefixCls('x-conversations-list'),
29
+ role: "list",
30
+ children: items.map(item => {
31
+ const isActive = activeKey !== undefined && item.key === activeKey;
32
+ const menuConfig = menu?.(item);
33
+ const menuOpen = openMenuKey !== null && item.key === openMenuKey;
34
+ return /*#__PURE__*/_jsx("li", {
35
+ role: "listitem",
36
+ children: /*#__PURE__*/_jsxs("div", {
37
+ className: classNames(prefixCls('x-conversations-item'), isActive && prefixCls('x-conversations-item--active')),
38
+ children: [/*#__PURE__*/_jsxs("button", {
39
+ type: "button",
40
+ className: prefixCls('x-conversations-item-main'),
41
+ onClick: () => {
42
+ setOpenMenuKey(null);
43
+ onActiveChange?.(item.key);
44
+ },
45
+ children: [item.icon ? /*#__PURE__*/_jsx("span", {
46
+ className: prefixCls('x-conversations-item-icon'),
47
+ children: item.icon
48
+ }) : null, /*#__PURE__*/_jsx("span", {
49
+ className: prefixCls('x-conversations-item-label'),
50
+ children: item.label
51
+ }), item.timestamp ? /*#__PURE__*/_jsx("span", {
52
+ className: prefixCls('x-conversations-item-time'),
53
+ children: item.timestamp
54
+ }) : null]
55
+ }), menuConfig ? /*#__PURE__*/_jsxs("span", {
56
+ className: prefixCls('x-conversations-item-menu'),
57
+ onClick: event => event.stopPropagation(),
58
+ children: [/*#__PURE__*/_jsx("button", {
59
+ type: "button",
60
+ className: classNames(prefixCls('x-conversations-menu-btn'), menuOpen && prefixCls('x-conversations-menu-btn--open')),
61
+ "aria-label": "\u4F1A\u8BDD\u64CD\u4F5C",
62
+ onClick: event => {
63
+ event.stopPropagation();
64
+ setOpenMenuKey(menuOpen ? null : item.key);
65
+ },
66
+ children: menuConfig.icon ?? '…'
67
+ }), menuOpen ? /*#__PURE__*/_jsx("span", {
68
+ className: prefixCls('x-conversations-menu'),
69
+ role: "menu",
70
+ children: menuConfig.items.map(menuItem => /*#__PURE__*/_jsx("button", {
71
+ type: "button",
72
+ role: "menuitem",
73
+ className: classNames(prefixCls('x-conversations-menu-item'), menuItem.danger && prefixCls('x-conversations-menu-item--danger')),
74
+ onClick: event => {
75
+ event.stopPropagation();
76
+ menuConfig.onClick(item, menuItem.key);
77
+ setOpenMenuKey(null);
78
+ },
79
+ children: menuItem.label
80
+ }, menuItem.key))
81
+ }) : null]
82
+ }) : null]
83
+ })
84
+ }, item.key);
85
+ })
86
+ })
87
+ });
88
+ };
89
+ Conversations.displayName = 'Conversations';
@@ -0,0 +1,138 @@
1
+ /* Conversations — 会话管理列表 */
2
+
3
+ .aura-x-conversations-list {
4
+ display: flex;
5
+ flex-direction: column;
6
+ gap: 2px;
7
+ margin: 0;
8
+ padding: var(--aura-spacing-1);
9
+ list-style: none;
10
+ }
11
+
12
+ .aura-x-conversations-item {
13
+ position: relative;
14
+ display: flex;
15
+ align-items: center;
16
+ border-radius: var(--aura-radius-md);
17
+ transition: background var(--aura-duration-fast) var(--aura-easing);
18
+ }
19
+
20
+ .aura-x-conversations-item:hover,
21
+ .aura-x-conversations-item--active {
22
+ background: var(--aura-x-accent-soft);
23
+ }
24
+
25
+ .aura-x-conversations-item--active .aura-x-conversations-item-label {
26
+ color: var(--aura-x-accent);
27
+ font-weight: 500;
28
+ }
29
+
30
+ .aura-x-conversations-item-main {
31
+ display: flex;
32
+ flex: 1;
33
+ gap: var(--aura-spacing-2);
34
+ align-items: center;
35
+ min-width: 0;
36
+ padding: var(--aura-spacing-2) var(--aura-spacing-3);
37
+ border: none;
38
+ background: transparent;
39
+ color: var(--aura-text);
40
+ font-size: var(--aura-font-size-sm);
41
+ text-align: left;
42
+ cursor: pointer;
43
+ }
44
+
45
+ .aura-x-conversations-item-icon {
46
+ display: grid;
47
+ place-items: center;
48
+ flex-shrink: 0;
49
+ }
50
+
51
+ .aura-x-conversations-item-label {
52
+ flex: 1;
53
+ overflow: hidden;
54
+ text-overflow: ellipsis;
55
+ white-space: nowrap;
56
+ }
57
+
58
+ .aura-x-conversations-item-time {
59
+ flex-shrink: 0;
60
+ font-size: var(--aura-font-size-xs);
61
+ color: var(--aura-text-tertiary);
62
+ }
63
+
64
+ .aura-x-conversations-item-menu {
65
+ position: relative;
66
+ display: none;
67
+ flex-shrink: 0;
68
+ }
69
+
70
+ .aura-x-conversations-item:hover .aura-x-conversations-item-menu,
71
+ .aura-x-conversations-menu-btn--open {
72
+ display: inline-flex;
73
+ }
74
+
75
+ .aura-x-conversations-menu-btn {
76
+ display: inline-flex;
77
+ align-items: center;
78
+ justify-content: center;
79
+ width: 24px;
80
+ height: 24px;
81
+ border: none;
82
+ border-radius: var(--aura-radius-sm);
83
+ background: transparent;
84
+ color: var(--aura-text-tertiary);
85
+ cursor: pointer;
86
+ letter-spacing: 1px;
87
+ transition: background var(--aura-duration-fast) var(--aura-easing);
88
+ }
89
+
90
+ .aura-x-conversations-menu-btn:hover,
91
+ .aura-x-conversations-menu-btn--open {
92
+ background: var(--aura-x-accent-soft);
93
+ color: var(--aura-x-accent);
94
+ }
95
+
96
+ .aura-x-conversations-menu {
97
+ position: absolute;
98
+ top: calc(100% + 4px);
99
+ right: 0;
100
+ z-index: 10;
101
+ display: flex;
102
+ flex-direction: column;
103
+ gap: 2px;
104
+ min-width: 120px;
105
+ padding: var(--aura-spacing-1);
106
+ border: 1px solid var(--aura-x-bubble-border);
107
+ border-radius: var(--aura-radius-md);
108
+ background: var(--aura-x-bubble-ai-bg);
109
+ backdrop-filter: var(--aura-x-glass-blur);
110
+ -webkit-backdrop-filter: var(--aura-x-glass-blur);
111
+ box-shadow: var(--aura-x-glow);
112
+ }
113
+
114
+ .aura-x-conversations-menu-item {
115
+ display: block;
116
+ width: 100%;
117
+ padding: var(--aura-spacing-1) var(--aura-spacing-3);
118
+ border: none;
119
+ border-radius: var(--aura-radius-sm);
120
+ background: transparent;
121
+ color: var(--aura-text);
122
+ font-size: var(--aura-font-size-sm);
123
+ text-align: left;
124
+ cursor: pointer;
125
+ transition: background var(--aura-duration-fast) var(--aura-easing);
126
+ }
127
+
128
+ .aura-x-conversations-menu-item:hover {
129
+ background: var(--aura-x-accent-soft);
130
+ }
131
+
132
+ .aura-x-conversations-menu-item--danger {
133
+ color: var(--aura-error);
134
+ }
135
+
136
+ .aura-x-conversations-menu-item--danger:hover {
137
+ background: rgba(239, 68, 68, 0.1);
138
+ }
@@ -0,0 +1,40 @@
1
+ import React from 'react';
2
+ export type FileCardStatus = 'init' | 'uploading' | 'done' | 'error';
3
+ export interface FileCardProps {
4
+ /** 文件名(建议带扩展名,如 report.pdf) */
5
+ name: string;
6
+ /** 字节数;内部格式化为 B / KB / MB / GB */
7
+ size?: number;
8
+ /**
9
+ * 状态:
10
+ * - `init`:普通展示(默认)
11
+ * - `uploading`:显示进度条与百分比
12
+ * - `done`:成功态
13
+ * - `error`:失败态,显示 errorTip
14
+ */
15
+ status?: FileCardStatus;
16
+ /** `status="uploading"` 时的进度(0–100,越界会自动钳制) */
17
+ percent?: number;
18
+ /** 文件描述,显示在元信息下方 */
19
+ description?: React.ReactNode;
20
+ /** 失败原因;`status="error"` 时替代 description 显示 */
21
+ errorTip?: React.ReactNode;
22
+ /** 自定义图标;缺省渲染内置文件图标 */
23
+ icon?: React.ReactNode;
24
+ /** 移除按钮;不传则不渲染 */
25
+ onRemove?: (name: string) => void;
26
+ className?: string;
27
+ style?: React.CSSProperties;
28
+ }
29
+ /** 字节数 → 人类可读字符串(B 取整,其余保留一位小数) */
30
+ export declare function formatFileSize(bytes: number): string;
31
+ /** 取小写扩展名;无扩展名返回空串 */
32
+ export declare function getFileExt(name: string): string;
33
+ /**
34
+ * FileCard — 文件卡片。
35
+ *
36
+ * 附件列表、引用文件、上传结果的基本展示单元:图标、文件名、大小、
37
+ * 扩展名徽标与状态(上传进度 / 完成 / 失败)。通常配合
38
+ * [`Attachments`](/x-components/attachments) 组成输入框上方的附件条。
39
+ */
40
+ export declare const FileCard: React.FC<FileCardProps>;