@expcat/tigercat-react 0.2.27 → 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 (87) hide show
  1. package/dist/chunk-4IO2M3ZJ.js +110 -0
  2. package/dist/{chunk-2UVQIL26.mjs → chunk-6DYS4PJT.mjs} +1 -1
  3. package/dist/chunk-6YKZAWNX.js +258 -0
  4. package/dist/chunk-73DMQ2SR.mjs +206 -0
  5. package/dist/chunk-FAZQT7YP.mjs +255 -0
  6. package/dist/{chunk-HRYBEBZC.js → chunk-GJKT2B56.js} +5 -1
  7. package/dist/{chunk-5XKYWZZZ.mjs → chunk-HGTF6A46.mjs} +5 -1
  8. package/dist/chunk-HT2BXCEM.js +264 -0
  9. package/dist/{chunk-6ZC7H22S.mjs → chunk-IAF24RKI.mjs} +1 -1
  10. package/dist/chunk-IYFSM2GA.mjs +141 -0
  11. package/dist/chunk-JAVDNFJD.js +144 -0
  12. package/dist/{chunk-P273E6XE.js → chunk-MQTHGPHF.js} +37 -21
  13. package/dist/chunk-OVWCTDAL.js +209 -0
  14. package/dist/{chunk-GIYBVWR4.mjs → chunk-OZLAGTZW.mjs} +38 -22
  15. package/dist/{chunk-OD2NNQD2.js → chunk-PBJ2J2B3.js} +2 -2
  16. package/dist/chunk-PVOQUXIB.mjs +189 -0
  17. package/dist/chunk-R67R3TVA.mjs +261 -0
  18. package/dist/{chunk-VR5OP4MO.js → chunk-UG3I4PCY.js} +2 -2
  19. package/dist/chunk-WKGCUR7O.mjs +107 -0
  20. package/dist/chunk-ZN2BZCTI.js +192 -0
  21. package/dist/components/ActivityFeed.d.mts +10 -0
  22. package/dist/components/ActivityFeed.d.ts +10 -0
  23. package/dist/components/ActivityFeed.js +23 -0
  24. package/dist/components/ActivityFeed.mjs +8 -0
  25. package/dist/components/AreaChart.js +4 -4
  26. package/dist/components/AreaChart.mjs +2 -2
  27. package/dist/components/BarChart.js +4 -4
  28. package/dist/components/BarChart.mjs +2 -2
  29. package/dist/components/ChatWindow.d.mts +12 -0
  30. package/dist/components/ChatWindow.d.ts +12 -0
  31. package/dist/components/ChatWindow.js +20 -0
  32. package/dist/components/ChatWindow.mjs +5 -0
  33. package/dist/components/CommentThread.d.mts +8 -0
  34. package/dist/components/CommentThread.d.ts +8 -0
  35. package/dist/components/CommentThread.js +21 -0
  36. package/dist/components/CommentThread.mjs +6 -0
  37. package/dist/components/DataTableWithToolbar.d.mts +51 -0
  38. package/dist/components/DataTableWithToolbar.d.ts +51 -0
  39. package/dist/components/DataTableWithToolbar.js +24 -0
  40. package/dist/components/DataTableWithToolbar.mjs +9 -0
  41. package/dist/components/DonutChart.js +5 -5
  42. package/dist/components/DonutChart.mjs +3 -3
  43. package/dist/components/Dropdown.js +4 -4
  44. package/dist/components/Dropdown.mjs +2 -2
  45. package/dist/components/DropdownItem.js +4 -4
  46. package/dist/components/DropdownItem.mjs +3 -3
  47. package/dist/components/FormItem.js +2 -2
  48. package/dist/components/FormItem.mjs +1 -1
  49. package/dist/components/FormWizard.d.mts +10 -0
  50. package/dist/components/FormWizard.d.ts +10 -0
  51. package/dist/components/FormWizard.js +19 -0
  52. package/dist/components/FormWizard.mjs +4 -0
  53. package/dist/components/LineChart.js +4 -4
  54. package/dist/components/LineChart.mjs +2 -2
  55. package/dist/components/NotificationCenter.d.mts +8 -0
  56. package/dist/components/NotificationCenter.d.ts +8 -0
  57. package/dist/components/NotificationCenter.js +23 -0
  58. package/dist/components/NotificationCenter.mjs +8 -0
  59. package/dist/components/PieChart.js +4 -4
  60. package/dist/components/PieChart.mjs +2 -2
  61. package/dist/components/RadarChart.js +4 -4
  62. package/dist/components/RadarChart.mjs +2 -2
  63. package/dist/components/ScatterChart.js +4 -4
  64. package/dist/components/ScatterChart.mjs +2 -2
  65. package/dist/components/Table.d.mts +1 -1
  66. package/dist/components/Table.d.ts +1 -1
  67. package/dist/components/Table.js +2 -2
  68. package/dist/components/Table.mjs +1 -1
  69. package/dist/index.d.mts +6 -0
  70. package/dist/index.d.ts +6 -0
  71. package/dist/index.js +197 -167
  72. package/dist/index.mjs +49 -43
  73. package/package.json +2 -2
  74. package/dist/{chunk-ZYF5GI2Q.js → chunk-4PTI6ZUK.js} +1 -1
  75. package/dist/{chunk-LIJLFLYE.js → chunk-4TWHENPT.js} +1 -1
  76. package/dist/{chunk-67WZRMD6.js → chunk-6E5UKM6O.js} +1 -1
  77. package/dist/{chunk-AFFSBNYB.mjs → chunk-AITVDDCE.mjs} +1 -1
  78. package/dist/{chunk-324UKFG2.mjs → chunk-IL2Y5RCX.mjs} +1 -1
  79. package/dist/{chunk-7SOL3UJ2.js → chunk-L63N3LCG.js} +1 -1
  80. package/dist/{chunk-E6GLWHRL.mjs → chunk-LZNG2HGC.mjs} +1 -1
  81. package/dist/{chunk-2VXA4YOP.js → chunk-N32MAX4A.js} +1 -1
  82. package/dist/{chunk-RKBNIEGF.mjs → chunk-PT4WLSTJ.mjs} +1 -1
  83. package/dist/{chunk-LWW2LXCP.js → chunk-SIB4EHB6.js} +1 -1
  84. package/dist/{chunk-2WLSB7K2.mjs → chunk-WYTHTJN3.mjs} +1 -1
  85. package/dist/{chunk-5QKBBGIA.mjs → chunk-YER7IQF4.mjs} +1 -1
  86. package/dist/{chunk-7IKJBQQV.mjs → chunk-YGOTPK2W.mjs} +1 -1
  87. package/dist/{chunk-KKHKQP6Z.js → chunk-ZUUG3WOL.js} +1 -1
@@ -0,0 +1,255 @@
1
+ import { Tabs, TabPane } from './chunk-C52ZCGYG.mjs';
2
+ import { List } from './chunk-BAPR7UUR.mjs';
3
+ import { Button } from './chunk-STEIWBMF.mjs';
4
+ import { Loading } from './chunk-PUDU34R4.mjs';
5
+ import { Text } from './chunk-6YDIBMCM.mjs';
6
+ import { Card } from './chunk-VD3IK5XT.mjs';
7
+ import { useMemo, useState, useEffect } from 'react';
8
+ import { buildNotificationGroups, classNames, formatActivityTime } from '@expcat/tigercat-core';
9
+ import { jsx, jsxs } from 'react/jsx-runtime';
10
+
11
+ var getGroupKey = (group, index) => {
12
+ return group.key ?? group.title ?? index;
13
+ };
14
+ var filterItems = (items, filter) => {
15
+ return items.filter((item) => {
16
+ const isRead = Boolean(item.read);
17
+ if (filter === "read") return isRead;
18
+ if (filter === "unread") return !isRead;
19
+ return true;
20
+ });
21
+ };
22
+ var NotificationCenter = ({
23
+ items = [],
24
+ groups,
25
+ groupBy,
26
+ groupOrder,
27
+ activeGroupKey,
28
+ defaultActiveGroupKey,
29
+ readFilter,
30
+ defaultReadFilter = "all",
31
+ loading = false,
32
+ loadingText = "\u52A0\u8F7D\u4E2D...",
33
+ emptyText = "\u6682\u65E0\u901A\u77E5",
34
+ title = "\u901A\u77E5\u4E2D\u5FC3",
35
+ allLabel = "\u5168\u90E8",
36
+ unreadLabel = "\u672A\u8BFB",
37
+ readLabel = "\u5DF2\u8BFB",
38
+ markAllReadText = "\u5168\u90E8\u6807\u8BB0\u5DF2\u8BFB",
39
+ markReadText = "\u6807\u8BB0\u5DF2\u8BFB",
40
+ markUnreadText = "\u6807\u8BB0\u672A\u8BFB",
41
+ manageReadState = false,
42
+ onGroupChange,
43
+ onReadFilterChange,
44
+ onMarkAllRead,
45
+ onItemClick,
46
+ onItemReadChange,
47
+ className,
48
+ ...props
49
+ }) => {
50
+ const resolvedGroups = useMemo(
51
+ () => buildNotificationGroups(items, groups, groupBy, groupOrder),
52
+ [items, groups, groupBy, groupOrder]
53
+ );
54
+ const firstGroupKey = useMemo(() => {
55
+ return resolvedGroups.length > 0 ? getGroupKey(resolvedGroups[0], 0) : void 0;
56
+ }, [resolvedGroups]);
57
+ const [internalGroupKey, setInternalGroupKey] = useState(
58
+ defaultActiveGroupKey
59
+ );
60
+ const [internalReadFilter, setInternalReadFilter] = useState(defaultReadFilter);
61
+ const currentGroupKey = activeGroupKey ?? internalGroupKey ?? firstGroupKey;
62
+ const currentReadFilter = readFilter ?? internalReadFilter;
63
+ useEffect(() => {
64
+ if (activeGroupKey !== void 0) return;
65
+ if (resolvedGroups.length === 0) {
66
+ setInternalGroupKey(void 0);
67
+ return;
68
+ }
69
+ const keys = resolvedGroups.map((group, index) => getGroupKey(group, index));
70
+ if (!keys.some((key) => key === currentGroupKey)) {
71
+ setInternalGroupKey(keys[0]);
72
+ }
73
+ }, [activeGroupKey, currentGroupKey, resolvedGroups]);
74
+ const currentGroup = useMemo(() => {
75
+ if (resolvedGroups.length === 0) return void 0;
76
+ if (currentGroupKey === void 0) return resolvedGroups[0];
77
+ const index = resolvedGroups.findIndex(
78
+ (group, groupIndex) => getGroupKey(group, groupIndex) === currentGroupKey
79
+ );
80
+ return index >= 0 ? resolvedGroups[index] : resolvedGroups[0];
81
+ }, [currentGroupKey, resolvedGroups]);
82
+ currentGroup?.items ?? [];
83
+ const [readStateOverrides, setReadStateOverrides] = useState(
84
+ () => /* @__PURE__ */ new Map()
85
+ );
86
+ useEffect(() => {
87
+ if (manageReadState) setReadStateOverrides(/* @__PURE__ */ new Map());
88
+ }, [items, manageReadState]);
89
+ const applyReadOverrides = (list) => {
90
+ if (!manageReadState || readStateOverrides.size === 0) return list;
91
+ return list.map((item) => {
92
+ const override = readStateOverrides.get(item.id);
93
+ return override !== void 0 ? { ...item, read: override } : item;
94
+ });
95
+ };
96
+ const effectiveGroups = useMemo(
97
+ () => resolvedGroups.map((group) => ({
98
+ ...group,
99
+ items: applyReadOverrides(group.items)
100
+ })),
101
+ // eslint-disable-next-line react-hooks/exhaustive-deps
102
+ [resolvedGroups, readStateOverrides]
103
+ );
104
+ const effectiveCurrentGroup = useMemo(() => {
105
+ if (effectiveGroups.length === 0) return void 0;
106
+ if (currentGroupKey === void 0) return effectiveGroups[0];
107
+ const index = effectiveGroups.findIndex(
108
+ (group, groupIndex) => getGroupKey(group, groupIndex) === currentGroupKey
109
+ );
110
+ return index >= 0 ? effectiveGroups[index] : effectiveGroups[0];
111
+ }, [currentGroupKey, effectiveGroups]);
112
+ const effectiveCurrentGroupItems = effectiveCurrentGroup?.items ?? [];
113
+ const effectiveItems = useMemo(() => applyReadOverrides(items), [items, readStateOverrides]);
114
+ const hasUnread = effectiveCurrentGroupItems.some((item) => !item.read);
115
+ const totalUnread = useMemo(() => {
116
+ const allItems = effectiveGroups.flatMap((group) => group.items);
117
+ if (allItems.length === 0) return effectiveItems.filter((item) => !item.read).length;
118
+ return allItems.filter((item) => !item.read).length;
119
+ }, [effectiveGroups, effectiveItems]);
120
+ const wrapperClasses = useMemo(
121
+ () => classNames("tiger-notification-center", "w-full", "flex", "flex-col", className),
122
+ [className]
123
+ );
124
+ const handleGroupChange = (key) => {
125
+ if (activeGroupKey === void 0) {
126
+ setInternalGroupKey(key);
127
+ }
128
+ onGroupChange?.(key);
129
+ };
130
+ const handleReadFilterChange = (next) => {
131
+ if (readFilter === void 0) {
132
+ setInternalReadFilter(next);
133
+ }
134
+ onReadFilterChange?.(next);
135
+ };
136
+ const handleMarkAllRead = () => {
137
+ if (manageReadState) {
138
+ setReadStateOverrides((prev) => {
139
+ const next = new Map(prev);
140
+ effectiveCurrentGroupItems.forEach((item) => next.set(item.id, true));
141
+ return next;
142
+ });
143
+ }
144
+ onMarkAllRead?.(currentGroupKey, effectiveCurrentGroupItems);
145
+ };
146
+ const renderItem = (item, index) => {
147
+ const isRead = Boolean(item.read);
148
+ const timeText = item.time ? formatActivityTime(item.time) : "";
149
+ return /* @__PURE__ */ jsxs(
150
+ "div",
151
+ {
152
+ className: classNames(
153
+ "flex items-start gap-3 w-full py-0.5 transition-colors",
154
+ !isRead && "border-l-2 border-l-[var(--tiger-primary,#2563eb)] -ml-[2px] pl-[calc(0.75rem-2px)]"
155
+ ),
156
+ children: [
157
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
158
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-2", children: [
159
+ /* @__PURE__ */ jsx(Text, { tag: "span", size: "sm", weight: isRead ? "normal" : "semibold", children: item.title }),
160
+ timeText ? /* @__PURE__ */ jsx("span", { className: "text-xs text-[var(--tiger-text-muted,#6b7280)] whitespace-nowrap flex-shrink-0", children: timeText }) : null
161
+ ] }),
162
+ item.description ? /* @__PURE__ */ jsx("div", { className: "mt-0.5 text-xs text-[var(--tiger-text-muted,#6b7280)] line-clamp-2 leading-relaxed", children: item.description }) : null
163
+ ] }),
164
+ /* @__PURE__ */ jsx(
165
+ Button,
166
+ {
167
+ size: "sm",
168
+ variant: "ghost",
169
+ onClick: (event) => {
170
+ event.stopPropagation();
171
+ if (manageReadState) {
172
+ setReadStateOverrides((prev) => {
173
+ const next = new Map(prev);
174
+ next.set(item.id, !isRead);
175
+ return next;
176
+ });
177
+ }
178
+ onItemReadChange?.(item, !isRead);
179
+ },
180
+ children: isRead ? markUnreadText : markReadText
181
+ }
182
+ )
183
+ ]
184
+ }
185
+ );
186
+ };
187
+ const renderList = (listItems) => /* @__PURE__ */ jsx(
188
+ List,
189
+ {
190
+ dataSource: listItems,
191
+ split: true,
192
+ bordered: "divided",
193
+ hoverable: true,
194
+ emptyText,
195
+ onItemClick: (item, index) => onItemClick?.(item, index),
196
+ renderItem
197
+ }
198
+ );
199
+ const filterButtons = [
200
+ { key: "all", label: allLabel },
201
+ { key: "unread", label: unreadLabel },
202
+ { key: "read", label: readLabel }
203
+ ];
204
+ const content = loading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsx(Loading, { text: loadingText }) }) : resolvedGroups.length > 0 ? /* @__PURE__ */ jsx("div", { className: "-mx-4 -mb-4", children: /* @__PURE__ */ jsx(Tabs, { type: "line", size: "small", activeKey: currentGroupKey, onChange: handleGroupChange, children: resolvedGroups.map((group, index) => {
205
+ const effectiveGroup = effectiveGroups.find(
206
+ (eg, ei) => getGroupKey(eg, ei) === getGroupKey(group, index)
207
+ );
208
+ const groupItems = effectiveGroup?.items ?? group.items;
209
+ const unreadCount = groupItems.filter((item) => !item.read).length;
210
+ const labelBase = group.title || String(group.key ?? index);
211
+ const label = unreadCount > 0 ? `${labelBase} (${unreadCount})` : labelBase;
212
+ return /* @__PURE__ */ jsx(
213
+ TabPane,
214
+ {
215
+ tabKey: getGroupKey(group, index),
216
+ label,
217
+ children: /* @__PURE__ */ jsx("div", { className: "max-h-[380px] overflow-y-auto", children: renderList(filterItems(groupItems, currentReadFilter)) })
218
+ },
219
+ String(getGroupKey(group, index))
220
+ );
221
+ }) }) }) : /* @__PURE__ */ jsx("div", { className: "-mx-4 -mb-4 max-h-[380px] overflow-y-auto", children: renderList(filterItems(effectiveItems, currentReadFilter)) });
222
+ return /* @__PURE__ */ jsx("div", { className: wrapperClasses, ...props, "data-tiger-notification-center": true, children: /* @__PURE__ */ jsx(
223
+ Card,
224
+ {
225
+ variant: "bordered",
226
+ className: "w-full",
227
+ header: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
228
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
229
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
230
+ /* @__PURE__ */ jsx(Text, { tag: "div", size: "base", weight: "bold", children: title }),
231
+ totalUnread > 0 ? /* @__PURE__ */ jsx("span", { className: "inline-flex items-center justify-center min-w-[20px] h-5 px-1.5 text-xs font-semibold rounded-full bg-[var(--tiger-primary,#2563eb)] text-white", children: totalUnread }) : null
232
+ ] }),
233
+ /* @__PURE__ */ jsx(Button, { size: "sm", variant: "ghost", disabled: !hasUnread, onClick: handleMarkAllRead, children: markAllReadText })
234
+ ] }),
235
+ /* @__PURE__ */ jsx("div", { className: "inline-flex rounded-md border border-[var(--tiger-border,#e5e7eb)] overflow-hidden self-start", children: filterButtons.map((option) => /* @__PURE__ */ jsx(
236
+ "button",
237
+ {
238
+ className: classNames(
239
+ "px-3 py-1 text-xs font-medium transition-colors",
240
+ "border-r border-[var(--tiger-border,#e5e7eb)] last:border-r-0",
241
+ currentReadFilter === option.key ? "bg-[var(--tiger-primary,#2563eb)] text-white" : "bg-[var(--tiger-surface,#ffffff)] text-[var(--tiger-text-muted,#6b7280)] hover:bg-[var(--tiger-surface-muted,#f9fafb)]"
242
+ ),
243
+ onClick: () => handleReadFilterChange(option.key),
244
+ children: option.label
245
+ },
246
+ option.key
247
+ )) })
248
+ ] }),
249
+ children: content
250
+ }
251
+ ) });
252
+ };
253
+ var NotificationCenter_default = NotificationCenter;
254
+
255
+ export { NotificationCenter, NotificationCenter_default };
@@ -89,6 +89,7 @@ function Table({
89
89
  rowClassName,
90
90
  stickyHeader = false,
91
91
  maxHeight,
92
+ tableLayout = "auto",
92
93
  onChange,
93
94
  onRowClick,
94
95
  onSelectionChange,
@@ -657,7 +658,10 @@ function Table({
657
658
  /* @__PURE__ */ jsxRuntime.jsxs(
658
659
  "table",
659
660
  {
660
- className: tigercatCore.tableBaseClasses,
661
+ className: tigercatCore.classNames(
662
+ tigercatCore.tableBaseClasses,
663
+ tableLayout === "fixed" ? "table-fixed" : "table-auto"
664
+ ),
661
665
  ...props,
662
666
  style: fixedColumnsInfo.hasFixedColumns && fixedColumnsInfo.minTableWidth ? {
663
667
  ...props.style,
@@ -87,6 +87,7 @@ function Table({
87
87
  rowClassName,
88
88
  stickyHeader = false,
89
89
  maxHeight,
90
+ tableLayout = "auto",
90
91
  onChange,
91
92
  onRowClick,
92
93
  onSelectionChange,
@@ -655,7 +656,10 @@ function Table({
655
656
  /* @__PURE__ */ jsxs(
656
657
  "table",
657
658
  {
658
- className: tableBaseClasses,
659
+ className: classNames(
660
+ tableBaseClasses,
661
+ tableLayout === "fixed" ? "table-fixed" : "table-auto"
662
+ ),
659
663
  ...props,
660
664
  style: fixedColumnsInfo.hasFixedColumns && fixedColumnsInfo.minTableWidth ? {
661
665
  ...props.style,
@@ -0,0 +1,264 @@
1
+ 'use strict';
2
+
3
+ var chunkR7MS42PL_js = require('./chunk-R7MS42PL.js');
4
+ var chunkA3DJSVTE_js = require('./chunk-A3DJSVTE.js');
5
+ var chunk2TS6X5RA_js = require('./chunk-2TS6X5RA.js');
6
+ var chunkYYGTJKP5_js = require('./chunk-YYGTJKP5.js');
7
+ var chunkTZ26HQAW_js = require('./chunk-TZ26HQAW.js');
8
+ var react = require('react');
9
+ var tigercatCore = require('@expcat/tigercat-core');
10
+ var jsxRuntime = require('react/jsx-runtime');
11
+
12
+ var CommentThread = ({
13
+ nodes,
14
+ items,
15
+ maxDepth = 3,
16
+ maxReplies = 3,
17
+ defaultExpandedKeys = [],
18
+ expandedKeys,
19
+ emptyText = "\u6682\u65E0\u8BC4\u8BBA",
20
+ replyPlaceholder = "\u5199\u4E0B\u56DE\u590D...",
21
+ replyButtonText = "\u56DE\u590D",
22
+ cancelReplyText = "\u53D6\u6D88",
23
+ likeText = "\u70B9\u8D5E",
24
+ likedText = "\u5DF2\u8D5E",
25
+ replyText = "\u56DE\u590D",
26
+ moreText = "\u66F4\u591A",
27
+ loadMoreText = "\u52A0\u8F7D\u66F4\u591A",
28
+ showAvatar = true,
29
+ showDivider = true,
30
+ showLike = true,
31
+ showReply = true,
32
+ showMore = true,
33
+ onLike,
34
+ onReply,
35
+ onMore,
36
+ onAction,
37
+ onExpandedChange,
38
+ onLoadMore,
39
+ className,
40
+ ...divProps
41
+ }) => {
42
+ const [innerExpandedKeys, setInnerExpandedKeys] = react.useState(defaultExpandedKeys);
43
+ const [expandedAllKeys, setExpandedAllKeys] = react.useState(/* @__PURE__ */ new Set());
44
+ const [replyingTo, setReplyingTo] = react.useState(null);
45
+ const [replyValue, setReplyValue] = react.useState("");
46
+ const mergedExpandedKeys = expandedKeys ?? innerExpandedKeys;
47
+ const expandedSet = react.useMemo(
48
+ () => new Set(mergedExpandedKeys),
49
+ [mergedExpandedKeys]
50
+ );
51
+ const resolvedNodes = react.useMemo(() => {
52
+ const tree = nodes && nodes.length > 0 ? nodes : tigercatCore.buildCommentTree(items ?? []);
53
+ return tigercatCore.clipCommentTreeDepth(tree, maxDepth);
54
+ }, [nodes, items, maxDepth]);
55
+ const updateExpandedKeys = (next) => {
56
+ if (!expandedKeys) {
57
+ setInnerExpandedKeys(next);
58
+ }
59
+ onExpandedChange?.(next);
60
+ };
61
+ const toggleExpanded = (id) => {
62
+ const next = expandedSet.has(id) ? mergedExpandedKeys.filter((key) => key !== id) : [...mergedExpandedKeys, id];
63
+ updateExpandedKeys(next);
64
+ };
65
+ const handleLoadMore = (node) => {
66
+ setExpandedAllKeys((prev) => {
67
+ const next = new Set(prev);
68
+ next.add(node.id);
69
+ return next;
70
+ });
71
+ onLoadMore?.(node);
72
+ };
73
+ const handleReplySubmit = (node) => {
74
+ const trimmed = replyValue.trim();
75
+ if (!trimmed) return;
76
+ onReply?.(node, replyValue);
77
+ setReplyValue("");
78
+ setReplyingTo(null);
79
+ if (!expandedSet.has(node.id)) {
80
+ const next = [...mergedExpandedKeys, node.id];
81
+ updateExpandedKeys(next);
82
+ }
83
+ };
84
+ const BTN_BASE = "px-1.5 py-0.5 h-auto min-h-0 text-xs rounded";
85
+ const ACTION_BTN = `${BTN_BASE} text-gray-400 hover:text-gray-600 font-normal hover:bg-gray-50`;
86
+ const PRIMARY_BTN = `${BTN_BASE} text-[var(--tiger-primary,#2563eb)] hover:text-[var(--tiger-primary-hover,#1d4ed8)] font-medium hover:bg-[var(--tiger-primary,#2563eb)]/5`;
87
+ const renderActionButton = (label, key, onClick, active) => /* @__PURE__ */ jsxRuntime.jsx(
88
+ chunkA3DJSVTE_js.Button,
89
+ {
90
+ size: "sm",
91
+ variant: "ghost",
92
+ className: tigercatCore.classNames(
93
+ ACTION_BTN,
94
+ active && "text-[var(--tiger-primary,#2563eb)] hover:text-[var(--tiger-primary,#2563eb)] font-medium"
95
+ ),
96
+ onClick,
97
+ children: label
98
+ },
99
+ key
100
+ );
101
+ const renderNode = (node, depth, isLast) => {
102
+ const hasChildren = !!node.children && node.children.length > 0;
103
+ const isExpanded = expandedSet.has(node.id);
104
+ const showReplies = hasChildren && isExpanded;
105
+ const showAllReplies = expandedAllKeys.has(node.id);
106
+ const repliesId = `tiger-comment-replies-${node.id}`;
107
+ const visibleChildren = showReplies ? maxReplies > 0 && !showAllReplies ? node.children.slice(0, maxReplies) : node.children : [];
108
+ const showLoadMoreBtn = showReplies && maxReplies > 0 && node.children.length > maxReplies && !showAllReplies;
109
+ const actions = [];
110
+ if (showLike) {
111
+ const likeLabel = node.liked ? likedText : likeText;
112
+ const likeCount = node.likes ? ` ${node.likes}` : "";
113
+ actions.push(
114
+ renderActionButton(
115
+ `${likeLabel}${likeCount}`,
116
+ "like",
117
+ () => onLike?.(node, !node.liked),
118
+ node.liked
119
+ )
120
+ );
121
+ }
122
+ if (showReply) {
123
+ actions.push(
124
+ renderActionButton(replyText, "reply", () => {
125
+ setReplyingTo((prev) => prev === node.id ? null : node.id);
126
+ setReplyValue("");
127
+ })
128
+ );
129
+ }
130
+ if (showMore) {
131
+ actions.push(renderActionButton(moreText, "more", () => onMore?.(node)));
132
+ }
133
+ if (node.actions && node.actions.length > 0) {
134
+ node.actions.forEach((action, index) => {
135
+ const actionKey = action.key ?? `${node.id}-action-${index}`;
136
+ actions.push(
137
+ /* @__PURE__ */ jsxRuntime.jsx(
138
+ chunkA3DJSVTE_js.Button,
139
+ {
140
+ size: "sm",
141
+ variant: action.variant ?? "ghost",
142
+ className: ACTION_BTN,
143
+ disabled: action.disabled,
144
+ onClick: () => {
145
+ action.onClick?.(node, action);
146
+ onAction?.(node, action);
147
+ },
148
+ children: action.label
149
+ },
150
+ actionKey
151
+ )
152
+ );
153
+ });
154
+ }
155
+ return /* @__PURE__ */ jsxRuntime.jsx(
156
+ "div",
157
+ {
158
+ className: tigercatCore.classNames(
159
+ "tiger-comment-thread-item",
160
+ depth === 1 && "py-4",
161
+ depth === 1 && !isLast && showDivider && "border-b border-[var(--tiger-border,#e5e7eb)]"
162
+ ),
163
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3", children: [
164
+ showAvatar && node.user ? /* @__PURE__ */ jsxRuntime.jsx(
165
+ chunkTZ26HQAW_js.Avatar,
166
+ {
167
+ size: depth === 1 ? "md" : "sm",
168
+ src: node.user.avatar,
169
+ text: node.user.name,
170
+ className: "shrink-0 mt-0.5"
171
+ }
172
+ ) : null,
173
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
174
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
175
+ node.user?.name ? /* @__PURE__ */ jsxRuntime.jsx(chunkYYGTJKP5_js.Text, { tag: "span", size: "sm", weight: "bold", children: node.user.name }) : null,
176
+ node.user?.title ? /* @__PURE__ */ jsxRuntime.jsx(chunkYYGTJKP5_js.Text, { tag: "span", size: "xs", color: "muted", children: node.user.title }) : null,
177
+ node.tag ? /* @__PURE__ */ jsxRuntime.jsx(chunk2TS6X5RA_js.Tag, { size: "sm", variant: node.tag.variant ?? "default", children: node.tag.label }) : null,
178
+ node.tags?.map((tag, index) => /* @__PURE__ */ jsxRuntime.jsx(chunk2TS6X5RA_js.Tag, { size: "sm", variant: tag.variant ?? "default", children: tag.label }, `${node.id}-tag-${index}`)),
179
+ node.time ? /* @__PURE__ */ jsxRuntime.jsx(chunkYYGTJKP5_js.Text, { tag: "span", size: "xs", color: "muted", className: "ml-auto", children: tigercatCore.formatCommentTime(node.time) }) : null
180
+ ] }),
181
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-[var(--tiger-text-secondary,#4b5563)] leading-relaxed break-words mt-1.5 mb-2", children: node.content }),
182
+ actions.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-1", children: actions }) : null,
183
+ replyingTo === node.id ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 space-y-2 bg-[var(--tiger-surface-muted,#f9fafb)] p-3 rounded-lg", children: [
184
+ /* @__PURE__ */ jsxRuntime.jsx(
185
+ chunkR7MS42PL_js.Textarea,
186
+ {
187
+ rows: 2,
188
+ value: replyValue,
189
+ placeholder: replyPlaceholder,
190
+ className: "bg-[var(--tiger-surface,#ffffff)]",
191
+ onChange: (event) => setReplyValue(event.target.value)
192
+ }
193
+ ),
194
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 justify-end", children: [
195
+ /* @__PURE__ */ jsxRuntime.jsx(
196
+ chunkA3DJSVTE_js.Button,
197
+ {
198
+ size: "sm",
199
+ variant: "ghost",
200
+ onClick: () => {
201
+ setReplyingTo(null);
202
+ setReplyValue("");
203
+ },
204
+ children: cancelReplyText
205
+ }
206
+ ),
207
+ /* @__PURE__ */ jsxRuntime.jsx(chunkA3DJSVTE_js.Button, { size: "sm", variant: "primary", onClick: () => handleReplySubmit(node), children: replyButtonText })
208
+ ] })
209
+ ] }) : null,
210
+ hasChildren ? /* @__PURE__ */ jsxRuntime.jsx(
211
+ chunkA3DJSVTE_js.Button,
212
+ {
213
+ size: "sm",
214
+ variant: "ghost",
215
+ className: tigercatCore.classNames("mt-2", PRIMARY_BTN),
216
+ "aria-expanded": isExpanded,
217
+ "aria-controls": repliesId,
218
+ onClick: () => toggleExpanded(node.id),
219
+ children: isExpanded ? "\u25BE \u6536\u8D77\u56DE\u590D" : `\u25B8 \u5C55\u5F00 ${node.children.length} \u6761\u56DE\u590D`
220
+ }
221
+ ) : null,
222
+ showReplies ? /* @__PURE__ */ jsxRuntime.jsxs(
223
+ "div",
224
+ {
225
+ id: repliesId,
226
+ className: "mt-3 ml-1 pl-4 border-l-2 border-[var(--tiger-border,#e5e7eb)] space-y-3",
227
+ children: [
228
+ visibleChildren.map(
229
+ (child, index) => renderNode(child, depth + 1, index === visibleChildren.length - 1)
230
+ ),
231
+ showLoadMoreBtn ? /* @__PURE__ */ jsxRuntime.jsx(
232
+ chunkA3DJSVTE_js.Button,
233
+ {
234
+ size: "sm",
235
+ variant: "ghost",
236
+ className: PRIMARY_BTN,
237
+ onClick: () => handleLoadMore(node),
238
+ children: loadMoreText
239
+ }
240
+ ) : null
241
+ ]
242
+ }
243
+ ) : null
244
+ ] })
245
+ ] })
246
+ },
247
+ node.id
248
+ );
249
+ };
250
+ return /* @__PURE__ */ jsxRuntime.jsx(
251
+ "div",
252
+ {
253
+ className: tigercatCore.classNames("tiger-comment-thread flex flex-col", className),
254
+ "data-tiger-comment-thread": true,
255
+ "aria-label": divProps["aria-label"] ?? (divProps["aria-labelledby"] ? void 0 : "\u8BC4\u8BBA\u7EBF\u7A0B"),
256
+ ...divProps,
257
+ children: resolvedNodes.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(chunkYYGTJKP5_js.Text, { tag: "div", size: "sm", color: "muted", className: "text-center py-8", children: emptyText }) : resolvedNodes.map((node, index) => renderNode(node, 1, index === resolvedNodes.length - 1))
258
+ }
259
+ );
260
+ };
261
+ var CommentThread_default = CommentThread;
262
+
263
+ exports.CommentThread = CommentThread;
264
+ exports.CommentThread_default = CommentThread_default;
@@ -1,4 +1,4 @@
1
- import { DropdownContext } from './chunk-7IKJBQQV.mjs';
1
+ import { DropdownContext } from './chunk-YGOTPK2W.mjs';
2
2
  import { useContext } from 'react';
3
3
  import { classNames, getDropdownItemClasses } from '@expcat/tigercat-core';
4
4
  import { jsx } from 'react/jsx-runtime';