@expcat/tigercat-react 2.0.0-rc.1 → 2.0.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 (29) hide show
  1. package/dist/{chunk-IZYFETUS.mjs → chunk-3RY6M4AK.mjs} +1 -1
  2. package/dist/chunk-C6QK5MJT.mjs +292 -0
  3. package/dist/{chunk-44CQTGAN.mjs → chunk-E7OTDBI6.mjs} +2 -2
  4. package/dist/{chunk-DJ4PSDQS.mjs → chunk-FYINJRYN.mjs} +2 -2
  5. package/dist/{chunk-KFPQ6DIH.mjs → chunk-GV4F6X3C.mjs} +29 -25
  6. package/dist/{chunk-K6GJMKJR.mjs → chunk-HELLYIX2.mjs} +1 -1
  7. package/dist/{chunk-POP3TS4Q.mjs → chunk-NBQ3Q6DD.mjs} +56 -28
  8. package/dist/{chunk-3O2WHF3U.mjs → chunk-NCHUEGUW.mjs} +2 -2
  9. package/dist/{chunk-VD55SSP7.mjs → chunk-PD6Q36OO.mjs} +14 -6
  10. package/dist/{chunk-HXD7KMRP.mjs → chunk-UCBW5RJN.mjs} +31 -2
  11. package/dist/{chunk-5IHOOP5A.mjs → chunk-UD4DTVJZ.mjs} +64 -79
  12. package/dist/{chunk-A6JNS35U.mjs → chunk-UT5BV2VO.mjs} +2 -2
  13. package/dist/{chunk-N6JNLJIN.mjs → chunk-YCKY72BW.mjs} +5 -1
  14. package/dist/components/ActivityFeed.mjs +1 -1
  15. package/dist/components/AreaChart.mjs +1 -1
  16. package/dist/components/BarChart.mjs +1 -1
  17. package/dist/components/CommentThread.mjs +1 -1
  18. package/dist/components/CropUpload.mjs +2 -2
  19. package/dist/components/DataTableWithToolbar.mjs +2 -2
  20. package/dist/components/ImageCropper.mjs +1 -1
  21. package/dist/components/LineChart.mjs +1 -1
  22. package/dist/components/NotificationCenter.mjs +1 -1
  23. package/dist/components/ScatterChart.mjs +1 -1
  24. package/dist/components/Table.mjs +1 -1
  25. package/dist/components/Upload.mjs +1 -1
  26. package/dist/components/VirtualTable.mjs +1 -1
  27. package/dist/index.d.mts +1 -1
  28. package/package.json +3 -3
  29. package/dist/chunk-XIVU7TWX.mjs +0 -305
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-K7MYQISG.mjs";
4
4
  import {
5
5
  ImageCropper
6
- } from "./chunk-VD55SSP7.mjs";
6
+ } from "./chunk-PD6Q36OO.mjs";
7
7
  import {
8
8
  Button
9
9
  } from "./chunk-5TE7KLE5.mjs";
@@ -0,0 +1,292 @@
1
+ import {
2
+ Timeline
3
+ } from "./chunk-QB5472NM.mjs";
4
+ import {
5
+ Link
6
+ } from "./chunk-XZVQ3PJS.mjs";
7
+ import {
8
+ Loading
9
+ } from "./chunk-AJJJ6HWC.mjs";
10
+ import {
11
+ Tag
12
+ } from "./chunk-7EXOY7GD.mjs";
13
+ import {
14
+ Text
15
+ } from "./chunk-HLS4CHWX.mjs";
16
+ import {
17
+ Card
18
+ } from "./chunk-IXV5YBCZ.mjs";
19
+ import {
20
+ Avatar
21
+ } from "./chunk-OO562MFD.mjs";
22
+
23
+ // src/components/ActivityFeed.tsx
24
+ import { useMemo } from "react";
25
+ import {
26
+ classNames,
27
+ buildActivityGroups,
28
+ formatActivityTime,
29
+ toActivityTimelineItems,
30
+ activityItemClasses,
31
+ activityItemLayoutClasses,
32
+ activityItemBodyClasses,
33
+ activityItemHeaderClasses,
34
+ activityItemTitleGroupClasses,
35
+ activityItemDescriptionClasses,
36
+ activityItemActionsClasses
37
+ } from "@expcat/tigercat-core";
38
+
39
+ // ../core/src/internal/activity-feed-styles.ts
40
+ var activityFeedActionClasses = "tiger-motion-aware inline-flex items-center px-2.5 py-1 rounded-[var(--tiger-radius-md,0.5rem)] text-xs font-semibold text-[var(--tiger-primary,#2563eb)] hover:bg-[var(--tiger-outline-bg-hover,#eff6ff)] [transition:var(--tiger-transition-base,all_200ms_cubic-bezier(0.4,0,0.2,1))]";
41
+ var activityFeedItemSurfaceClasses = "tiger-motion-aware p-4 rounded-[var(--tiger-radius-xl,1rem)] border border-[var(--tiger-border,#e5e7eb)] bg-[var(--tiger-surface,#ffffff)] shadow-[var(--tiger-shadow-sm,0_1px_2px_rgb(0_0_0_/_0.05))] [transition:var(--tiger-transition-base,all_200ms_cubic-bezier(0.4,0,0.2,1))] hover:shadow-[var(--tiger-shadow-glass-strong,0_4px_6px_-1px_rgb(0_0_0_/_0.1))] hover:-translate-y-0.5 w-full";
42
+ var activityFeedAvatarClasses = "tiger-motion-aware shrink-0 ring-2 ring-[var(--tiger-surface,#ffffff)] shadow-[var(--tiger-shadow-sm,0_1px_2px_rgb(0_0_0_/_0.05))] [transition:var(--tiger-transition-base,all_200ms_cubic-bezier(0.4,0,0.2,1))] hover:scale-105";
43
+ var activityFeedTitleClasses = "tiger-motion-aware text-[var(--tiger-text,#111827)] hover:text-[var(--tiger-primary,#2563eb)] transition-colors cursor-pointer truncate";
44
+ var activityFeedTimeClasses = "shrink-0 whitespace-nowrap font-medium text-[var(--tiger-text-muted,#6b7280)]";
45
+ var activityFeedDescriptionClasses = "text-[var(--tiger-text-secondary,#4b5563)] leading-relaxed pl-0.5 mt-1";
46
+ var activityFeedStateCardClasses = "bg-[var(--tiger-surface,#ffffff)] border-[var(--tiger-border,#e5e7eb)] rounded-[var(--tiger-radius-xl,1rem)] shadow-[var(--tiger-shadow-sm,0_1px_2px_rgb(0_0_0_/_0.05))] overflow-hidden";
47
+ var activityFeedLoadingClasses = "text-[var(--tiger-primary,#2563eb)] font-medium";
48
+ var activityFeedEmptyIconClasses = "tiger-motion-aware w-12 h-12 text-[var(--tiger-text-muted,#9ca3af)] mb-3 animate-pulse";
49
+ var activityFeedGroupMarkerClasses = "w-1.5 h-3.5 bg-[var(--tiger-primary,#2563eb)] rounded-full shadow-sm";
50
+ var activityFeedGroupTitleClasses = "text-[var(--tiger-text,#111827)] uppercase tracking-wider";
51
+ var activityFeedDotBaseClasses = "w-3 h-3 rounded-full border-2 border-[var(--tiger-surface,#ffffff)] shadow-sm relative z-10";
52
+ var activityFeedDotPulseBaseClasses = "tiger-motion-aware absolute inline-flex h-full w-full rounded-full animate-ping opacity-75";
53
+ var dotVariantClasses = {
54
+ success: "bg-[var(--tiger-success,#16a34a)]",
55
+ warning: "bg-[var(--tiger-warning,#d97706)]",
56
+ error: "bg-[var(--tiger-error,#dc2626)]",
57
+ danger: "bg-[var(--tiger-error,#dc2626)]",
58
+ primary: "bg-[var(--tiger-primary,#2563eb)]",
59
+ info: "bg-[var(--tiger-primary,#2563eb)]"
60
+ };
61
+ var dotPulseVariantClasses = {
62
+ success: "bg-[var(--tiger-success,#16a34a)]/30",
63
+ warning: "bg-[var(--tiger-warning,#d97706)]/30",
64
+ error: "bg-[var(--tiger-error,#dc2626)]/30",
65
+ danger: "bg-[var(--tiger-error,#dc2626)]/30",
66
+ primary: "bg-[var(--tiger-primary,#2563eb)]/30",
67
+ info: "bg-[var(--tiger-primary,#2563eb)]/30"
68
+ };
69
+ var getActivityFeedDotClasses = (variant) => ({
70
+ dot: dotVariantClasses[variant ?? ""] ?? "bg-[var(--tiger-border,#d1d5db)]",
71
+ pulse: dotPulseVariantClasses[variant ?? ""] ?? ""
72
+ });
73
+
74
+ // src/components/ActivityFeed.tsx
75
+ import { jsx, jsxs } from "react/jsx-runtime";
76
+ var renderAction = (item, action, index) => {
77
+ const key = action.key ?? `${item.id}-action-${index}`;
78
+ return /* @__PURE__ */ jsx(
79
+ Link,
80
+ {
81
+ size: "sm",
82
+ variant: "primary",
83
+ underline: false,
84
+ href: action.href,
85
+ target: action.target,
86
+ disabled: action.disabled,
87
+ className: activityFeedActionClasses,
88
+ onClick: () => action.onClick?.(item, action),
89
+ children: action.label
90
+ },
91
+ key
92
+ );
93
+ };
94
+ var ActivityFeed = ({
95
+ items = [],
96
+ groups,
97
+ groupBy,
98
+ groupOrder,
99
+ loading = false,
100
+ loadingText = "\u52A0\u8F7D\u4E2D...",
101
+ emptyText = "\u6682\u65E0\u52A8\u6001",
102
+ showAvatar = true,
103
+ showTime = true,
104
+ showGroupTitle = true,
105
+ renderItem,
106
+ renderGroupHeader,
107
+ className,
108
+ ...props
109
+ }) => {
110
+ const resolvedGroups = useMemo(
111
+ () => buildActivityGroups(items, groups, groupBy, groupOrder),
112
+ [items, groups, groupBy, groupOrder]
113
+ );
114
+ const wrapperClasses = classNames(
115
+ "tiger-activity-feed",
116
+ "flex",
117
+ "flex-col",
118
+ "gap-6",
119
+ "w-full",
120
+ className
121
+ );
122
+ const renderDefaultItem = (item, index, group) => {
123
+ if (renderItem) return renderItem(item, index, group);
124
+ const titleText = item.title ?? (typeof item.content === "string" || typeof item.content === "number" ? String(item.content) : "");
125
+ const descriptionText = item.description;
126
+ const timeText = showTime ? formatActivityTime(item.time) : "";
127
+ const actionNodes = item.actions?.map(
128
+ (action, actionIndex) => renderAction(item, action, actionIndex)
129
+ );
130
+ return /* @__PURE__ */ jsx("div", { className: classNames(activityItemClasses, activityFeedItemSurfaceClasses), children: /* @__PURE__ */ jsxs("div", { className: activityItemLayoutClasses, children: [
131
+ showAvatar && item.user ? /* @__PURE__ */ jsx(
132
+ Avatar,
133
+ {
134
+ size: "sm",
135
+ src: item.user.avatar,
136
+ text: item.user.name,
137
+ className: activityFeedAvatarClasses
138
+ }
139
+ ) : null,
140
+ /* @__PURE__ */ jsxs("div", { className: activityItemBodyClasses, children: [
141
+ /* @__PURE__ */ jsxs("div", { className: activityItemHeaderClasses, children: [
142
+ /* @__PURE__ */ jsxs("div", { className: activityItemTitleGroupClasses, children: [
143
+ titleText ? /* @__PURE__ */ jsx(Text, { tag: "div", size: "sm", weight: "semibold", className: activityFeedTitleClasses, children: titleText }) : null,
144
+ item.status ? /* @__PURE__ */ jsx(
145
+ Tag,
146
+ {
147
+ variant: item.status.variant ?? "default",
148
+ size: "sm",
149
+ className: "shrink-0 rounded-full px-2 py-0.5 text-[10px] font-semibold tracking-wide uppercase border border-current bg-current/10 shadow-sm",
150
+ children: item.status.label
151
+ }
152
+ ) : null
153
+ ] }),
154
+ timeText ? /* @__PURE__ */ jsx(Text, { tag: "div", size: "xs", color: "muted", className: activityFeedTimeClasses, children: timeText }) : null
155
+ ] }),
156
+ descriptionText ? /* @__PURE__ */ jsx(
157
+ Text,
158
+ {
159
+ tag: "div",
160
+ size: "sm",
161
+ color: "muted",
162
+ className: classNames(
163
+ activityItemDescriptionClasses,
164
+ activityFeedDescriptionClasses
165
+ ),
166
+ children: descriptionText
167
+ }
168
+ ) : null,
169
+ actionNodes?.length ? /* @__PURE__ */ jsx("div", { className: classNames(activityItemActionsClasses, "mt-2.5"), children: actionNodes }) : null
170
+ ] })
171
+ ] }) });
172
+ };
173
+ if (loading) {
174
+ return /* @__PURE__ */ jsx(
175
+ "div",
176
+ {
177
+ className: wrapperClasses,
178
+ role: "feed",
179
+ "aria-label": "\u52A8\u6001",
180
+ "aria-busy": true,
181
+ ...props,
182
+ "data-tiger-activity-feed": true,
183
+ children: /* @__PURE__ */ jsx(
184
+ Card,
185
+ {
186
+ variant: "bordered",
187
+ size: "sm",
188
+ className: classNames("tiger-activity-feed-loading", activityFeedStateCardClasses),
189
+ children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsx(Loading, { text: loadingText, className: activityFeedLoadingClasses }) })
190
+ }
191
+ )
192
+ }
193
+ );
194
+ }
195
+ if (resolvedGroups.length === 0) {
196
+ return /* @__PURE__ */ jsx(
197
+ "div",
198
+ {
199
+ className: wrapperClasses,
200
+ role: "feed",
201
+ "aria-label": "\u52A8\u6001",
202
+ ...props,
203
+ "data-tiger-activity-feed": true,
204
+ children: /* @__PURE__ */ jsx(
205
+ Card,
206
+ {
207
+ variant: "bordered",
208
+ size: "sm",
209
+ className: classNames("tiger-activity-feed-empty", activityFeedStateCardClasses),
210
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-12 px-4", children: [
211
+ /* @__PURE__ */ jsx(
212
+ "svg",
213
+ {
214
+ className: activityFeedEmptyIconClasses,
215
+ fill: "none",
216
+ viewBox: "0 0 24 24",
217
+ stroke: "currentColor",
218
+ strokeWidth: "1.5",
219
+ children: /* @__PURE__ */ jsx(
220
+ "path",
221
+ {
222
+ strokeLinecap: "round",
223
+ strokeLinejoin: "round",
224
+ d: "M12 7.5h1.5m-1.5 3h1.5m-7.5 3h10.5m-10.5 3h10.5m-13.5-9h16.5M3 5.25h18M3 18.75h18"
225
+ }
226
+ )
227
+ }
228
+ ),
229
+ /* @__PURE__ */ jsx(Text, { tag: "div", size: "sm", color: "muted", className: "font-medium", children: emptyText })
230
+ ] })
231
+ }
232
+ )
233
+ }
234
+ );
235
+ }
236
+ return /* @__PURE__ */ jsx(
237
+ "div",
238
+ {
239
+ className: wrapperClasses,
240
+ role: "feed",
241
+ "aria-label": "\u52A8\u6001",
242
+ ...props,
243
+ "data-tiger-activity-feed": true,
244
+ children: resolvedGroups.map((group, groupIndex) => {
245
+ const headerNode = renderGroupHeader?.(group);
246
+ const groupTitle = group.title;
247
+ const timelineItems = toActivityTimelineItems(group.items);
248
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
249
+ showGroupTitle && groupTitle ? headerNode ?? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-2", children: [
250
+ /* @__PURE__ */ jsx("span", { className: activityFeedGroupMarkerClasses }),
251
+ /* @__PURE__ */ jsx(
252
+ Text,
253
+ {
254
+ tag: "span",
255
+ size: "sm",
256
+ weight: "bold",
257
+ className: activityFeedGroupTitleClasses,
258
+ children: groupTitle
259
+ }
260
+ )
261
+ ] }) : null,
262
+ /* @__PURE__ */ jsx(
263
+ Timeline,
264
+ {
265
+ items: timelineItems,
266
+ renderDot: (timelineItem) => {
267
+ const activity = timelineItem.activity;
268
+ const statusVariant = activity?.status?.variant ?? "default";
269
+ const dotClasses = getActivityFeedDotClasses(statusVariant);
270
+ return /* @__PURE__ */ jsxs("div", { className: "relative flex items-center justify-center w-4 h-4", children: [
271
+ dotClasses.pulse ? /* @__PURE__ */ jsx("span", { className: `${activityFeedDotPulseBaseClasses} ${dotClasses.pulse}` }) : null,
272
+ /* @__PURE__ */ jsx("span", { className: `${activityFeedDotBaseClasses} ${dotClasses.dot}` })
273
+ ] });
274
+ },
275
+ renderItem: (timelineItem, index) => {
276
+ const activity = timelineItem.activity;
277
+ if (!activity) return null;
278
+ return renderDefaultItem(activity, index, group);
279
+ }
280
+ }
281
+ )
282
+ ] }, group.key ?? groupIndex);
283
+ })
284
+ }
285
+ );
286
+ };
287
+ var ActivityFeed_default = ActivityFeed;
288
+
289
+ export {
290
+ ActivityFeed,
291
+ ActivityFeed_default
292
+ };
@@ -353,12 +353,12 @@ var ScatterChart = ({
353
353
  }
354
354
  );
355
355
  if (!showLegend) {
356
- return /* @__PURE__ */ jsxs("div", { className: "inline-block relative", children: [
356
+ return /* @__PURE__ */ jsxs("div", { className: classNames("relative", responsive ? "block w-full min-w-0" : "inline-block"), children: [
357
357
  chart,
358
358
  tooltip
359
359
  ] });
360
360
  }
361
- return /* @__PURE__ */ jsxs("div", { className: wrapperClasses, children: [
361
+ return /* @__PURE__ */ jsxs("div", { className: classNames(wrapperClasses, responsive && "w-full min-w-0"), children: [
362
362
  chart,
363
363
  /* @__PURE__ */ jsx(
364
364
  ChartLegend,
@@ -566,12 +566,12 @@ var AreaChart = ({
566
566
  }
567
567
  );
568
568
  if (!showLegend) {
569
- return /* @__PURE__ */ jsxs("div", { className: "inline-block relative", children: [
569
+ return /* @__PURE__ */ jsxs("div", { className: classNames("relative", responsive ? "block w-full min-w-0" : "inline-block"), children: [
570
570
  chart,
571
571
  tooltip
572
572
  ] });
573
573
  }
574
- return /* @__PURE__ */ jsxs("div", { className: wrapperClasses, children: [
574
+ return /* @__PURE__ */ jsxs("div", { className: classNames(wrapperClasses, responsive && "w-full min-w-0"), children: [
575
575
  chart,
576
576
  /* @__PURE__ */ jsx(
577
577
  ChartLegend,
@@ -178,7 +178,7 @@ var VirtualTable = ({
178
178
  })
179
179
  ),
180
180
  style: { ...widthStyle, ...stickyStyle },
181
- children: col.title ?? ""
181
+ children: col.renderHeader ? col.renderHeader() : col.title ?? ""
182
182
  },
183
183
  col.key
184
184
  );
@@ -215,30 +215,34 @@ var VirtualTable = ({
215
215
  } : void 0,
216
216
  children: [
217
217
  colRange && colRange.leftPad > 0 && /* @__PURE__ */ jsx("td", { "aria-hidden": true, style: { width: `${colRange.leftPad}px`, padding: 0 } }),
218
- visibleColumns.map((col, colIdx) => /* @__PURE__ */ jsx(
219
- "td",
220
- {
221
- "aria-colindex": colIndexOffset + colIdx + 1,
222
- className: classNames(
223
- virtualTableCellClasses,
224
- getTableFixedCellClasses({
225
- view: "virtual-table",
226
- column: col,
227
- record: row,
228
- rowIndex: globalIdx,
229
- striped,
230
- stripedActive: striped && globalIdx % 2 === 1,
231
- selected: isSelected,
232
- hoverable: true,
233
- fixedInfo,
234
- selectedClassName: virtualTableFixedCellSelectedClasses
235
- })
236
- ),
237
- style: getVirtualTableFixedCellStyle(col.key, fixedInfo),
238
- children: renderCell ? renderCell(row[col.key], row, col) : String(row[col.key] ?? "")
239
- },
240
- col.key
241
- )),
218
+ visibleColumns.map((col, colIdx) => {
219
+ const dataKey = col.dataKey || col.key;
220
+ const value = row[dataKey];
221
+ return /* @__PURE__ */ jsx(
222
+ "td",
223
+ {
224
+ "aria-colindex": colIndexOffset + colIdx + 1,
225
+ className: classNames(
226
+ virtualTableCellClasses,
227
+ getTableFixedCellClasses({
228
+ view: "virtual-table",
229
+ column: col,
230
+ record: row,
231
+ rowIndex: globalIdx,
232
+ striped,
233
+ stripedActive: striped && globalIdx % 2 === 1,
234
+ selected: isSelected,
235
+ hoverable: true,
236
+ fixedInfo,
237
+ selectedClassName: virtualTableFixedCellSelectedClasses
238
+ })
239
+ ),
240
+ style: getVirtualTableFixedCellStyle(col.key, fixedInfo),
241
+ children: renderCell ? renderCell(value, row, col) : col.render ? col.render(row, globalIdx) : value
242
+ },
243
+ col.key
244
+ );
245
+ }),
242
246
  colRange && colRange.rightPad > 0 && /* @__PURE__ */ jsx("td", { "aria-hidden": true, style: { width: `${colRange.rightPad}px`, padding: 0 } })
243
247
  ]
244
248
  },
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Table
3
- } from "./chunk-N6JNLJIN.mjs";
3
+ } from "./chunk-YCKY72BW.mjs";
4
4
  import {
5
5
  Select
6
6
  } from "./chunk-PAN256RW.mjs";
@@ -25,6 +25,34 @@ import {
25
25
  buildNotificationGroups,
26
26
  formatActivityTime
27
27
  } from "@expcat/tigercat-core";
28
+
29
+ // ../core/src/internal/notification-center-styles.ts
30
+ var notificationCenterItemClasses = "tiger-motion-aware group relative flex items-start gap-3.5 w-full p-3.5 rounded-[var(--tiger-radius-lg,0.75rem)] hover:bg-[var(--tiger-surface-muted,#f9fafb)] [transition:var(--tiger-transition-base,all_200ms_cubic-bezier(0.4,0,0.2,1))]";
31
+ var notificationCenterUnreadItemClasses = "bg-[var(--tiger-outline-bg-hover,#eff6ff)] border-l-[3px] border-l-[var(--tiger-primary,#2563eb)] -ml-[3px] pl-[calc(0.875rem-3px)]";
32
+ var notificationCenterReadItemClasses = "border-l-[3px] border-l-transparent -ml-[3px] pl-[calc(0.875rem-3px)]";
33
+ var notificationCenterReadTitleClasses = "text-[var(--tiger-text-secondary,#4b5563)]";
34
+ var notificationCenterUnreadTitleClasses = "text-[var(--tiger-text,#111827)]";
35
+ var notificationCenterUnreadDotClasses = "tiger-motion-aware w-1.5 h-1.5 rounded-full bg-[var(--tiger-primary,#2563eb)] shrink-0 shadow-sm animate-pulse";
36
+ var notificationCenterTimeClasses = "text-[11px] text-[var(--tiger-text-muted,#6b7280)] font-medium whitespace-nowrap flex-shrink-0 self-center";
37
+ var notificationCenterReadDescriptionClasses = "text-[var(--tiger-text-muted,#6b7280)]";
38
+ var notificationCenterUnreadDescriptionClasses = "text-[var(--tiger-text-secondary,#4b5563)]";
39
+ var notificationCenterItemActionClasses = "tiger-motion-aware opacity-0 group-hover:opacity-100 focus:opacity-100 rounded-full px-2.5 py-1 text-[11px] font-semibold bg-[var(--tiger-surface-muted,#f3f4f6)] hover:bg-[var(--tiger-fill-hover,#e5e7eb)] text-[var(--tiger-text-secondary,#374151)] border-0 flex-shrink-0 self-center [transition:var(--tiger-transition-base,all_200ms_cubic-bezier(0.4,0,0.2,1))]";
40
+ var notificationCenterEmptyIconWrapperClasses = "p-3.5 bg-[var(--tiger-surface-muted,#f9fafb)] rounded-full mb-3 shadow-inner";
41
+ var notificationCenterEmptyIconClasses = "tiger-motion-aware w-8 h-8 text-[var(--tiger-text-muted,#9ca3af)] animate-pulse";
42
+ var notificationCenterEmptyTextClasses = "font-semibold text-[var(--tiger-text-muted,#6b7280)]";
43
+ var notificationCenterLoadingClasses = "text-[var(--tiger-primary,#2563eb)] font-medium";
44
+ var notificationCenterCardClasses = "tiger-motion-aware w-full rounded-[var(--tiger-radius-xl,1rem)] border border-[var(--tiger-border,#e5e7eb)] bg-[var(--tiger-surface,#ffffff)] shadow-[var(--tiger-shadow-glass,0_8px_30px_rgb(0_0_0_/_0.04))] [transition:var(--tiger-transition-base,all_200ms_cubic-bezier(0.4,0,0.2,1))] overflow-hidden";
45
+ var notificationCenterTitleClasses = "text-[var(--tiger-text,#111827)]";
46
+ var notificationCenterUnreadBadgeClasses = "tiger-motion-aware inline-flex items-center justify-center min-w-[20px] h-5 px-1.5 text-[11px] font-bold rounded-full bg-[var(--tiger-primary,#2563eb)] text-white shadow-sm animate-pulse";
47
+ var notificationCenterMarkAllBaseClasses = "tiger-motion-aware text-xs font-semibold transition-colors";
48
+ var notificationCenterMarkAllEnabledClasses = "text-[var(--tiger-primary,#2563eb)] hover:text-[var(--tiger-primary-hover,#1d4ed8)]";
49
+ var notificationCenterMarkAllDisabledClasses = "text-[var(--tiger-text-muted,#9ca3af)]";
50
+ var notificationCenterFilterGroupClasses = "inline-flex items-center gap-0.5 p-0.5 rounded-[var(--tiger-radius-md,0.5rem)] bg-[var(--tiger-surface-muted,#f3f4f6)] self-start";
51
+ var notificationCenterFilterButtonClasses = "tiger-motion-aware px-3.5 py-1 text-xs font-semibold rounded-[var(--tiger-radius-sm,0.375rem)] [transition:var(--tiger-transition-base,all_200ms_cubic-bezier(0.4,0,0.2,1))]";
52
+ var notificationCenterFilterActiveClasses = "bg-[var(--tiger-surface,#ffffff)] text-[var(--tiger-text,#111827)] shadow-sm";
53
+ var notificationCenterFilterIdleClasses = "text-[var(--tiger-text-muted,#6b7280)] hover:text-[var(--tiger-text,#111827)]";
54
+
55
+ // src/components/NotificationCenter.tsx
28
56
  import { jsx, jsxs } from "react/jsx-runtime";
29
57
  var getGroupKey = (group, index) => {
30
58
  return group.key ?? group.title ?? index;
@@ -193,8 +221,8 @@ var NotificationCenter = ({
193
221
  "div",
194
222
  {
195
223
  className: classNames(
196
- "group relative flex items-start gap-3.5 w-full p-3.5 rounded-xl transition-all duration-300 hover:bg-gray-50/60 dark:hover:bg-gray-800/30",
197
- !isRead ? "bg-blue-50/20 dark:bg-blue-950/5 hover:bg-blue-50/40 dark:hover:bg-blue-950/10 border-l-[3px] border-l-blue-500/80 -ml-[3px] pl-[calc(0.875rem-3px)]" : "border-l-[3px] border-l-transparent -ml-[3px] pl-[calc(0.875rem-3px)]"
224
+ notificationCenterItemClasses,
225
+ isRead ? notificationCenterReadItemClasses : notificationCenterUnreadItemClasses
198
226
  ),
199
227
  children: [
200
228
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
@@ -206,20 +234,20 @@ var NotificationCenter = ({
206
234
  tag: "span",
207
235
  size: "sm",
208
236
  weight: isRead ? "normal" : "semibold",
209
- className: isRead ? "text-gray-600 dark:text-gray-400" : "text-gray-900 dark:text-gray-100",
237
+ className: isRead ? notificationCenterReadTitleClasses : notificationCenterUnreadTitleClasses,
210
238
  children: item.title
211
239
  }
212
240
  ),
213
- !isRead && /* @__PURE__ */ jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-blue-500 dark:bg-blue-400 shrink-0 shadow-sm shadow-blue-500/40 animate-pulse" })
241
+ !isRead && /* @__PURE__ */ jsx("span", { className: notificationCenterUnreadDotClasses })
214
242
  ] }),
215
- timeText ? /* @__PURE__ */ jsx("span", { className: "text-[11px] text-gray-400 dark:text-gray-500 font-medium whitespace-nowrap flex-shrink-0 self-center", children: timeText }) : null
243
+ timeText ? /* @__PURE__ */ jsx("span", { className: notificationCenterTimeClasses, children: timeText }) : null
216
244
  ] }),
217
245
  item.description ? /* @__PURE__ */ jsx(
218
246
  "div",
219
247
  {
220
248
  className: classNames(
221
249
  "mt-1 text-xs leading-relaxed line-clamp-2",
222
- isRead ? "text-gray-500 dark:text-gray-400" : "text-gray-600 dark:text-gray-300"
250
+ isRead ? notificationCenterReadDescriptionClasses : notificationCenterUnreadDescriptionClasses
223
251
  ),
224
252
  children: item.description
225
253
  }
@@ -230,7 +258,7 @@ var NotificationCenter = ({
230
258
  {
231
259
  size: "sm",
232
260
  variant: "ghost",
233
- className: "opacity-0 group-hover:opacity-100 focus:opacity-100 rounded-full px-2.5 py-1 text-[11px] font-semibold transition-all duration-200 bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300 border-0 flex-shrink-0 self-center",
261
+ className: notificationCenterItemActionClasses,
234
262
  onClick: (event) => {
235
263
  event.stopPropagation();
236
264
  if (manageReadState) {
@@ -252,10 +280,10 @@ var NotificationCenter = ({
252
280
  const renderList = (listItems) => {
253
281
  if (listItems.length === 0) {
254
282
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-14 px-4 text-center", children: [
255
- /* @__PURE__ */ jsx("div", { className: "p-3.5 bg-gray-50 dark:bg-gray-900 rounded-full mb-3 shadow-inner", children: /* @__PURE__ */ jsx(
283
+ /* @__PURE__ */ jsx("div", { className: notificationCenterEmptyIconWrapperClasses, children: /* @__PURE__ */ jsx(
256
284
  "svg",
257
285
  {
258
- className: "w-8 h-8 text-gray-400 dark:text-gray-600 animate-pulse",
286
+ className: notificationCenterEmptyIconClasses,
259
287
  fill: "none",
260
288
  viewBox: "0 0 24 24",
261
289
  stroke: "currentColor",
@@ -270,16 +298,7 @@ var NotificationCenter = ({
270
298
  )
271
299
  }
272
300
  ) }),
273
- /* @__PURE__ */ jsx(
274
- Text,
275
- {
276
- tag: "div",
277
- size: "sm",
278
- color: "muted",
279
- className: "font-semibold text-gray-400 dark:text-gray-500",
280
- children: emptyText
281
- }
282
- )
301
+ /* @__PURE__ */ jsx(Text, { tag: "div", size: "sm", color: "muted", className: notificationCenterEmptyTextClasses, children: emptyText })
283
302
  ] });
284
303
  }
285
304
  return /* @__PURE__ */ jsx(
@@ -295,7 +314,16 @@ var NotificationCenter = ({
295
314
  }
296
315
  );
297
316
  };
298
- const content = loading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-16", children: /* @__PURE__ */ jsx(Loading, { text: loadingText, className: "text-blue-500 dark:text-blue-400 font-medium" }) }) : resolvedGroups.length > 0 ? /* @__PURE__ */ jsx("div", { className: "-mx-4 -mb-4", children: /* @__PURE__ */ jsx(Tabs, { type: "line", size: "small", activeKey: currentGroupKey, onActiveKeyChange: handleGroupChange, children: groupTabData.map((tab) => /* @__PURE__ */ jsx(TabPane, { tabKey: tab.key, label: tab.label, children: /* @__PURE__ */ jsx("div", { className: "max-h-[380px] overflow-y-auto", children: renderList(tab.filteredItems) }) }, String(tab.key))) }) }) : /* @__PURE__ */ jsx("div", { className: "-mx-4 -mb-4 max-h-[380px] overflow-y-auto", children: renderList(filteredFlatItems) });
317
+ const content = loading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-16", children: /* @__PURE__ */ jsx(Loading, { text: loadingText, className: notificationCenterLoadingClasses }) }) : resolvedGroups.length > 0 ? /* @__PURE__ */ jsx("div", { className: "-mx-4 -mb-4", children: /* @__PURE__ */ jsx(
318
+ Tabs,
319
+ {
320
+ type: "line",
321
+ size: "small",
322
+ activeKey: currentGroupKey,
323
+ onActiveKeyChange: handleGroupChange,
324
+ children: groupTabData.map((tab) => /* @__PURE__ */ jsx(TabPane, { tabKey: tab.key, label: tab.label, children: /* @__PURE__ */ jsx("div", { className: "max-h-[380px] overflow-y-auto", children: renderList(tab.filteredItems) }) }, String(tab.key)))
325
+ }
326
+ ) }) : /* @__PURE__ */ jsx("div", { className: "-mx-4 -mb-4 max-h-[380px] overflow-y-auto", children: renderList(filteredFlatItems) });
299
327
  return /* @__PURE__ */ jsx(
300
328
  "div",
301
329
  {
@@ -308,7 +336,7 @@ var NotificationCenter = ({
308
336
  Card,
309
337
  {
310
338
  variant: "bordered",
311
- className: "w-full rounded-2xl border border-gray-100/80 dark:border-gray-800/80 bg-white/95 dark:bg-gray-950/90 backdrop-blur-md shadow-[0_8px_30px_rgb(0,0,0,0.04)] dark:shadow-[0_8px_30px_rgb(0,0,0,0.2)] transition-all duration-300 overflow-hidden",
339
+ className: notificationCenterCardClasses,
312
340
  header: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
313
341
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
314
342
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
@@ -318,11 +346,11 @@ var NotificationCenter = ({
318
346
  tag: "div",
319
347
  size: "base",
320
348
  weight: "bold",
321
- className: "text-gray-900 dark:text-gray-100",
349
+ className: notificationCenterTitleClasses,
322
350
  children: title
323
351
  }
324
352
  ),
325
- totalUnread > 0 ? /* @__PURE__ */ jsx("span", { className: "inline-flex items-center justify-center min-w-[20px] h-5 px-1.5 text-[11px] font-bold rounded-full bg-gradient-to-r from-blue-500 to-indigo-600 text-white shadow-sm shadow-blue-500/20 animate-pulse", children: totalUnread }) : null
353
+ totalUnread > 0 ? /* @__PURE__ */ jsx("span", { className: notificationCenterUnreadBadgeClasses, children: totalUnread }) : null
326
354
  ] }),
327
355
  /* @__PURE__ */ jsx(
328
356
  Button,
@@ -332,19 +360,19 @@ var NotificationCenter = ({
332
360
  disabled: !hasUnread,
333
361
  onClick: handleMarkAllRead,
334
362
  className: classNames(
335
- "text-xs font-semibold transition-colors duration-200",
336
- hasUnread ? "text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300" : "text-gray-400 dark:text-gray-600"
363
+ notificationCenterMarkAllBaseClasses,
364
+ hasUnread ? notificationCenterMarkAllEnabledClasses : notificationCenterMarkAllDisabledClasses
337
365
  ),
338
366
  children: markAllReadText
339
367
  }
340
368
  )
341
369
  ] }),
342
- /* @__PURE__ */ jsx("div", { className: "inline-flex items-center gap-0.5 p-0.5 rounded-lg bg-gray-100/80 dark:bg-gray-800/60 self-start", children: filterButtons.map((option) => /* @__PURE__ */ jsx(
370
+ /* @__PURE__ */ jsx("div", { className: notificationCenterFilterGroupClasses, children: filterButtons.map((option) => /* @__PURE__ */ jsx(
343
371
  "button",
344
372
  {
345
373
  className: classNames(
346
- "px-3.5 py-1 text-xs font-semibold rounded-md transition-all duration-200",
347
- currentReadFilter === option.key ? "bg-white dark:bg-gray-700 text-gray-900 dark:text-white shadow-sm scale-102" : "text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white"
374
+ notificationCenterFilterButtonClasses,
375
+ currentReadFilter === option.key ? notificationCenterFilterActiveClasses : notificationCenterFilterIdleClasses
348
376
  ),
349
377
  onClick: () => handleReadFilterChange(option.key),
350
378
  children: option.label
@@ -528,12 +528,12 @@ var LineChart = ({
528
528
  }
529
529
  );
530
530
  if (!showLegend) {
531
- return /* @__PURE__ */ jsxs("div", { className: "inline-block relative", children: [
531
+ return /* @__PURE__ */ jsxs("div", { className: classNames("relative", responsive ? "block w-full min-w-0" : "inline-block"), children: [
532
532
  chart,
533
533
  tooltip
534
534
  ] });
535
535
  }
536
- return /* @__PURE__ */ jsxs("div", { className: wrapperClasses, children: [
536
+ return /* @__PURE__ */ jsxs("div", { className: classNames(wrapperClasses, responsive && "w-full min-w-0"), children: [
537
537
  chart,
538
538
  /* @__PURE__ */ jsx(
539
539
  ChartLegend,
@@ -31,6 +31,7 @@ import {
31
31
  mergeTigerLocale
32
32
  } from "@expcat/tigercat-core";
33
33
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
34
+ var isPositiveFinite = (value) => Number.isFinite(value) && value > 0;
34
35
  var ImageCropper = forwardRef(
35
36
  ({
36
37
  src,
@@ -70,16 +71,23 @@ var ImageCropper = forwardRef(
70
71
  }, [displayWidth, displayHeight]);
71
72
  useEffect(() => {
72
73
  setImageLoaded(false);
74
+ imageRef.current = null;
73
75
  const img = new window.Image();
74
76
  img.crossOrigin = "anonymous";
75
77
  img.onload = () => {
76
- imageRef.current = img;
78
+ const naturalWidth = img.naturalWidth;
79
+ const naturalHeight = img.naturalHeight;
80
+ if (!isPositiveFinite(naturalWidth) || !isPositiveFinite(naturalHeight)) return;
77
81
  const container = containerRef.current;
78
- const containerW = container ? container.clientWidth : img.naturalWidth;
79
- const containerH = container ? container.clientHeight || 400 : img.naturalHeight;
80
- const ratio = Math.min(containerW / img.naturalWidth, containerH / img.naturalHeight, 1);
81
- const dw = img.naturalWidth * ratio;
82
- const dh = img.naturalHeight * ratio;
82
+ const measuredWidth = container?.clientWidth ?? 0;
83
+ const measuredHeight = container?.clientHeight ?? 0;
84
+ const containerW = isPositiveFinite(measuredWidth) ? measuredWidth : naturalWidth;
85
+ const containerH = isPositiveFinite(measuredHeight) ? measuredHeight : 400;
86
+ const ratio = Math.min(containerW / naturalWidth, containerH / naturalHeight, 1);
87
+ const dw = naturalWidth * ratio;
88
+ const dh = naturalHeight * ratio;
89
+ if (!isPositiveFinite(ratio) || !isPositiveFinite(dw) || !isPositiveFinite(dh)) return;
90
+ imageRef.current = img;
83
91
  setDisplayWidth(dw);
84
92
  setDisplayHeight(dh);
85
93
  displayDimsRef.current = { w: dw, h: dh };