@octohirono/stitch-design-system 0.1.0 → 0.3.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 (83) hide show
  1. package/dist/components/BarChart/BarChart.d.ts +42 -0
  2. package/dist/components/BarChart/BarChart.js +71 -0
  3. package/dist/components/BarChart/bar-chart.module.js +4 -0
  4. package/dist/components/BarChart/index.d.ts +2 -0
  5. package/dist/components/Calendar/Calendar.d.ts +57 -0
  6. package/dist/components/Calendar/Calendar.js +83 -0
  7. package/dist/components/Calendar/calendar.module.js +26 -0
  8. package/dist/components/Calendar/index.d.ts +2 -0
  9. package/dist/components/ChatFile/ChatFile.d.ts +34 -0
  10. package/dist/components/ChatFile/ChatFile.js +71 -0
  11. package/dist/components/ChatFile/chat-file.module.js +12 -0
  12. package/dist/components/ChatFile/index.d.ts +2 -0
  13. package/dist/components/ChatImage/ChatImage.d.ts +31 -0
  14. package/dist/components/ChatImage/ChatImage.js +88 -0
  15. package/dist/components/ChatImage/chat-image.module.js +12 -0
  16. package/dist/components/ChatImage/index.d.ts +2 -0
  17. package/dist/components/ChatInput/ChatInput.d.ts +77 -0
  18. package/dist/components/ChatInput/ChatInput.js +88 -0
  19. package/dist/components/ChatInput/chat-input.module.js +11 -0
  20. package/dist/components/ChatInput/index.d.ts +2 -0
  21. package/dist/components/ChatList/ChatList.d.ts +58 -0
  22. package/dist/components/ChatList/ChatList.js +49 -0
  23. package/dist/components/ChatList/chat-list.module.js +7 -0
  24. package/dist/components/ChatList/index.d.ts +2 -0
  25. package/dist/components/ChatMessage/ChatMessage.d.ts +52 -0
  26. package/dist/components/ChatMessage/ChatMessage.js +71 -0
  27. package/dist/components/ChatMessage/chat-message.module.js +21 -0
  28. package/dist/components/ChatMessage/index.d.ts +2 -0
  29. package/dist/components/ChatMessageActions/ChatMessageActions.d.ts +40 -0
  30. package/dist/components/ChatMessageActions/ChatMessageActions.js +34 -0
  31. package/dist/components/ChatMessageActions/chat-message-actions.module.js +7 -0
  32. package/dist/components/ChatMessageActions/index.d.ts +2 -0
  33. package/dist/components/ChatVoice/ChatVoice.d.ts +39 -0
  34. package/dist/components/ChatVoice/ChatVoice.js +44 -0
  35. package/dist/components/ChatVoice/chat-voice.module.js +12 -0
  36. package/dist/components/ChatVoice/index.d.ts +2 -0
  37. package/dist/components/ContextMenu/ContextMenu.js +41 -34
  38. package/dist/components/ContextMenu/context-menu.module.js +10 -9
  39. package/dist/components/DatePicker/DatePicker.d.ts +60 -0
  40. package/dist/components/DatePicker/DatePicker.js +75 -0
  41. package/dist/components/DatePicker/datepicker.module.js +17 -0
  42. package/dist/components/DatePicker/index.d.ts +2 -0
  43. package/dist/components/DropdownMenu/DropdownMenu.js +45 -38
  44. package/dist/components/DropdownMenu/dropdown-menu.module.js +10 -9
  45. package/dist/components/Icon/Icon.d.ts +36 -0
  46. package/dist/components/Icon/Icon.js +59 -1
  47. package/dist/components/Image/Image.js +1 -1
  48. package/dist/components/Image/image.module.js +14 -14
  49. package/dist/components/LineChart/LineChart.d.ts +48 -0
  50. package/dist/components/LineChart/LineChart.js +110 -0
  51. package/dist/components/LineChart/index.d.ts +2 -0
  52. package/dist/components/LineChart/line-chart.module.js +7 -0
  53. package/dist/components/PieChart/PieChart.d.ts +43 -0
  54. package/dist/components/PieChart/PieChart.js +56 -0
  55. package/dist/components/PieChart/index.d.ts +2 -0
  56. package/dist/components/PieChart/pie-chart.module.js +7 -0
  57. package/dist/components/Select/Select.js +87 -83
  58. package/dist/components/Select/select.module.js +10 -9
  59. package/dist/components/Stat/Stat.d.ts +71 -0
  60. package/dist/components/Stat/Stat.js +66 -0
  61. package/dist/components/Stat/StatGroup.d.ts +14 -0
  62. package/dist/components/Stat/StatGroup.js +16 -0
  63. package/dist/components/Stat/index.d.ts +4 -0
  64. package/dist/components/Stat/stat.module.js +23 -0
  65. package/dist/components/TypingIndicator/TypingIndicator.d.ts +24 -0
  66. package/dist/components/TypingIndicator/TypingIndicator.js +29 -0
  67. package/dist/components/TypingIndicator/index.d.ts +2 -0
  68. package/dist/components/TypingIndicator/typing-indicator.module.js +8 -0
  69. package/dist/components/_internal/dataviz/ChartFrame.d.ts +20 -0
  70. package/dist/components/_internal/dataviz/ChartFrame.js +18 -0
  71. package/dist/components/_internal/dataviz/ChartTooltip.d.ts +23 -0
  72. package/dist/components/_internal/dataviz/ChartTooltip.js +33 -0
  73. package/dist/components/_internal/dataviz/chart-frame.module.js +4 -0
  74. package/dist/components/_internal/dataviz/chart-tooltip.module.js +11 -0
  75. package/dist/components/_internal/dataviz/chartColors.d.ts +12 -0
  76. package/dist/components/_internal/dataviz/chartColors.js +3 -0
  77. package/dist/components/_internal/dataviz/index.d.ts +5 -0
  78. package/dist/index.d.ts +28 -0
  79. package/dist/index.js +37 -22
  80. package/dist/style.css +1305 -448
  81. package/dist/themes/seline.css +39 -0
  82. package/dist/themes/steep.css +37 -0
  83. package/package.json +9 -4
@@ -0,0 +1,88 @@
1
+ import { Icon as e } from "../Icon/Icon.js";
2
+ import t from "./chat-input.module.js";
3
+ import { useCallback as n, useLayoutEffect as r, useRef as i, useState as a } from "react";
4
+ import o from "clsx";
5
+ import { jsx as s, jsxs as c } from "react/jsx-runtime";
6
+ //#region packages/react/src/components/ChatInput/ChatInput.tsx
7
+ var l = 1, u = ({ value: u, defaultValue: d, onChange: f, onSubmit: p, placeholder: m, disabled: h = !1, loading: g = !1, autoSize: _ = !0, submitType: v = "enter", prefix: y, actions: b, sendAriaLabel: x = "发送", className: S, style: C, ...w }) => {
8
+ let [T, E] = a(d ?? ""), D = u !== void 0, O = D ? u : T, k = i(null), A = n(() => {
9
+ let e = k.current;
10
+ if (e == null || _ === !1) return;
11
+ let t = _ === !0 ? {} : _, n = parseFloat(window.getComputedStyle(e).lineHeight) || 0;
12
+ e.style.height = "auto";
13
+ let r = e.scrollHeight;
14
+ if (n > 0) {
15
+ let i = t.minRows ?? l;
16
+ if (r = Math.max(r, i * n), t.maxRows != null) {
17
+ let i = t.maxRows * n;
18
+ e.style.overflowY = r > i ? "auto" : "hidden", r = Math.min(r, i);
19
+ } else e.style.overflowY = "hidden";
20
+ }
21
+ e.style.height = `${r}px`;
22
+ }, [_]);
23
+ r(() => {
24
+ A();
25
+ }, [O, A]), r(() => {
26
+ let e = k.current;
27
+ if (e == null || _ === !1 || typeof ResizeObserver > "u") return;
28
+ let t = -1, n = new ResizeObserver((e) => {
29
+ let n = e[0].contentRect.width;
30
+ n !== t && (t = n, A());
31
+ });
32
+ return n.observe(e), () => n.disconnect();
33
+ }, [_, A]);
34
+ let j = n((e) => {
35
+ D || E(e.target.value), f?.(e);
36
+ }, [D, f]), M = n(() => {
37
+ if (h || g) return;
38
+ let e = O;
39
+ e.trim() !== "" && (p?.(e), D || E(""));
40
+ }, [
41
+ h,
42
+ g,
43
+ O,
44
+ p,
45
+ D
46
+ ]), N = n((e) => {
47
+ e.key === "Enter" && (e.nativeEvent.isComposing || (v === "enter" ? !e.shiftKey : e.shiftKey) && (e.preventDefault(), M()));
48
+ }, [v, M]), P = !h && !g && O.trim() !== "";
49
+ return /* @__PURE__ */ c("div", {
50
+ className: o(t.input, h && t["is-disabled"], S),
51
+ style: C,
52
+ children: [
53
+ y != null && /* @__PURE__ */ s("div", {
54
+ className: t.prefix,
55
+ children: y
56
+ }),
57
+ /* @__PURE__ */ s("textarea", {
58
+ ref: k,
59
+ className: t.textarea,
60
+ value: O,
61
+ placeholder: m,
62
+ disabled: h,
63
+ rows: 1,
64
+ onChange: j,
65
+ onKeyDown: N,
66
+ ...w
67
+ }),
68
+ /* @__PURE__ */ c("div", {
69
+ className: t.actions,
70
+ children: [b, /* @__PURE__ */ s("button", {
71
+ type: "button",
72
+ className: t.send,
73
+ onClick: M,
74
+ disabled: !P,
75
+ "aria-label": x,
76
+ "aria-busy": g || void 0,
77
+ children: /* @__PURE__ */ s(e, {
78
+ name: "send",
79
+ size: 20
80
+ })
81
+ })]
82
+ })
83
+ ]
84
+ });
85
+ };
86
+ u.displayName = "ChatInput";
87
+ //#endregion
88
+ export { u as ChatInput };
@@ -0,0 +1,11 @@
1
+ //#region packages/react/src/components/ChatInput/chat-input.module.less
2
+ var e = "_input_1o9t1_1", t = "_prefix_1o9t1_27", n = "_textarea_1o9t1_32", r = "_actions_1o9t1_56", i = "_send_1o9t1_62", a = {
3
+ input: e,
4
+ "is-disabled": "_is-disabled_1o9t1_15",
5
+ prefix: t,
6
+ textarea: n,
7
+ actions: r,
8
+ send: i
9
+ };
10
+ //#endregion
11
+ export { r as actions, a as default, e as input, t as prefix, i as send, n as textarea };
@@ -0,0 +1,2 @@
1
+ export { ChatInput } from './ChatInput';
2
+ export type { ChatInputProps, ChatInputSubmitType, ChatInputAutoSize, } from './ChatInput';
@@ -0,0 +1,58 @@
1
+ import React from 'react';
2
+ import type { ChatMessageProps, ChatMessageVariant } from '../ChatMessage';
3
+ /** 单条消息数据 = 一条 `ChatMessage` 的 props + 稳定 `id`(React key + append 判定) */
4
+ export interface ChatListItem extends ChatMessageProps {
5
+ /** 唯一标识:作 React key,并驱动「新消息 append」判定 */
6
+ id: string | number;
7
+ }
8
+ /**
9
+ * 消息流容器:**数据驱动**——吃 `items`(每项 = 一条 `ChatMessage` 的 props + `id`),内部
10
+ * 渲染 `ChatMessage`(`ChatMessage` 仍可单独使用,列表场景走 `items`)。负责连发分组编排、
11
+ * 贴底滚动与向上加载历史的接缝。对外 props 照搬 Ant Design X `Bubble.List`(`items` / `roles` /
12
+ * `autoScroll`),加载更多接缝取 Ant `on*` 惯例。
13
+ *
14
+ * 跨-prop 注意事项:
15
+ * - **数据驱动、组件不算业务**:消息内容 / 时间 / 头像 / 已读态全由 `items` 每项自带(就是
16
+ * `ChatMessageProps`);组件只按数组顺序渲染,不排序、不去重、不算时间。
17
+ * - **`roles` 灌角色默认**:按 `variant` 给同类消息灌共享默认(如 received 统一头像),`item`
18
+ * 显式字段优先覆盖 `roles` 默认(照 Ant X `roles`)。
19
+ * - **连发分组自动编排**:相邻同 `variant`(非 system)的续条自动置 `ChatMessage` 的 `grouped`
20
+ * ——头像只在组内首条显示、组内间距收紧(**不合并内容,仍是多个独立气泡**)。`system` 项
21
+ * (如日期分隔)断组。`item` 显式传 `grouped` 时以其为准。
22
+ * - **日期分隔 = `system` 项**:日期分隔线作为一条 `variant="system"` 的 `item` 承载居中灰条,
23
+ * **标签文字(今天 / 昨天 / 某月某日)由 app 放进该项的 `content`,组件不算日期**。
24
+ * - **`autoScroll` 贴底 + 上滚暂停**:`items` 追加时若用户仍在底部则自动滚到底;用户手动上滚
25
+ * 离底即暂停自动贴底、滚回底部恢复。`autoScroll={false}` 整体关闭。
26
+ * - **`onReachTop` 只发信号、组件不 fetch**:滚到顶发一次 `onReachTop`,去哪取历史、怎么
27
+ * prepend 全交 app;`loadingMore` 由 app 控制,为真时顶部显示转圈(复用 `<Loading>`)。组件
28
+ * 不拥有传输(接缝原则同 `ChatMessage`)。
29
+ * - **根节点 `role="log"` + 键盘可聚焦**:消息流作实时日志区(`aria-live="polite"` + 增量播报),
30
+ * 新消息由辅助技术增量读出;容器 `tabIndex={0}` 使纯键盘用户 Tab 进本区后用方向键 /
31
+ * PageUp/Down 翻历史(滚到顶即触 `onReachTop`),聚焦环走 `:focus-visible`(WCAG 2.1.1)。
32
+ */
33
+ export interface ChatListProps {
34
+ /** 消息数据(数据驱动,内部渲染 `ChatMessage`);每项 = `ChatMessageProps` + `id` */
35
+ items: ChatListItem[];
36
+ /** 按 `variant` 的角色默认配置(照 Ant X `roles`);合并进同 variant 的每项,item 显式值优先 */
37
+ roles?: Partial<Record<ChatMessageVariant, Partial<ChatMessageProps>>>;
38
+ /**
39
+ * 新消息自动贴底(照 Ant X `autoScroll`):用户手动上滚时暂停、滚回底部恢复
40
+ * @default true
41
+ */
42
+ autoScroll?: boolean;
43
+ /**
44
+ * 滚到顶时触发(加载更多历史):**组件不 fetch**,去哪拿数据、拿到怎么 prepend 全交 app;
45
+ * 组件只发信号并等 app 回灌 `items`(接缝原则同 `ChatMessage` 不拥有传输)
46
+ */
47
+ onReachTop?: () => void;
48
+ /**
49
+ * 顶部加载中(**由 app 控制**,配合 `onReachTop`):为真在顶部显示转圈(复用 `<Loading>`)
50
+ * @default false
51
+ */
52
+ loadingMore?: boolean;
53
+ /** 自定义类名(挂到根容器) */
54
+ className?: string;
55
+ /** 行内样式(挂到根容器) */
56
+ style?: React.CSSProperties;
57
+ }
58
+ export declare const ChatList: React.FC<ChatListProps>;
@@ -0,0 +1,49 @@
1
+ import { ChatMessage as e } from "../ChatMessage/ChatMessage.js";
2
+ import { Loading as t } from "../Loading/Loading.js";
3
+ import n from "./chat-list.module.js";
4
+ import { useCallback as r, useLayoutEffect as i, useRef as a } from "react";
5
+ import o from "clsx";
6
+ import { jsx as s, jsxs as c } from "react/jsx-runtime";
7
+ //#region packages/react/src/components/ChatList/ChatList.tsx
8
+ var l = 48, u = ({ items: u, roles: d, onReachTop: f, autoScroll: p = !0, loadingMore: m = !1, className: h, style: g }) => {
9
+ let _ = a(null), v = a(!1), y = a(!0), b = r(() => {
10
+ let e = _.current;
11
+ if (e == null) return;
12
+ let t = e.scrollHeight - e.clientHeight > l && e.scrollTop <= l;
13
+ t && !v.current && !m && f?.(), v.current = t;
14
+ let n = e.scrollHeight - e.clientHeight - e.scrollTop;
15
+ y.current = n <= l;
16
+ }, [f, m]);
17
+ return i(() => {
18
+ let e = _.current;
19
+ e == null || !p || !y.current || (e.scrollTop = e.scrollHeight);
20
+ }, [u, p]), /* @__PURE__ */ c("div", {
21
+ className: o(n.list, h),
22
+ style: g,
23
+ ref: _,
24
+ onScroll: b,
25
+ role: "log",
26
+ "aria-live": "polite",
27
+ "aria-relevant": "additions",
28
+ tabIndex: 0,
29
+ children: [m && /* @__PURE__ */ s("div", {
30
+ className: n["top-loader"],
31
+ children: /* @__PURE__ */ s(t, {
32
+ spinning: !0,
33
+ size: "small"
34
+ })
35
+ }), u.map((t, n) => {
36
+ let { id: r, ...i } = t, a = d?.[i.variant ?? "received"], o = a ? {
37
+ ...a,
38
+ ...i
39
+ } : i, c = u[n - 1], l = o.grouped ?? (c != null && c.variant === o.variant && o.variant !== "system");
40
+ return /* @__PURE__ */ s(e, {
41
+ ...o,
42
+ grouped: l
43
+ }, r);
44
+ })]
45
+ });
46
+ };
47
+ u.displayName = "ChatList";
48
+ //#endregion
49
+ export { u as ChatList };
@@ -0,0 +1,7 @@
1
+ //#region packages/react/src/components/ChatList/chat-list.module.less
2
+ var e = "_list_1xrm9_1", t = {
3
+ list: e,
4
+ "top-loader": "_top-loader_1xrm9_13"
5
+ };
6
+ //#endregion
7
+ export { t as default, e as list };
@@ -0,0 +1,2 @@
1
+ export { ChatList } from './ChatList';
2
+ export type { ChatListProps, ChatListItem } from './ChatList';
@@ -0,0 +1,52 @@
1
+ import React from 'react';
2
+ export type ChatMessageVariant = 'sent' | 'received' | 'system';
3
+ export type ChatMessageStatus = 'sent' | 'delivered' | 'read';
4
+ /**
5
+ * 单条聊天气泡:三态 `variant`(sent 右 / received 左 / system 居中灰条)+ `content`
6
+ * 消息体(纯文本或 ReactNode)+ `avatar`(复用 `<Avatar>`)+ `time` 时间元信息 +
7
+ * `status` 已读回执(仅 sent 侧)+ `grouped` 连发分组样式钩子。对外 props 照搬 Ant
8
+ * Design X `Bubble`(`content`/`variant`/`avatar`),已读回执 `status` 取 Ant 命名惯例。
9
+ *
10
+ * 跨-prop 注意事项:
11
+ * - **`variant` 驱动 placement**:sent 靠右、received 靠左、system 居中——不另立
12
+ * `placement` prop(三态已定方位)。system 态无头像、无 status。
13
+ * - **`content` 优先,`children` 兜底**:两者皆可传消息体,`content` 存在时取 `content`。
14
+ * - **纯 emoji 自动大图无气泡**:`content`(或 `children`)为纯 emoji 字符串(≤3 个、无其它
15
+ * 可见字符)时自动渲成大图、去掉气泡底色与内边距(照即时通讯惯例),不需额外 prop。
16
+ * - **`status` 仅 sent 侧出现**:sent → 单勾、delivered → 双勾(均 `--stitch-text-muted`)、
17
+ * read → 双勾 `--stitch-info`;勾走 `<Icon name="check">`(禁 emoji / Unicode `✓` / 裸
18
+ * svg),回执整体挂 `role="img"` + 可访问名(已发送 / 已送达 / 已读),内层 Icon 纯装饰。
19
+ * - **`grouped` 只出样式钩子**:为真时隐藏头像、收紧下间距(相邻同 variant 连发),由上层
20
+ * 编排决定何时置真,组件本身不判断相邻。头像列占位随「该条是否带 `avatar`」:带头像的续条
21
+ * (grouped 隐藏头像但保留列,同串气泡左缘对齐成一列,群聊);无头像的消息不占列、气泡贴边
22
+ * (1:1 私聊首尾条都无头像 → 整串贴边对齐)。要对齐成列 = 给每条都灌头像(列表走 `roles` /
23
+ * 每项 `avatar`),不靠「续条自动占空列」。
24
+ */
25
+ export interface ChatMessageProps {
26
+ /**
27
+ * 气泡三态:sent(本方,右)/ received(对方,左)/ system(系统居中灰条)
28
+ * @default 'received'
29
+ */
30
+ variant?: ChatMessageVariant;
31
+ /** 消息内容(纯文本或 ReactNode);纯 emoji 字符串自动大图无气泡。与 children 二选一(优先 content) */
32
+ content?: React.ReactNode;
33
+ /** 消息内容(content 的兜底写法) */
34
+ children?: React.ReactNode;
35
+ /** 头像(复用 `<Avatar>`);system 态不显示 */
36
+ avatar?: React.ReactNode;
37
+ /** 时间 / 元信息(如发送时间) */
38
+ time?: React.ReactNode;
39
+ /** 已读回执:sent 单勾 / delivered 双勾 / read 双勾高亮;仅 sent 侧渲染 */
40
+ status?: ChatMessageStatus;
41
+ /**
42
+ * 连发分组样式钩子:为真时隐藏头像但保留头像列缩进(气泡对齐成列)、收紧下间距
43
+ * (相邻同 variant 时由上层置真)
44
+ * @default false
45
+ */
46
+ grouped?: boolean;
47
+ /** 自定义类名(挂到根容器) */
48
+ className?: string;
49
+ /** 行内样式(挂到根容器) */
50
+ style?: React.CSSProperties;
51
+ }
52
+ export declare const ChatMessage: React.FC<ChatMessageProps>;
@@ -0,0 +1,71 @@
1
+ import { Icon as e } from "../Icon/Icon.js";
2
+ import t from "./chat-message.module.js";
3
+ import "react";
4
+ import n from "clsx";
5
+ import { Fragment as r, jsx as i, jsxs as a } from "react/jsx-runtime";
6
+ //#region packages/react/src/components/ChatMessage/ChatMessage.tsx
7
+ var o = {
8
+ sent: "已发送",
9
+ delivered: "已送达",
10
+ read: "已读"
11
+ }, s = /(\p{Extended_Pictographic}(️|‍|[\u{1F3FB}-\u{1F3FF}])*)/gu;
12
+ function c(e) {
13
+ if (typeof e != "string") return !1;
14
+ let t = e.trim();
15
+ if (!t) return !1;
16
+ let n = t.match(s);
17
+ return n ? t.replace(s, "").trim() === "" && n.length <= 3 : !1;
18
+ }
19
+ var l = ({ variant: s = "received", content: l, children: u, avatar: d, time: f, status: p, grouped: m = !1, className: h, style: g }) => {
20
+ let _ = l ?? u, v = s === "system", y = !v && c(_), b = n(t.message, t[`variant-${s}`], m && t["is-grouped"], y && t["is-emoji"], h);
21
+ if (v) return /* @__PURE__ */ a("div", {
22
+ className: b,
23
+ style: g,
24
+ children: [/* @__PURE__ */ i("div", {
25
+ className: t.system,
26
+ children: _
27
+ }), f != null && /* @__PURE__ */ i("div", {
28
+ className: t.time,
29
+ children: f
30
+ })]
31
+ });
32
+ let x = s === "sent" && p != null, S = p === "sent" ? 1 : 2, C = d != null, w = f != null || x ? /* @__PURE__ */ a(r, { children: [f != null && /* @__PURE__ */ i("span", {
33
+ className: t.time,
34
+ children: f
35
+ }), x && p != null && /* @__PURE__ */ i("span", {
36
+ className: n(t.ticks, p === "read" && t["ticks-read"]),
37
+ role: "img",
38
+ "aria-label": o[p],
39
+ children: Array.from({ length: S }).map((n, r) => /* @__PURE__ */ i(e, {
40
+ name: "check",
41
+ size: "1em",
42
+ className: t.tick
43
+ }, r))
44
+ })] }) : null;
45
+ return /* @__PURE__ */ a("div", {
46
+ className: b,
47
+ style: g,
48
+ children: [C && /* @__PURE__ */ i("div", {
49
+ className: t["avatar-slot"],
50
+ children: !m && d
51
+ }), /* @__PURE__ */ i("div", {
52
+ className: t.body,
53
+ children: y ? /* @__PURE__ */ a(r, { children: [/* @__PURE__ */ i("div", {
54
+ className: t.emoji,
55
+ children: _
56
+ }), w && /* @__PURE__ */ i("div", {
57
+ className: t["meta-below"],
58
+ children: w
59
+ })] }) : /* @__PURE__ */ a("div", {
60
+ className: t.bubble,
61
+ children: [_, w && /* @__PURE__ */ i("span", {
62
+ className: t.meta,
63
+ children: w
64
+ })]
65
+ })
66
+ })]
67
+ });
68
+ };
69
+ l.displayName = "ChatMessage";
70
+ //#endregion
71
+ export { l as ChatMessage };
@@ -0,0 +1,21 @@
1
+ //#region packages/react/src/components/ChatMessage/chat-message.module.less
2
+ var e = "_message_di477_1", t = "_body_di477_30", n = "_bubble_di477_39", r = "_emoji_di477_63", i = "_system_di477_67", a = "_meta_di477_75", o = "_time_di477_94", s = "_ticks_di477_97", c = "_tick_di477_97", l = {
3
+ message: e,
4
+ "variant-received": "_variant-received_di477_10",
5
+ "variant-sent": "_variant-sent_di477_14",
6
+ "variant-system": "_variant-system_di477_18",
7
+ "avatar-slot": "_avatar-slot_di477_24",
8
+ body: t,
9
+ bubble: n,
10
+ emoji: r,
11
+ system: i,
12
+ meta: a,
13
+ "meta-below": "_meta-below_di477_76",
14
+ time: o,
15
+ ticks: s,
16
+ tick: c,
17
+ "ticks-read": "_ticks-read_di477_105",
18
+ "is-grouped": "_is-grouped_di477_108"
19
+ };
20
+ //#endregion
21
+ export { t as body, n as bubble, l as default, r as emoji, e as message, a as meta, i as system, c as tick, s as ticks, o as time };
@@ -0,0 +1,2 @@
1
+ export { ChatMessage } from './ChatMessage';
2
+ export type { ChatMessageProps, ChatMessageVariant, ChatMessageStatus, } from './ChatMessage';
@@ -0,0 +1,40 @@
1
+ import React from 'react';
2
+ import { type DropdownMenuItem } from '../DropdownMenu';
3
+ /**
4
+ * 一条消息操作项。结构与 `DropdownMenuItem` / `ContextMenuItem` 完全一致(同一心智,
5
+ * 同 Ant v5 `items` 形态),因为它原样喂给这两个复用件。
6
+ */
7
+ export type ChatMessageAction = DropdownMenuItem;
8
+ /**
9
+ * 消息操作菜单:把一条消息(`children`,通常是 `<ChatMessage>`)包成「右键 / 长按出操作」。
10
+ * 本组件只出**触发 + 菜单壳**——动作项(回复 / 撤回 / 转发…)与回调全由 app 经 `actions` 传入。
11
+ * 不另造浮层:**指针路**用 `ContextMenu`——桌面右键、触屏长按目标区弹出(即时通讯惯例,无常驻按钮);
12
+ * **键盘路**用 `DropdownMenu`——尾角触发钮仅在键盘聚焦时显形、Enter 打开。两路喂同一份 `actions`。
13
+ *
14
+ * 跨-prop 注意事项:
15
+ * - **两路触发、一份动作**:`actions` 同时喂给 `ContextMenu`(右键 / 长按,指针主入口)与
16
+ * `DropdownMenu`(键盘聚焦露钮点开);app 只需配一份。每项 `{ label, icon?, onClick?, danger?,
17
+ * disabled?, children? }` 取 Ant v5 `items` 惯例,点项触发 `item.onClick`(动作语义、无选中态)。
18
+ * - **组件只出壳**:不持菜单开合 state、不判相邻、不接业务——回调交 app(`actions[].onClick`);
19
+ * 图标走 `<Icon>`(项 `icon` 由底层复用件经 `<Icon>` 渲染,禁裸 svg / emoji / Unicode 符号)。
20
+ * - **无常驻 hover 按钮**:指针用户走右键 / 长按,尾角触发钮**只在键盘聚焦(`:focus-visible`)**时显形、
21
+ * 不随 hover 出现(避免气泡上常驻钮),仅为保证键盘可达;无可见文字 → 走 `triggerLabel` 给可及名
22
+ * (默认「消息操作」)。
23
+ * - **键盘 / 焦点 / ARIA**(方向键走项、Enter 选中、Esc 关、焦点归还、`role="menu"`)由复用件
24
+ * (ContextMenu / DropdownMenu → 底层)保证,本组件不重复实现。
25
+ */
26
+ export interface ChatMessageActionsProps {
27
+ /** 被包裹的消息(通常是 `<ChatMessage>`):hover / 长按此区出操作入口 */
28
+ children: React.ReactNode;
29
+ /** 动作项数组(Ant v5 `items` 风格,原样喂给 DropdownMenu / ContextMenu) */
30
+ actions: ChatMessageAction[];
31
+ /** 触发钮的无障碍标签(无可见文字时的可及名) @default '消息操作' */
32
+ triggerLabel?: string;
33
+ /** 菜单显隐变化回调(两路共用) */
34
+ onOpenChange?: (open: boolean) => void;
35
+ /** 自定义类名(挂到根容器) */
36
+ className?: string;
37
+ /** 行内样式(挂到根容器) */
38
+ style?: React.CSSProperties;
39
+ }
40
+ export declare const ChatMessageActions: React.FC<ChatMessageActionsProps>;
@@ -0,0 +1,34 @@
1
+ import { Icon as e } from "../Icon/Icon.js";
2
+ import { DropdownMenu as t } from "../DropdownMenu/DropdownMenu.js";
3
+ import { ContextMenu as n } from "../ContextMenu/ContextMenu.js";
4
+ import r from "./chat-message-actions.module.js";
5
+ import "react";
6
+ import i from "clsx";
7
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
8
+ //#region packages/react/src/components/ChatMessageActions/ChatMessageActions.tsx
9
+ var s = ({ children: s, actions: c, triggerLabel: l = "消息操作", onOpenChange: u, className: d, style: f }) => /* @__PURE__ */ a(n, {
10
+ items: c,
11
+ onOpenChange: u,
12
+ children: /* @__PURE__ */ o("div", {
13
+ className: i(r.wrap, d),
14
+ style: f,
15
+ children: [s, /* @__PURE__ */ a(t, {
16
+ items: c,
17
+ onOpenChange: u,
18
+ "aria-label": l,
19
+ trigger: /* @__PURE__ */ a("button", {
20
+ type: "button",
21
+ className: r.trigger,
22
+ "aria-label": l,
23
+ children: /* @__PURE__ */ a(e, {
24
+ name: "chevron-down",
25
+ size: "1em",
26
+ "aria-hidden": !0
27
+ })
28
+ })
29
+ })]
30
+ })
31
+ });
32
+ s.displayName = "ChatMessageActions";
33
+ //#endregion
34
+ export { s as ChatMessageActions };
@@ -0,0 +1,7 @@
1
+ //#region packages/react/src/components/ChatMessageActions/chat-message-actions.module.less
2
+ var e = "_wrap_9echt_1", t = "_trigger_9echt_5", n = {
3
+ wrap: e,
4
+ trigger: t
5
+ };
6
+ //#endregion
7
+ export { n as default, t as trigger, e as wrap };
@@ -0,0 +1,2 @@
1
+ export { ChatMessageActions } from './ChatMessageActions';
2
+ export type { ChatMessageActionsProps, ChatMessageAction, } from './ChatMessageActions';
@@ -0,0 +1,39 @@
1
+ import React from 'react';
2
+ /**
3
+ * 语音消息(手绘静态波形):播放按钮(`<Button>` + `<Icon play/pause>`)+ 一排高低不等的
4
+ * 波形小条 + 时长;作为 `<ChatMessage>` 的 `content` 塞入(sent / received 两侧皆可)。
5
+ * 组件**不解码音频**——波形振幅数组 `waveform` 由 app 传入。无 Ant 对应件 → 播放态取
6
+ * Ant v5 `open` / `onOpenChange` 惯例(`playing` / `onPlayingChange`)、播放进度取 Ant
7
+ * `percent` 惯例,均不自创。
8
+ *
9
+ * 跨-prop 注意事项:
10
+ * - **波形柱是角色变量小元素、非内联 `<svg>`**:每根柱一个 `<div>`,高度按 `waveform` 振幅
11
+ * (`0…1`)由内联 `height` 百分比驱动(几何数据、非颜色);颜色只走角色变量类——已播段
12
+ * `--stitch-accent`、未播段 `--stitch-border`,切站换肤跟随。
13
+ * - **`percent` 划已播 / 未播**:`0…100`,按柱序比例染色(前 `percent%` 的柱 = 已播 accent)。
14
+ * - **`playing` 切图标、`onPlayingChange` 交 app**:受控播放态(app 翻转 `playing`);播放按钮
15
+ * 带可访问名(播放语音 / 暂停语音),波形本体装饰性 `aria-hidden`。
16
+ */
17
+ export interface ChatVoiceProps {
18
+ /** 波形振幅数组(`0…1`,由 app 传入;组件不解码音频) */
19
+ waveform: number[];
20
+ /** 时长文本(如 `0:12`) */
21
+ duration?: React.ReactNode;
22
+ /**
23
+ * 已播进度(`0…100`):前 `percent%` 的波形柱染为已播色(accent)
24
+ * @default 0
25
+ */
26
+ percent?: number;
27
+ /**
28
+ * 是否播放中:切换播放 / 暂停图标
29
+ * @default false
30
+ */
31
+ playing?: boolean;
32
+ /** 点击播放按钮的回调(播放 / 暂停交 app) */
33
+ onPlayingChange?: (playing: boolean) => void;
34
+ /** 自定义类名(挂到根容器) */
35
+ className?: string;
36
+ /** 行内样式(挂到根容器) */
37
+ style?: React.CSSProperties;
38
+ }
39
+ export declare const ChatVoice: React.FC<ChatVoiceProps>;
@@ -0,0 +1,44 @@
1
+ import { Button as e } from "../Button/Button.js";
2
+ import { Icon as t } from "../Icon/Icon.js";
3
+ import n from "./chat-voice.module.js";
4
+ import "react";
5
+ import r from "clsx";
6
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
7
+ //#region packages/react/src/components/ChatVoice/ChatVoice.tsx
8
+ var o = ({ waveform: o, duration: s, percent: c = 0, playing: l = !1, onPlayingChange: u, className: d, style: f }) => {
9
+ let p = o.length, m = Math.round(Math.min(100, Math.max(0, c)) / 100 * p);
10
+ return /* @__PURE__ */ a("div", {
11
+ className: r(n.voice, d),
12
+ style: f,
13
+ children: [
14
+ /* @__PURE__ */ i(e, {
15
+ type: "primary",
16
+ className: n.play,
17
+ onClick: () => u?.(!l),
18
+ "aria-label": l ? "暂停语音" : "播放语音",
19
+ icon: /* @__PURE__ */ i(t, {
20
+ name: l ? "pause" : "play",
21
+ size: "1.125em"
22
+ })
23
+ }),
24
+ /* @__PURE__ */ i("div", {
25
+ className: n.wave,
26
+ "aria-hidden": "true",
27
+ children: o.map((e, t) => {
28
+ let a = Math.max(.15, Math.min(1, e)) * 100;
29
+ return /* @__PURE__ */ i("div", {
30
+ className: r(n.bar, t < m ? n["bar-played"] : n["bar-idle"]),
31
+ style: { height: `${a}%` }
32
+ }, t);
33
+ })
34
+ }),
35
+ s != null && /* @__PURE__ */ i("span", {
36
+ className: n.duration,
37
+ children: s
38
+ })
39
+ ]
40
+ });
41
+ };
42
+ o.displayName = "ChatVoice";
43
+ //#endregion
44
+ export { o as ChatVoice };
@@ -0,0 +1,12 @@
1
+ //#region packages/react/src/components/ChatVoice/chat-voice.module.less
2
+ var e = "_voice_16mxc_1", t = "_play_16mxc_7", n = "_wave_16mxc_14", r = "_bar_16mxc_22", i = "_duration_16mxc_34", a = {
3
+ voice: e,
4
+ play: t,
5
+ wave: n,
6
+ bar: r,
7
+ "bar-played": "_bar-played_16mxc_28",
8
+ "bar-idle": "_bar-idle_16mxc_31",
9
+ duration: i
10
+ };
11
+ //#endregion
12
+ export { r as bar, a as default, i as duration, t as play, e as voice, n as wave };
@@ -0,0 +1,2 @@
1
+ export { ChatVoice } from './ChatVoice';
2
+ export type { ChatVoiceProps } from './ChatVoice';