@alfadocs/ui-kit-debug 0.2.0 → 0.2.2

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 (64) hide show
  1. package/dist/_chunks/{chat-input-DOlsB1fm.js → chat-input-Bov-gkwP.js} +40 -38
  2. package/dist/_chunks/{chat-input-DOlsB1fm.js.map → chat-input-Bov-gkwP.js.map} +1 -1
  3. package/dist/_chunks/{combobox-DCNXqbC7.js → combobox-BLWruOxK.js} +74 -75
  4. package/dist/_chunks/combobox-BLWruOxK.js.map +1 -0
  5. package/dist/_chunks/{freemium-paywall-CnvceDav.js → freemium-paywall-CrVefV0M.js} +2 -2
  6. package/dist/_chunks/{freemium-paywall-CnvceDav.js.map → freemium-paywall-CrVefV0M.js.map} +1 -1
  7. package/dist/_chunks/{leo-sidebar-CfEY-xi2.js → leo-sidebar-kHO45M6C.js} +2 -2
  8. package/dist/_chunks/{leo-sidebar-CfEY-xi2.js.map → leo-sidebar-kHO45M6C.js.map} +1 -1
  9. package/dist/_chunks/{link-8QmFjIz2.js → link-BcYW1eNM.js} +48 -32
  10. package/dist/_chunks/link-BcYW1eNM.js.map +1 -0
  11. package/dist/_chunks/{message-card-ChCX9Iv6.js → message-card-DjvsB_3U.js} +12 -12
  12. package/dist/_chunks/message-card-DjvsB_3U.js.map +1 -0
  13. package/dist/_chunks/{message-tray-n8q9ITXI.js → message-tray-BbnAzlLH.js} +23 -23
  14. package/dist/_chunks/{message-tray-n8q9ITXI.js.map → message-tray-BbnAzlLH.js.map} +1 -1
  15. package/dist/_chunks/{notification-card-hBlPN1-c.js → notification-card-uTPEvAQS.js} +21 -21
  16. package/dist/_chunks/notification-card-uTPEvAQS.js.map +1 -0
  17. package/dist/_chunks/{notification-tray-C5cnXbl9.js → notification-tray-PGtMqXbP.js} +56 -56
  18. package/dist/_chunks/{notification-tray-C5cnXbl9.js.map → notification-tray-PGtMqXbP.js.map} +1 -1
  19. package/dist/_chunks/{payment-form-C3vT_npe.js → payment-form-B_BdHwjb.js} +21 -21
  20. package/dist/_chunks/{payment-form-C3vT_npe.js.map → payment-form-B_BdHwjb.js.map} +1 -1
  21. package/dist/_chunks/transaction-chip-DE6DITun.js +196 -0
  22. package/dist/_chunks/transaction-chip-DE6DITun.js.map +1 -0
  23. package/dist/agent-catalog.json +15 -1
  24. package/dist/components/chat-input/chat-input.d.ts.map +1 -1
  25. package/dist/components/chat-input/index.js +1 -1
  26. package/dist/components/combobox/combobox.d.ts.map +1 -1
  27. package/dist/components/combobox/index.js +1 -1
  28. package/dist/components/freemium-paywall/index.js +1 -1
  29. package/dist/components/index.d.ts +1 -0
  30. package/dist/components/index.d.ts.map +1 -1
  31. package/dist/components/link/index.js +1 -1
  32. package/dist/components/link/link.d.ts +1 -0
  33. package/dist/components/link/link.d.ts.map +1 -1
  34. package/dist/components/message-card/index.js +1 -1
  35. package/dist/components/message-card/message-card.d.ts.map +1 -1
  36. package/dist/components/message-tray/index.js +1 -1
  37. package/dist/components/message-tray/message-tray.d.ts.map +1 -1
  38. package/dist/components/notification-card/index.js +1 -1
  39. package/dist/components/notification-card/notification-card.d.ts.map +1 -1
  40. package/dist/components/notification-tray/index.js +1 -1
  41. package/dist/components/notification-tray/notification-tray.d.ts.map +1 -1
  42. package/dist/components/payment-form/index.js +1 -1
  43. package/dist/components/transaction-chip/index.d.ts +3 -0
  44. package/dist/components/transaction-chip/index.d.ts.map +1 -0
  45. package/dist/components/transaction-chip/index.js +5 -0
  46. package/dist/components/transaction-chip/index.js.map +1 -0
  47. package/dist/components/transaction-chip/transaction-chip.d.ts +30 -0
  48. package/dist/components/transaction-chip/transaction-chip.d.ts.map +1 -0
  49. package/dist/i18n/config.js +36 -0
  50. package/dist/i18n/config.js.map +1 -1
  51. package/dist/i18n/resources.d.ts +36 -0
  52. package/dist/i18n/resources.d.ts.map +1 -1
  53. package/dist/index.js +34 -32
  54. package/dist/index.js.map +1 -1
  55. package/dist/locales/de.json +12 -0
  56. package/dist/locales/en.json +12 -0
  57. package/dist/locales/it.json +12 -0
  58. package/dist/patterns/leo-assistant/index.js +1 -1
  59. package/dist/tokens.css +1 -1
  60. package/package.json +1 -1
  61. package/dist/_chunks/combobox-DCNXqbC7.js.map +0 -1
  62. package/dist/_chunks/link-8QmFjIz2.js.map +0 -1
  63. package/dist/_chunks/message-card-ChCX9Iv6.js.map +0 -1
  64. package/dist/_chunks/notification-card-hBlPN1-c.js.map +0 -1
@@ -6,8 +6,8 @@ import { useTranslation as W } from "react-i18next";
6
6
  import { I as ue } from "./icon-button-C4CGcYuz.js";
7
7
  import { B as _ } from "./button-DD_0Xdmr.js";
8
8
  import { S as U } from "./separator-CYU_bGFn.js";
9
- import { S as g } from "./skeleton-CZbwyJAA.js";
10
- import { M as pe } from "./message-card-ChCX9Iv6.js";
9
+ import { S as f } from "./skeleton-CZbwyJAA.js";
10
+ import { M as pe } from "./message-card-DjvsB_3U.js";
11
11
  import { u as ge } from "./registry-C9nwlNyL.js";
12
12
  import { M as Y } from "./mail-C8irm52s.js";
13
13
  const fe = {
@@ -162,12 +162,12 @@ function R() {
162
162
  "aria-hidden": "true",
163
163
  className: "ds:flex ds:items-start ds:gap-[var(--spacing-sm)] ds:p-[var(--spacing-sm)]",
164
164
  children: [
165
- /* @__PURE__ */ s(g, { variant: "circular", size: "sm" }),
165
+ /* @__PURE__ */ s(f, { variant: "circular", size: "sm" }),
166
166
  /* @__PURE__ */ c("div", { className: "ds:flex-1 ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]", children: [
167
- /* @__PURE__ */ s(g, { variant: "text", size: "md", width: "60%" }),
168
- /* @__PURE__ */ s(g, { variant: "text", size: "sm", width: "80%" }),
169
- /* @__PURE__ */ s(g, { variant: "text", size: "sm", width: "95%" }),
170
- /* @__PURE__ */ s(g, { variant: "text", size: "sm", width: "30%" })
167
+ /* @__PURE__ */ s(f, { variant: "text", size: "md", width: "60%" }),
168
+ /* @__PURE__ */ s(f, { variant: "text", size: "sm", width: "80%" }),
169
+ /* @__PURE__ */ s(f, { variant: "text", size: "sm", width: "95%" }),
170
+ /* @__PURE__ */ s(f, { variant: "text", size: "sm", width: "30%" })
171
171
  ] })
172
172
  ]
173
173
  }
@@ -202,10 +202,10 @@ const Te = oe(
202
202
  items: t,
203
203
  unreadCount: T,
204
204
  open: k,
205
- onOpenChange: f,
205
+ onOpenChange: v,
206
206
  onItemClick: u,
207
207
  onDismiss: p,
208
- onMarkRead: v,
208
+ onMarkRead: y,
209
209
  onMarkAllRead: C,
210
210
  loading: G = !1,
211
211
  maxVisible: J,
@@ -218,12 +218,12 @@ const Te = oe(
218
218
  ...D
219
219
  }, ee) => {
220
220
  var A;
221
- const { t: d } = W(), N = k !== void 0, [se, ae] = q(!1), z = N ? k : se, y = F(
221
+ const { t: d } = W(), N = k !== void 0, [se, ae] = q(!1), z = N ? k : se, h = F(
222
222
  (e) => {
223
- N || ae(e), f == null || f(e);
223
+ N || ae(e), v == null || v(e);
224
224
  },
225
- [N, f]
226
- ), [h, I] = q(
225
+ [N, v]
226
+ ), [g, I] = q(
227
227
  () => t.map((e) => ({ item: e, leaving: !1 }))
228
228
  ), K = F(() => {
229
229
  if (typeof window > "u") return 200;
@@ -246,12 +246,12 @@ const Te = oe(
246
246
  return o;
247
247
  });
248
248
  }, [t]), H(() => {
249
- if (!h.some((n) => n.leaving)) return;
249
+ if (!g.some((n) => n.leaving)) return;
250
250
  const e = K(), r = setTimeout(() => {
251
251
  I((n) => n.filter((o) => !o.leaving));
252
252
  }, e);
253
253
  return () => clearTimeout(r);
254
- }, [h, K]);
254
+ }, [g, K]);
255
255
  const M = m(null), O = m((A = t[0]) == null ? void 0 : A.id);
256
256
  H(() => {
257
257
  var n;
@@ -279,8 +279,8 @@ const Te = oe(
279
279
  P.current = z;
280
280
  const ie = le(
281
281
  () => ({
282
- open: () => y(!0),
283
- close: () => y(!1),
282
+ open: () => h(!0),
283
+ close: () => h(!1),
284
284
  isOpen: () => P.current,
285
285
  getItems: () => l.current.map((e) => ({ id: e.id, read: !!e.read })),
286
286
  getUnreadCount: () => V.current ?? l.current.filter((e) => !e.read).length,
@@ -290,14 +290,14 @@ const Te = oe(
290
290
  },
291
291
  markRead: (e) => {
292
292
  const r = l.current.find((n) => n.id === e);
293
- r && (v == null || v(r));
293
+ r && (y == null || y(r));
294
294
  },
295
295
  dismiss: (e) => {
296
296
  const r = l.current.find((n) => n.id === e);
297
297
  r && (p == null || p(r));
298
298
  }
299
299
  }),
300
- [y, u, v, p]
300
+ [h, u, y, p]
301
301
  ), B = m(null);
302
302
  return me(ee, () => B.current, []), ge(fe, ie, a), /* @__PURE__ */ s(
303
303
  "div",
@@ -307,7 +307,7 @@ const Te = oe(
307
307
  "data-component-id": a,
308
308
  className: [ve({ size: w }), $].filter(Boolean).join(" "),
309
309
  ...D,
310
- children: /* @__PURE__ */ c(b.Root, { open: z, onOpenChange: y, children: [
310
+ children: /* @__PURE__ */ c(b.Root, { open: z, onOpenChange: h, children: [
311
311
  /* @__PURE__ */ s(b.Trigger, { asChild: !0, children: /* @__PURE__ */ s(
312
312
  ue,
313
313
  {
@@ -364,14 +364,14 @@ const Te = oe(
364
364
  /* @__PURE__ */ s(
365
365
  "div",
366
366
  {
367
- role: "list",
367
+ role: g.length > 0 ? "list" : void 0,
368
368
  "data-max-visible": J,
369
369
  className: "ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:overflow-y-auto ds:pt-[var(--spacing-xs)] ds:flex-1 ds:sm:flex-none ds:sm:[max-block-size:var(--message-tray-max-block-size,26rem)]",
370
370
  children: G ? /* @__PURE__ */ c(L, { children: [
371
371
  /* @__PURE__ */ s(R, {}),
372
372
  /* @__PURE__ */ s(R, {}),
373
373
  /* @__PURE__ */ s(R, {})
374
- ] }) : h.length === 0 ? /* @__PURE__ */ s(be, {}) : h.map(({ item: e, leaving: r }) => /* @__PURE__ */ s(
374
+ ] }) : g.length === 0 ? /* @__PURE__ */ s(be, {}) : g.map(({ item: e, leaving: r }) => /* @__PURE__ */ s(
375
375
  pe,
376
376
  {
377
377
  item: e,
@@ -411,4 +411,4 @@ export {
411
411
  Te as M,
412
412
  fe as m
413
413
  };
414
- //# sourceMappingURL=message-tray-n8q9ITXI.js.map
414
+ //# sourceMappingURL=message-tray-BbnAzlLH.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"message-tray-n8q9ITXI.js","sources":["../../src/components/message-tray/message-tray.agent.ts","../../src/components/message-tray/message-tray.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — MessageTray. */\n/* */\n/* Tray-level surface: open/close the inbox panel, read message ids and */\n/* unread flag (never sender names / subjects / previews — those are */\n/* PHI), and route per-message operations through the curated handle. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { MessageTrayHandle } from './message-tray';\n\nexport const messageTrayAgent: AgentAdapter<MessageTrayHandle> = {\n id: 'message-tray',\n capabilities: ['open', 'close', 'select_single', 'dismiss'],\n state: {\n items: {\n type: 'Array<{ id: string; read: boolean }>',\n descriptionKey: 'ui.agent.messageTray.state.items',\n description:\n 'Currently-displayed messages. Ids + read flag only — no PHI / no sender names.',\n read: (handle) => handle.getItems(),\n },\n unreadCount: {\n type: 'number',\n descriptionKey: 'ui.agent.messageTray.state.unreadCount',\n description: 'Badge unread count surfaced by the host.',\n read: (handle) => handle.getUnreadCount(),\n },\n isOpen: {\n type: 'boolean',\n descriptionKey: 'ui.agent.messageTray.state.isOpen',\n description: 'Whether the dropdown panel is currently open.',\n read: (handle) => handle.isOpen(),\n },\n },\n actions: {\n open: {\n safety: 'read',\n descriptionKey: 'ui.agent.messageTray.actions.open',\n description: 'Open the message panel.',\n invoke: (handle) => {\n handle.open();\n },\n },\n close: {\n safety: 'read',\n descriptionKey: 'ui.agent.messageTray.actions.close',\n description: 'Close the message panel.',\n invoke: (handle) => {\n handle.close();\n },\n },\n select_item: {\n safety: 'read',\n argsType: '{ id: string }',\n descriptionKey: 'ui.agent.messageTray.actions.selectItem',\n description: 'Activate the message with the given id.',\n invoke: (handle, args: { id: string }) => {\n handle.selectItem(args.id);\n },\n },\n mark_read: {\n safety: 'write',\n argsType: '{ id: string }',\n descriptionKey: 'ui.agent.messageTray.actions.markRead',\n description: 'Request the host to mark a message as read.',\n invoke: (handle, args: { id: string }) => {\n handle.markRead(args.id);\n },\n },\n dismiss: {\n safety: 'destructive',\n argsType: '{ id: string }',\n descriptionKey: 'ui.agent.messageTray.actions.dismiss',\n description:\n 'Request the host to dismiss / archive the message with the given id.',\n invoke: (handle, args: { id: string }) => {\n handle.dismiss(args.id);\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'message-tray',\n description: 'Marks the MessageTray wrapper.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description:\n 'Sourced from the id prop. Required to address a specific tray from the agent.',\n },\n item: {\n attr: 'data-message-id',\n description:\n 'Stable message id emitted on each rendered MessageCard inside the tray.',\n },\n },\n};\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type HTMLAttributes,\n} from 'react';\nimport * as RadixPopover from '@radix-ui/react-popover';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Mail } from 'lucide-react';\nimport { IconButton } from '../button/icon-button';\nimport { Button } from '../button/button';\nimport { Separator } from '../separator/separator';\nimport { Skeleton } from '../skeleton/skeleton';\nimport { MessageCard, type MessageItem } from '../message-card/message-card';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { messageTrayAgent } from './message-tray.agent';\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\n/**\n * Curated imperative handle for MessageTray. Exposed as the forwardRef\n * target so a future agent / MCP UI bridge can drive the tray without\n * touching the DOM. See `message-tray.agent.ts`.\n */\nexport interface MessageTrayHandle {\n open: () => void;\n close: () => void;\n isOpen: () => boolean;\n getItems: () => Array<{ id: string; read: boolean }>;\n getUnreadCount: () => number;\n selectItem: (id: string) => void;\n markRead: (id: string) => void;\n dismiss: (id: string) => void;\n}\n\nexport interface MessageTrayProps\n extends\n Omit<\n HTMLAttributes<HTMLDivElement>,\n 'onClick' | 'children' | 'role' | 'id'\n >,\n VariantProps<typeof messageTrayVariants> {\n /**\n * Stable instance id. Surfaced on the root as `data-component-id` so\n * an agent / MCP UI bridge can address this specific tray.\n */\n id?: string;\n /** Fires when the host should mark a single message as read (used by agent integration). */\n onMarkRead?: (item: MessageItem) => void;\n /** Messages rendered in the dropdown panel. */\n items: MessageItem[];\n /** Number of unread messages. Drives the badge count. */\n unreadCount?: number;\n /** Controlled open state. */\n open?: boolean;\n /** Fires when the open state changes. */\n onOpenChange?: (open: boolean) => void;\n /** Fires when the user activates an item (click or Enter/Space). */\n onItemClick?: (item: MessageItem) => void;\n /** Fires when the user dismisses / archives a message. */\n onDismiss?: (item: MessageItem) => void;\n /** Fires when the user clicks the header \"Mark all as read\" action. */\n onMarkAllRead?: () => void;\n /** When true the panel shows skeleton placeholders. */\n loading?: boolean;\n /**\n * Advisory item count before the list scrolls. Consumers override the cap\n * via the `--message-tray-max-block-size` custom property.\n */\n maxVisible?: number;\n /** When set renders a footer link that invokes `onViewAll`. */\n viewAllLabel?: string;\n /** Fires when the footer \"View all\" link is clicked. */\n onViewAll?: () => void;\n /** Panel alignment relative to the trigger. Default `'end'`. */\n align?: 'start' | 'center' | 'end';\n /** Side of the trigger to open on. Default `'bottom'`. */\n side?: 'top' | 'bottom';\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst messageTrayVariants = cva('ds:relative ds:inline-flex ds:items-center', {\n variants: {\n size: {\n sm: '',\n md: '',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n});\n\nconst panelVariants = cva(\n [\n 'ds:flex ds:flex-col',\n 'ds:bg-[var(--popover)] ds:text-[var(--popover-foreground)]',\n 'ds:border ds:border-[color:var(--border)]',\n 'ds:rounded-[var(--radius-md)]',\n 'ds:shadow-[var(--shadow-lg)]',\n 'ds:z-[var(--z-popover)]',\n // Width: fluid below the design cap so narrow viewports keep a visible\n // gutter on both sides (shadow included). Cap slightly wider than\n // NotificationTray because message rows carry subject + preview.\n 'ds:w-[min(26rem,calc(100vw-2*var(--spacing-md)))]',\n // Height: below the `sm` breakpoint the panel takes a near-full-screen\n // sheet shape so the user gets room to triage an inbox without\n // scrolling a tiny popover. `6rem` reserves space for the Header\n // (≈4rem) plus the sideOffset + collisionPadding (≈2rem). Above `sm`\n // it returns to `h-auto` so the list's own cap governs the height.\n 'ds:h-[calc(100dvh-6rem)] ds:sm:h-auto',\n 'ds:data-[state=open]:animate-in ds:data-[state=closed]:animate-out',\n 'ds:data-[state=closed]:fade-out-0 ds:data-[state=open]:fade-in-0',\n 'ds:data-[state=closed]:zoom-out-95 ds:data-[state=open]:zoom-in-95',\n 'ds:motion-reduce:transition-none ds:motion-reduce:animate-none',\n 'ds:focus-visible:outline-none',\n 'ds:forced-colors:border-[CanvasText]',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:p-[var(--spacing-xs)]',\n md: 'ds:p-[var(--spacing-sm)]',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n },\n);\n\nconst badgeVariants = cva(\n [\n 'ds:absolute ds:-top-[var(--spacing-xs)] ds:-end-[var(--spacing-xs)]',\n 'ds:inline-flex ds:items-center ds:justify-center',\n 'ds:min-w-[calc(var(--spacing-md)+var(--spacing-xs))] ds:h-[calc(var(--spacing-md)+var(--spacing-xs))] ds:ps-[calc(var(--spacing-xs)/1.5)] ds:pe-[calc(var(--spacing-xs)/1.5)]',\n 'ds:rounded-[var(--radius-full)]',\n 'ds:bg-[color:var(--destructive)] ds:text-[color:var(--destructive-foreground)]',\n 'ds:text-[length:var(--font-size-xs)] ds:font-semibold ds:leading-none',\n 'ds:pointer-events-none ds:select-none',\n 'ds:forced-colors:outline ds:forced-colors:outline-1 ds:forced-colors:outline-[CanvasText]',\n ].join(' '),\n);\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\nfunction formatBadgeCount(count: number, overflowLabel: string): string {\n return count > 99 ? overflowLabel : String(count);\n}\n\nfunction SkeletonRow() {\n return (\n <div\n aria-hidden=\"true\"\n className=\"ds:flex ds:items-start ds:gap-[var(--spacing-sm)] ds:p-[var(--spacing-sm)]\"\n >\n <Skeleton variant=\"circular\" size=\"sm\" />\n <div className=\"ds:flex-1 ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <Skeleton variant=\"text\" size=\"md\" width=\"60%\" />\n <Skeleton variant=\"text\" size=\"sm\" width=\"80%\" />\n <Skeleton variant=\"text\" size=\"sm\" width=\"95%\" />\n <Skeleton variant=\"text\" size=\"sm\" width=\"30%\" />\n </div>\n </div>\n );\n}\n\nfunction EmptyPanel() {\n const { t } = useTranslation();\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className=\"ds:flex ds:flex-col ds:items-center ds:justify-center ds:gap-[var(--spacing-xs)] ds:p-[var(--spacing-lg)] ds:text-center\"\n >\n <span\n aria-hidden=\"true\"\n className=\"ds:inline-flex ds:items-center ds:justify-center ds:size-10 ds:rounded-[var(--radius-full)] ds:bg-[color:var(--muted)] ds:text-[color:var(--muted-foreground)] ds:[&>svg]:size-5\"\n >\n <Mail />\n </span>\n <p className=\"type-title-item ds:text-[color:var(--foreground)]\">\n {t('ui.messageTray.noMessages', 'No messages')}\n </p>\n <p className=\"type-meta ds:text-[color:var(--muted-foreground)]\">\n {t('ui.messageTray.noMessagesDescription', 'Your inbox is clear.')}\n </p>\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Root */\n/* ------------------------------------------------------------------ */\n\nexport const MessageTray = forwardRef<HTMLDivElement, MessageTrayProps>(\n (\n {\n id,\n items,\n unreadCount,\n open,\n onOpenChange,\n onItemClick,\n onDismiss,\n onMarkRead,\n onMarkAllRead,\n loading = false,\n maxVisible,\n viewAllLabel,\n onViewAll,\n align = 'end',\n side = 'bottom',\n size = 'md',\n className,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation();\n\n const isControlled = open !== undefined;\n const [internalOpen, setInternalOpen] = useState(false);\n const isOpen = isControlled ? open : internalOpen;\n\n const handleOpenChange = useCallback(\n (next: boolean) => {\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange],\n );\n\n /* Exit-animation list — same AnimatePresence-style bookkeeping as\n * NotificationTray. See that component for rationale. */\n type Displayed = { item: MessageItem; leaving: boolean };\n const [displayed, setDisplayed] = useState<Displayed[]>(() =>\n items.map((item) => ({ item, leaving: false })),\n );\n\n const animationDurationMs = useCallback((): number => {\n if (typeof window === 'undefined') return 200;\n const raw = window\n .getComputedStyle(document.documentElement)\n .getPropertyValue('--animation-duration');\n if (!raw) return 200;\n const trimmed = raw.trim();\n const n = parseFloat(trimmed);\n if (!Number.isFinite(n)) return 200;\n return trimmed.endsWith('ms') ? n : n * 1000;\n }, []);\n\n useLayoutEffect(() => {\n setDisplayed((prev) => {\n const nextIds = new Set(items.map((i) => i.id));\n const prevIds = new Set(prev.map((d) => d.item.id));\n\n const merged: Displayed[] = prev.map((d) => {\n if (nextIds.has(d.item.id)) {\n const fresh = items.find((i) => i.id === d.item.id);\n return fresh\n ? { item: fresh, leaving: false }\n : { ...d, leaving: true };\n }\n return { ...d, leaving: true };\n });\n\n for (const i of items) {\n if (!prevIds.has(i.id)) merged.push({ item: i, leaving: false });\n }\n return merged;\n });\n }, [items]);\n\n useEffect(() => {\n if (!displayed.some((d) => d.leaving)) return;\n const ms = animationDurationMs();\n const timer = setTimeout(() => {\n setDisplayed((prev) => prev.filter((d) => !d.leaving));\n }, ms);\n return () => clearTimeout(timer);\n }, [displayed, animationDurationMs]);\n\n const liveRegionRef = useRef<HTMLDivElement | null>(null);\n const lastTopIdRef = useRef<string | undefined>(items[0]?.id);\n\n useEffect(() => {\n const topId = items[0]?.id;\n const prev = lastTopIdRef.current;\n if (prev && topId && prev !== topId && liveRegionRef.current) {\n const newest = items[0];\n if (newest && !newest.read) {\n liveRegionRef.current.textContent = t('ui.messageTray.newMessage', {\n sender: newest.sender.name,\n defaultValue: 'New message from {{sender}}',\n });\n }\n }\n lastTopIdRef.current = topId;\n }, [items, t]);\n\n const displayCount = unreadCount ?? 0;\n const triggerAriaLabel =\n displayCount > 0\n ? t('ui.messageTray.triggerLabel', {\n count: displayCount,\n defaultValue: 'Messages, {{count}} unread',\n })\n : t('ui.messageTray.triggerLabelNone', 'Messages, none unread');\n\n const badgeLabel = formatBadgeCount(\n displayCount,\n t('ui.messageTray.badgeCountOverflow', '99+'),\n );\n\n const panelClass = panelVariants({ size });\n\n /* Curated imperative handle for agent integration. See\n * message-tray.agent.ts. */\n const itemsRef = useRef<MessageItem[]>(items);\n itemsRef.current = items;\n const unreadRef = useRef<number | undefined>(unreadCount);\n unreadRef.current = unreadCount;\n const isOpenRef = useRef<boolean>(isOpen);\n isOpenRef.current = isOpen;\n\n const handle = useMemo<MessageTrayHandle>(\n () => ({\n open: () => handleOpenChange(true),\n close: () => handleOpenChange(false),\n isOpen: () => isOpenRef.current,\n getItems: () =>\n itemsRef.current.map((i) => ({ id: i.id, read: !!i.read })),\n getUnreadCount: () =>\n unreadRef.current ?? itemsRef.current.filter((i) => !i.read).length,\n selectItem: (targetId: string) => {\n const found = itemsRef.current.find((i) => i.id === targetId);\n if (found) onItemClick?.(found);\n },\n markRead: (targetId: string) => {\n const found = itemsRef.current.find((i) => i.id === targetId);\n if (found) onMarkRead?.(found);\n },\n dismiss: (targetId: string) => {\n const found = itemsRef.current.find((i) => i.id === targetId);\n if (found) onDismiss?.(found);\n },\n }),\n [handleOpenChange, onItemClick, onMarkRead, onDismiss],\n );\n\n const rootRef = useRef<HTMLDivElement>(null);\n useImperativeHandle(ref, () => rootRef.current as HTMLDivElement, []);\n useAgentRegistration(messageTrayAgent, handle, id);\n\n return (\n <div\n ref={rootRef}\n data-component=\"message-tray\"\n data-component-id={id}\n className={[messageTrayVariants({ size }), className]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n >\n <RadixPopover.Root open={isOpen} onOpenChange={handleOpenChange}>\n <RadixPopover.Trigger asChild>\n <IconButton\n icon={<Mail />}\n intent=\"outline\"\n size={size === 'sm' ? 'sm' : 'md'}\n aria-label={triggerAriaLabel}\n aria-haspopup=\"dialog\"\n />\n </RadixPopover.Trigger>\n {displayCount > 0 ? (\n <span\n aria-hidden=\"true\"\n data-testid=\"message-tray-badge\"\n className={badgeVariants()}\n >\n {badgeLabel}\n </span>\n ) : null}\n <div\n ref={liveRegionRef}\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"ds:sr-only\"\n />\n <RadixPopover.Portal>\n <RadixPopover.Content\n role=\"dialog\"\n aria-label={t('ui.messageTray.panelTitle', 'Messages')}\n side={side}\n align={align}\n sideOffset={8}\n // `spacing-md` (16px) keeps Radix's collision-avoidance from\n // flush-mounting the panel against the viewport edge when the\n // trigger is near the inline-end of a narrow screen.\n collisionPadding={16}\n className={panelClass}\n >\n <div className=\"ds:flex ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)] ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:pb-[var(--spacing-xs)]\">\n <h3 className=\"ds:m-0 type-title-card ds:text-[color:var(--foreground)]\">\n {t('ui.messageTray.panelTitle', 'Messages')}\n </h3>\n {onMarkAllRead && items.some((item) => !item.read) ? (\n <Button\n intent=\"link\"\n size=\"sm\"\n onClick={onMarkAllRead}\n className=\"ds:text-[length:var(--font-size-xs)]\"\n >\n {t('ui.messageTray.markAllRead', 'Mark all as read')}\n </Button>\n ) : null}\n </div>\n <Separator />\n <div\n role=\"list\"\n data-max-visible={maxVisible}\n // Below `sm` the panel is a near-full-screen sheet (see\n // `panelVariants`) and the list expands to fill the\n // remaining space with `flex-1`. Above `sm` the list\n // caps at the `--message-tray-max-block-size` custom\n // property so the popover stays compact.\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:overflow-y-auto ds:pt-[var(--spacing-xs)] ds:flex-1 ds:sm:flex-none ds:sm:[max-block-size:var(--message-tray-max-block-size,26rem)]\"\n >\n {loading ? (\n <>\n <SkeletonRow />\n <SkeletonRow />\n <SkeletonRow />\n </>\n ) : displayed.length === 0 ? (\n <EmptyPanel />\n ) : (\n displayed.map(({ item, leaving }) => (\n <MessageCard\n key={item.id}\n item={item}\n variant=\"compact\"\n leaving={leaving}\n onActivate={onItemClick}\n onDismiss={onDismiss}\n data-message-id={item.id}\n />\n ))\n )}\n </div>\n {viewAllLabel ? (\n <>\n <Separator />\n <div className=\"ds:pt-[var(--spacing-xs)]\">\n <Button\n intent=\"link\"\n size=\"sm\"\n onClick={onViewAll}\n className=\"ds:w-full ds:justify-center\"\n >\n {viewAllLabel}\n </Button>\n </div>\n </>\n ) : null}\n </RadixPopover.Content>\n </RadixPopover.Portal>\n </RadixPopover.Root>\n </div>\n );\n },\n);\n\nMessageTray.displayName = 'MessageTray';\n"],"names":["messageTrayAgent","handle","args","messageTrayVariants","cva","panelVariants","badgeVariants","formatBadgeCount","count","overflowLabel","SkeletonRow","jsxs","jsx","Skeleton","EmptyPanel","t","useTranslation","Mail","MessageTray","forwardRef","id","items","unreadCount","open","onOpenChange","onItemClick","onDismiss","onMarkRead","onMarkAllRead","loading","maxVisible","viewAllLabel","onViewAll","align","side","size","className","rest","ref","isControlled","internalOpen","setInternalOpen","useState","isOpen","handleOpenChange","useCallback","next","displayed","setDisplayed","item","animationDurationMs","raw","trimmed","useLayoutEffect","prev","nextIds","prevIds","d","merged","fresh","i","useEffect","ms","timer","liveRegionRef","useRef","lastTopIdRef","_a","topId","newest","displayCount","triggerAriaLabel","badgeLabel","panelClass","itemsRef","unreadRef","isOpenRef","useMemo","targetId","found","rootRef","useImperativeHandle","useAgentRegistration","RadixPopover","IconButton","Button","Separator","Fragment","leaving","MessageCard"],"mappings":"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"}
1
+ {"version":3,"file":"message-tray-BbnAzlLH.js","sources":["../../src/components/message-tray/message-tray.agent.ts","../../src/components/message-tray/message-tray.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — MessageTray. */\n/* */\n/* Tray-level surface: open/close the inbox panel, read message ids and */\n/* unread flag (never sender names / subjects / previews — those are */\n/* PHI), and route per-message operations through the curated handle. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { MessageTrayHandle } from './message-tray';\n\nexport const messageTrayAgent: AgentAdapter<MessageTrayHandle> = {\n id: 'message-tray',\n capabilities: ['open', 'close', 'select_single', 'dismiss'],\n state: {\n items: {\n type: 'Array<{ id: string; read: boolean }>',\n descriptionKey: 'ui.agent.messageTray.state.items',\n description:\n 'Currently-displayed messages. Ids + read flag only — no PHI / no sender names.',\n read: (handle) => handle.getItems(),\n },\n unreadCount: {\n type: 'number',\n descriptionKey: 'ui.agent.messageTray.state.unreadCount',\n description: 'Badge unread count surfaced by the host.',\n read: (handle) => handle.getUnreadCount(),\n },\n isOpen: {\n type: 'boolean',\n descriptionKey: 'ui.agent.messageTray.state.isOpen',\n description: 'Whether the dropdown panel is currently open.',\n read: (handle) => handle.isOpen(),\n },\n },\n actions: {\n open: {\n safety: 'read',\n descriptionKey: 'ui.agent.messageTray.actions.open',\n description: 'Open the message panel.',\n invoke: (handle) => {\n handle.open();\n },\n },\n close: {\n safety: 'read',\n descriptionKey: 'ui.agent.messageTray.actions.close',\n description: 'Close the message panel.',\n invoke: (handle) => {\n handle.close();\n },\n },\n select_item: {\n safety: 'read',\n argsType: '{ id: string }',\n descriptionKey: 'ui.agent.messageTray.actions.selectItem',\n description: 'Activate the message with the given id.',\n invoke: (handle, args: { id: string }) => {\n handle.selectItem(args.id);\n },\n },\n mark_read: {\n safety: 'write',\n argsType: '{ id: string }',\n descriptionKey: 'ui.agent.messageTray.actions.markRead',\n description: 'Request the host to mark a message as read.',\n invoke: (handle, args: { id: string }) => {\n handle.markRead(args.id);\n },\n },\n dismiss: {\n safety: 'destructive',\n argsType: '{ id: string }',\n descriptionKey: 'ui.agent.messageTray.actions.dismiss',\n description:\n 'Request the host to dismiss / archive the message with the given id.',\n invoke: (handle, args: { id: string }) => {\n handle.dismiss(args.id);\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'message-tray',\n description: 'Marks the MessageTray wrapper.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description:\n 'Sourced from the id prop. Required to address a specific tray from the agent.',\n },\n item: {\n attr: 'data-message-id',\n description:\n 'Stable message id emitted on each rendered MessageCard inside the tray.',\n },\n },\n};\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type HTMLAttributes,\n} from 'react';\nimport * as RadixPopover from '@radix-ui/react-popover';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Mail } from 'lucide-react';\nimport { IconButton } from '../button/icon-button';\nimport { Button } from '../button/button';\nimport { Separator } from '../separator/separator';\nimport { Skeleton } from '../skeleton/skeleton';\nimport { MessageCard, type MessageItem } from '../message-card/message-card';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { messageTrayAgent } from './message-tray.agent';\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\n/**\n * Curated imperative handle for MessageTray. Exposed as the forwardRef\n * target so a future agent / MCP UI bridge can drive the tray without\n * touching the DOM. See `message-tray.agent.ts`.\n */\nexport interface MessageTrayHandle {\n open: () => void;\n close: () => void;\n isOpen: () => boolean;\n getItems: () => Array<{ id: string; read: boolean }>;\n getUnreadCount: () => number;\n selectItem: (id: string) => void;\n markRead: (id: string) => void;\n dismiss: (id: string) => void;\n}\n\nexport interface MessageTrayProps\n extends\n Omit<\n HTMLAttributes<HTMLDivElement>,\n 'onClick' | 'children' | 'role' | 'id'\n >,\n VariantProps<typeof messageTrayVariants> {\n /**\n * Stable instance id. Surfaced on the root as `data-component-id` so\n * an agent / MCP UI bridge can address this specific tray.\n */\n id?: string;\n /** Fires when the host should mark a single message as read (used by agent integration). */\n onMarkRead?: (item: MessageItem) => void;\n /** Messages rendered in the dropdown panel. */\n items: MessageItem[];\n /** Number of unread messages. Drives the badge count. */\n unreadCount?: number;\n /** Controlled open state. */\n open?: boolean;\n /** Fires when the open state changes. */\n onOpenChange?: (open: boolean) => void;\n /** Fires when the user activates an item (click or Enter/Space). */\n onItemClick?: (item: MessageItem) => void;\n /** Fires when the user dismisses / archives a message. */\n onDismiss?: (item: MessageItem) => void;\n /** Fires when the user clicks the header \"Mark all as read\" action. */\n onMarkAllRead?: () => void;\n /** When true the panel shows skeleton placeholders. */\n loading?: boolean;\n /**\n * Advisory item count before the list scrolls. Consumers override the cap\n * via the `--message-tray-max-block-size` custom property.\n */\n maxVisible?: number;\n /** When set renders a footer link that invokes `onViewAll`. */\n viewAllLabel?: string;\n /** Fires when the footer \"View all\" link is clicked. */\n onViewAll?: () => void;\n /** Panel alignment relative to the trigger. Default `'end'`. */\n align?: 'start' | 'center' | 'end';\n /** Side of the trigger to open on. Default `'bottom'`. */\n side?: 'top' | 'bottom';\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst messageTrayVariants = cva('ds:relative ds:inline-flex ds:items-center', {\n variants: {\n size: {\n sm: '',\n md: '',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n});\n\nconst panelVariants = cva(\n [\n 'ds:flex ds:flex-col',\n 'ds:bg-[var(--popover)] ds:text-[var(--popover-foreground)]',\n 'ds:border ds:border-[color:var(--border)]',\n 'ds:rounded-[var(--radius-md)]',\n 'ds:shadow-[var(--shadow-lg)]',\n 'ds:z-[var(--z-popover)]',\n // Width: fluid below the design cap so narrow viewports keep a visible\n // gutter on both sides (shadow included). Cap slightly wider than\n // NotificationTray because message rows carry subject + preview.\n 'ds:w-[min(26rem,calc(100vw-2*var(--spacing-md)))]',\n // Height: below the `sm` breakpoint the panel takes a near-full-screen\n // sheet shape so the user gets room to triage an inbox without\n // scrolling a tiny popover. `6rem` reserves space for the Header\n // (≈4rem) plus the sideOffset + collisionPadding (≈2rem). Above `sm`\n // it returns to `h-auto` so the list's own cap governs the height.\n 'ds:h-[calc(100dvh-6rem)] ds:sm:h-auto',\n 'ds:data-[state=open]:animate-in ds:data-[state=closed]:animate-out',\n 'ds:data-[state=closed]:fade-out-0 ds:data-[state=open]:fade-in-0',\n 'ds:data-[state=closed]:zoom-out-95 ds:data-[state=open]:zoom-in-95',\n 'ds:motion-reduce:transition-none ds:motion-reduce:animate-none',\n 'ds:focus-visible:outline-none',\n 'ds:forced-colors:border-[CanvasText]',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:p-[var(--spacing-xs)]',\n md: 'ds:p-[var(--spacing-sm)]',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n },\n);\n\nconst badgeVariants = cva(\n [\n 'ds:absolute ds:-top-[var(--spacing-xs)] ds:-end-[var(--spacing-xs)]',\n 'ds:inline-flex ds:items-center ds:justify-center',\n 'ds:min-w-[calc(var(--spacing-md)+var(--spacing-xs))] ds:h-[calc(var(--spacing-md)+var(--spacing-xs))] ds:ps-[calc(var(--spacing-xs)/1.5)] ds:pe-[calc(var(--spacing-xs)/1.5)]',\n 'ds:rounded-[var(--radius-full)]',\n 'ds:bg-[color:var(--destructive)] ds:text-[color:var(--destructive-foreground)]',\n 'ds:text-[length:var(--font-size-xs)] ds:font-semibold ds:leading-none',\n 'ds:pointer-events-none ds:select-none',\n 'ds:forced-colors:outline ds:forced-colors:outline-1 ds:forced-colors:outline-[CanvasText]',\n ].join(' '),\n);\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\nfunction formatBadgeCount(count: number, overflowLabel: string): string {\n return count > 99 ? overflowLabel : String(count);\n}\n\nfunction SkeletonRow() {\n return (\n <div\n aria-hidden=\"true\"\n className=\"ds:flex ds:items-start ds:gap-[var(--spacing-sm)] ds:p-[var(--spacing-sm)]\"\n >\n <Skeleton variant=\"circular\" size=\"sm\" />\n <div className=\"ds:flex-1 ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <Skeleton variant=\"text\" size=\"md\" width=\"60%\" />\n <Skeleton variant=\"text\" size=\"sm\" width=\"80%\" />\n <Skeleton variant=\"text\" size=\"sm\" width=\"95%\" />\n <Skeleton variant=\"text\" size=\"sm\" width=\"30%\" />\n </div>\n </div>\n );\n}\n\nfunction EmptyPanel() {\n const { t } = useTranslation();\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className=\"ds:flex ds:flex-col ds:items-center ds:justify-center ds:gap-[var(--spacing-xs)] ds:p-[var(--spacing-lg)] ds:text-center\"\n >\n <span\n aria-hidden=\"true\"\n className=\"ds:inline-flex ds:items-center ds:justify-center ds:size-10 ds:rounded-[var(--radius-full)] ds:bg-[color:var(--muted)] ds:text-[color:var(--muted-foreground)] ds:[&>svg]:size-5\"\n >\n <Mail />\n </span>\n <p className=\"type-title-item ds:text-[color:var(--foreground)]\">\n {t('ui.messageTray.noMessages', 'No messages')}\n </p>\n <p className=\"type-meta ds:text-[color:var(--muted-foreground)]\">\n {t('ui.messageTray.noMessagesDescription', 'Your inbox is clear.')}\n </p>\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Root */\n/* ------------------------------------------------------------------ */\n\nexport const MessageTray = forwardRef<HTMLDivElement, MessageTrayProps>(\n (\n {\n id,\n items,\n unreadCount,\n open,\n onOpenChange,\n onItemClick,\n onDismiss,\n onMarkRead,\n onMarkAllRead,\n loading = false,\n maxVisible,\n viewAllLabel,\n onViewAll,\n align = 'end',\n side = 'bottom',\n size = 'md',\n className,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation();\n\n const isControlled = open !== undefined;\n const [internalOpen, setInternalOpen] = useState(false);\n const isOpen = isControlled ? open : internalOpen;\n\n const handleOpenChange = useCallback(\n (next: boolean) => {\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange],\n );\n\n /* Exit-animation list — same AnimatePresence-style bookkeeping as\n * NotificationTray. See that component for rationale. */\n type Displayed = { item: MessageItem; leaving: boolean };\n const [displayed, setDisplayed] = useState<Displayed[]>(() =>\n items.map((item) => ({ item, leaving: false })),\n );\n\n const animationDurationMs = useCallback((): number => {\n if (typeof window === 'undefined') return 200;\n const raw = window\n .getComputedStyle(document.documentElement)\n .getPropertyValue('--animation-duration');\n if (!raw) return 200;\n const trimmed = raw.trim();\n const n = parseFloat(trimmed);\n if (!Number.isFinite(n)) return 200;\n return trimmed.endsWith('ms') ? n : n * 1000;\n }, []);\n\n useLayoutEffect(() => {\n setDisplayed((prev) => {\n const nextIds = new Set(items.map((i) => i.id));\n const prevIds = new Set(prev.map((d) => d.item.id));\n\n const merged: Displayed[] = prev.map((d) => {\n if (nextIds.has(d.item.id)) {\n const fresh = items.find((i) => i.id === d.item.id);\n return fresh\n ? { item: fresh, leaving: false }\n : { ...d, leaving: true };\n }\n return { ...d, leaving: true };\n });\n\n for (const i of items) {\n if (!prevIds.has(i.id)) merged.push({ item: i, leaving: false });\n }\n return merged;\n });\n }, [items]);\n\n useEffect(() => {\n if (!displayed.some((d) => d.leaving)) return;\n const ms = animationDurationMs();\n const timer = setTimeout(() => {\n setDisplayed((prev) => prev.filter((d) => !d.leaving));\n }, ms);\n return () => clearTimeout(timer);\n }, [displayed, animationDurationMs]);\n\n const liveRegionRef = useRef<HTMLDivElement | null>(null);\n const lastTopIdRef = useRef<string | undefined>(items[0]?.id);\n\n useEffect(() => {\n const topId = items[0]?.id;\n const prev = lastTopIdRef.current;\n if (prev && topId && prev !== topId && liveRegionRef.current) {\n const newest = items[0];\n if (newest && !newest.read) {\n liveRegionRef.current.textContent = t('ui.messageTray.newMessage', {\n sender: newest.sender.name,\n defaultValue: 'New message from {{sender}}',\n });\n }\n }\n lastTopIdRef.current = topId;\n }, [items, t]);\n\n const displayCount = unreadCount ?? 0;\n const triggerAriaLabel =\n displayCount > 0\n ? t('ui.messageTray.triggerLabel', {\n count: displayCount,\n defaultValue: 'Messages, {{count}} unread',\n })\n : t('ui.messageTray.triggerLabelNone', 'Messages, none unread');\n\n const badgeLabel = formatBadgeCount(\n displayCount,\n t('ui.messageTray.badgeCountOverflow', '99+'),\n );\n\n const panelClass = panelVariants({ size });\n\n /* Curated imperative handle for agent integration. See\n * message-tray.agent.ts. */\n const itemsRef = useRef<MessageItem[]>(items);\n itemsRef.current = items;\n const unreadRef = useRef<number | undefined>(unreadCount);\n unreadRef.current = unreadCount;\n const isOpenRef = useRef<boolean>(isOpen);\n isOpenRef.current = isOpen;\n\n const handle = useMemo<MessageTrayHandle>(\n () => ({\n open: () => handleOpenChange(true),\n close: () => handleOpenChange(false),\n isOpen: () => isOpenRef.current,\n getItems: () =>\n itemsRef.current.map((i) => ({ id: i.id, read: !!i.read })),\n getUnreadCount: () =>\n unreadRef.current ?? itemsRef.current.filter((i) => !i.read).length,\n selectItem: (targetId: string) => {\n const found = itemsRef.current.find((i) => i.id === targetId);\n if (found) onItemClick?.(found);\n },\n markRead: (targetId: string) => {\n const found = itemsRef.current.find((i) => i.id === targetId);\n if (found) onMarkRead?.(found);\n },\n dismiss: (targetId: string) => {\n const found = itemsRef.current.find((i) => i.id === targetId);\n if (found) onDismiss?.(found);\n },\n }),\n [handleOpenChange, onItemClick, onMarkRead, onDismiss],\n );\n\n const rootRef = useRef<HTMLDivElement>(null);\n useImperativeHandle(ref, () => rootRef.current as HTMLDivElement, []);\n useAgentRegistration(messageTrayAgent, handle, id);\n\n return (\n <div\n ref={rootRef}\n data-component=\"message-tray\"\n data-component-id={id}\n className={[messageTrayVariants({ size }), className]\n .filter(Boolean)\n .join(' ')}\n {...rest}\n >\n <RadixPopover.Root open={isOpen} onOpenChange={handleOpenChange}>\n <RadixPopover.Trigger asChild>\n <IconButton\n icon={<Mail />}\n intent=\"outline\"\n size={size === 'sm' ? 'sm' : 'md'}\n aria-label={triggerAriaLabel}\n aria-haspopup=\"dialog\"\n />\n </RadixPopover.Trigger>\n {displayCount > 0 ? (\n <span\n aria-hidden=\"true\"\n data-testid=\"message-tray-badge\"\n className={badgeVariants()}\n >\n {badgeLabel}\n </span>\n ) : null}\n <div\n ref={liveRegionRef}\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"ds:sr-only\"\n />\n <RadixPopover.Portal>\n <RadixPopover.Content\n role=\"dialog\"\n aria-label={t('ui.messageTray.panelTitle', 'Messages')}\n side={side}\n align={align}\n sideOffset={8}\n // `spacing-md` (16px) keeps Radix's collision-avoidance from\n // flush-mounting the panel against the viewport edge when the\n // trigger is near the inline-end of a narrow screen.\n collisionPadding={16}\n className={panelClass}\n >\n <div className=\"ds:flex ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)] ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:pb-[var(--spacing-xs)]\">\n <h3 className=\"ds:m-0 type-title-card ds:text-[color:var(--foreground)]\">\n {t('ui.messageTray.panelTitle', 'Messages')}\n </h3>\n {onMarkAllRead && items.some((item) => !item.read) ? (\n <Button\n intent=\"link\"\n size=\"sm\"\n onClick={onMarkAllRead}\n className=\"ds:text-[length:var(--font-size-xs)]\"\n >\n {t('ui.messageTray.markAllRead', 'Mark all as read')}\n </Button>\n ) : null}\n </div>\n <Separator />\n <div\n // Only carry `role=\"list\"` when there are list children —\n // axe's `aria-required-children` rule fires on an empty\n // list. The loading skeleton + populated rendering both\n // produce role=\"listitem\" descendants below.\n role={displayed.length > 0 ? 'list' : undefined}\n data-max-visible={maxVisible}\n // Below `sm` the panel is a near-full-screen sheet (see\n // `panelVariants`) and the list expands to fill the\n // remaining space with `flex-1`. Above `sm` the list\n // caps at the `--message-tray-max-block-size` custom\n // property so the popover stays compact.\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:overflow-y-auto ds:pt-[var(--spacing-xs)] ds:flex-1 ds:sm:flex-none ds:sm:[max-block-size:var(--message-tray-max-block-size,26rem)]\"\n >\n {loading ? (\n <>\n <SkeletonRow />\n <SkeletonRow />\n <SkeletonRow />\n </>\n ) : displayed.length === 0 ? (\n <EmptyPanel />\n ) : (\n displayed.map(({ item, leaving }) => (\n <MessageCard\n key={item.id}\n item={item}\n variant=\"compact\"\n leaving={leaving}\n onActivate={onItemClick}\n onDismiss={onDismiss}\n data-message-id={item.id}\n />\n ))\n )}\n </div>\n {viewAllLabel ? (\n <>\n <Separator />\n <div className=\"ds:pt-[var(--spacing-xs)]\">\n <Button\n intent=\"link\"\n size=\"sm\"\n onClick={onViewAll}\n className=\"ds:w-full ds:justify-center\"\n >\n {viewAllLabel}\n </Button>\n </div>\n </>\n ) : null}\n </RadixPopover.Content>\n </RadixPopover.Portal>\n </RadixPopover.Root>\n </div>\n );\n },\n);\n\nMessageTray.displayName = 'MessageTray';\n"],"names":["messageTrayAgent","handle","args","messageTrayVariants","cva","panelVariants","badgeVariants","formatBadgeCount","count","overflowLabel","SkeletonRow","jsxs","jsx","Skeleton","EmptyPanel","t","useTranslation","Mail","MessageTray","forwardRef","id","items","unreadCount","open","onOpenChange","onItemClick","onDismiss","onMarkRead","onMarkAllRead","loading","maxVisible","viewAllLabel","onViewAll","align","side","size","className","rest","ref","isControlled","internalOpen","setInternalOpen","useState","isOpen","handleOpenChange","useCallback","next","displayed","setDisplayed","item","animationDurationMs","raw","trimmed","useLayoutEffect","prev","nextIds","prevIds","d","merged","fresh","i","useEffect","ms","timer","liveRegionRef","useRef","lastTopIdRef","_a","topId","newest","displayCount","triggerAriaLabel","badgeLabel","panelClass","itemsRef","unreadRef","isOpenRef","useMemo","targetId","found","rootRef","useImperativeHandle","useAgentRegistration","RadixPopover","IconButton","Button","Separator","Fragment","leaving","MessageCard"],"mappings":"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"}
@@ -1,12 +1,12 @@
1
1
  import { jsx as a, jsxs as n } from "react/jsx-runtime";
2
2
  import { forwardRef as M, useMemo as P, useState as R, useRef as B, useCallback as L } from "react";
3
- import { c as U } from "./index-D2ZczOXr.js";
4
- import { useTranslation as W } from "react-i18next";
5
- import { I as E } from "./icon-button-C4CGcYuz.js";
3
+ import { c as D } from "./index-D2ZczOXr.js";
4
+ import { useTranslation as U } from "react-i18next";
5
+ import { I as W } from "./icon-button-C4CGcYuz.js";
6
6
  import { B as N } from "./button-DD_0Xdmr.js";
7
- import { T as H } from "./timestamp-BV2lC-wV.js";
8
- import { X } from "./x-CCcI3eJp.js";
9
- const q = U(
7
+ import { T as E } from "./timestamp-BV2lC-wV.js";
8
+ import { X as H } from "./x-CCcI3eJp.js";
9
+ const X = D(
10
10
  [
11
11
  "ds:relative ds:flex ds:gap-[var(--spacing-sm)]",
12
12
  "ds:rounded-[var(--radius-sm)]",
@@ -73,10 +73,10 @@ const q = U(
73
73
  "ds:focus-visible:after:outline-offset-[length:var(--focus-ring-offset)]",
74
74
  "ds:forced-colors:focus-visible:after:outline-[CanvasText]"
75
75
  ].join(" ");
76
- function G(e) {
76
+ function q(e) {
77
77
  return /^(https?:\/\/(?!\/)|\/(?!\/)|#)/.test(e);
78
78
  }
79
- const J = M(
79
+ const G = M(
80
80
  ({
81
81
  item: e,
82
82
  variant: r = "compact",
@@ -89,7 +89,7 @@ const J = M(
89
89
  className: z,
90
90
  ...T
91
91
  }, K) => {
92
- const { t: u, i18n: v } = W(), S = P(() => {
92
+ const { t: u, i18n: v } = U(), S = P(() => {
93
93
  const s = new Date(e.createdAt);
94
94
  return Number.isNaN(s.getTime()) ? "" : new Intl.DateTimeFormat(v.language, {
95
95
  dateStyle: "medium",
@@ -112,7 +112,7 @@ const J = M(
112
112
  time: S,
113
113
  unreadSuffix: I,
114
114
  defaultValue: "{{title}}, {{time}}{{unreadSuffix}}"
115
- }), p = !!e.url && G(e.url), i = /* @__PURE__ */ a(
115
+ }), p = !!e.url && q(e.url), i = /* @__PURE__ */ a(
116
116
  "span",
117
117
  {
118
118
  className: [
@@ -130,7 +130,7 @@ const J = M(
130
130
  "aria-label": x,
131
131
  className: C + " ds:contents",
132
132
  onClick: (s) => {
133
- s.defaultPrevented || s.metaKey || s.ctrlKey || s.shiftKey || t(e);
133
+ s.defaultPrevented || s.metaKey || s.ctrlKey || s.shiftKey || (s.preventDefault(), t(e));
134
134
  },
135
135
  children: i
136
136
  }
@@ -149,7 +149,7 @@ const J = M(
149
149
  href: e.url,
150
150
  className: "ds:text-[color:var(--foreground)] ds:no-underline ds:hover:underline ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]",
151
151
  onClick: (s) => {
152
- s.defaultPrevented || s.metaKey || s.ctrlKey || s.shiftKey || t(e);
152
+ s.defaultPrevented || s.metaKey || s.ctrlKey || s.shiftKey || (s.preventDefault(), t(e));
153
153
  },
154
154
  children: i
155
155
  }
@@ -163,7 +163,7 @@ const J = M(
163
163
  "data-read": e.read ? "true" : "false",
164
164
  "data-leaving": g ? "true" : void 0,
165
165
  "aria-hidden": g || void 0,
166
- className: q({ variant: r, size: k, state: F, className: z }),
166
+ className: X({ variant: r, size: k, state: F, className: z }),
167
167
  ...T,
168
168
  children: [
169
169
  e.icon ? /* @__PURE__ */ a(
@@ -191,7 +191,7 @@ const J = M(
191
191
  ] }),
192
192
  e.description ? /* @__PURE__ */ a("p", { className: "ds:m-0 type-body-sm ds:text-[color:var(--muted-foreground)] ds:[overflow:hidden] ds:[display:-webkit-box] ds:[-webkit-box-orient:vertical] ds:[-webkit-line-clamp:2] ds:break-words", children: e.description }) : null,
193
193
  /* @__PURE__ */ a(
194
- H,
194
+ E,
195
195
  {
196
196
  value: e.createdAt,
197
197
  shape: "chip",
@@ -212,7 +212,7 @@ const J = M(
212
212
  {
213
213
  href: e.url,
214
214
  onClick: (s) => {
215
- s.defaultPrevented || s.metaKey || s.ctrlKey || s.shiftKey || t == null || t(e);
215
+ s.defaultPrevented || s.metaKey || s.ctrlKey || s.shiftKey || (s.preventDefault(), t == null || t(e));
216
216
  },
217
217
  children: l
218
218
  }
@@ -232,9 +232,9 @@ const J = M(
232
232
  ] }) : null
233
233
  ] }),
234
234
  r === "compact" && d ? /* @__PURE__ */ a("span", { className: "ds:relative ds:z-[1] ds:opacity-0 ds:group-hover:opacity-100 ds:group-focus-within:opacity-100 ds:transition-opacity ds:motion-reduce:transition-none", children: /* @__PURE__ */ a(
235
- E,
235
+ W,
236
236
  {
237
- icon: /* @__PURE__ */ a(X, {}),
237
+ icon: /* @__PURE__ */ a(H, {}),
238
238
  intent: "ghost",
239
239
  size: "sm",
240
240
  "aria-label": u(
@@ -249,9 +249,9 @@ const J = M(
249
249
  );
250
250
  }
251
251
  );
252
- J.displayName = "NotificationCard";
252
+ G.displayName = "NotificationCard";
253
253
  export {
254
- J as N,
255
- G as i
254
+ G as N,
255
+ q as i
256
256
  };
257
- //# sourceMappingURL=notification-card-hBlPN1-c.js.map
257
+ //# sourceMappingURL=notification-card-uTPEvAQS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification-card-uTPEvAQS.js","sources":["../../src/components/notification-card/notification-card.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useMemo,\n useRef,\n useState,\n type HTMLAttributes,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { X } from 'lucide-react';\nimport { IconButton } from '../button/icon-button';\nimport { Button } from '../button/button';\nimport { Timestamp } from '../timestamp';\n\n/* ------------------------------------------------------------------ */\n/* Types */\n/* ------------------------------------------------------------------ */\n\nexport interface NotificationItem {\n /** Unique identifier for the notification. */\n id: string;\n /** Notification title — rendered on the first line. */\n title: string;\n /** Notification body — rendered as plain text. */\n description?: string;\n /** Optional leading glyph — a React node (usually a Lucide icon). */\n icon?: ReactNode;\n /** Optional action URL — when present the card title is an anchor. */\n url?: string;\n /** ISO-8601 timestamp of when the notification was created. */\n createdAt: string;\n /** Whether the notification has been seen. Unread items get accent styling. */\n read?: boolean;\n}\n\nexport interface NotificationCardProps\n extends\n Omit<HTMLAttributes<HTMLDivElement>, 'onClick' | 'role' | 'title'>,\n VariantProps<typeof cardVariants> {\n /** The notification to render. */\n item: NotificationItem;\n /**\n * Layout shape.\n * - `compact` — single-line row with the whole card clickable (used by\n * NotificationTray).\n * - `dashboard` — alert-style block with explicit CTA and mark-as-read\n * controls (used by dashboards / sidebars).\n */\n variant?: 'compact' | 'dashboard';\n /** Visual density. */\n size?: 'sm' | 'md';\n /** Fires when the card title / body is activated. */\n onActivate?: (item: NotificationItem) => void;\n /** Fires when the dismiss control is activated. */\n onDismiss?: (item: NotificationItem) => void;\n /**\n * Label for the dashboard-variant CTA. Only rendered when `variant` is\n * `'dashboard'` and the item has a `url`.\n */\n ctaLabel?: string;\n /**\n * Label for the dashboard-variant mark-as-read link. Only rendered when\n * `variant` is `'dashboard'` and `onDismiss` is supplied.\n */\n dismissLabel?: string;\n /**\n * External exit-animation control. When supplied the card plays its\n * fade-out when this turns `true` and the consumer owns the subsequent\n * unmount (see NotificationTray). If omitted, the card self-manages the\n * exit on internal dismiss.\n */\n leaving?: boolean;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst cardVariants = cva(\n [\n 'ds:relative ds:flex ds:gap-[var(--spacing-sm)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:transition-colors',\n // Mount: fade + slide-down so a fresh notification reads as arriving.\n // `data-leaving=true` plays the matching exit, driven by the owning\n // tray's AnimatePresence loop.\n 'ds:motion-safe:animate-in ds:motion-safe:fade-in-0 ds:motion-safe:slide-in-from-top-2 ds:motion-safe:duration-[var(--animation-duration)]',\n 'ds:data-[leaving=true]:motion-safe:animate-out ds:data-[leaving=true]:motion-safe:fade-out-0 ds:data-[leaving=true]:motion-safe:slide-out-to-top-2',\n // Pin the exit's end-state until React unmounts. Without `fill-mode-forwards`\n // tw-animate-css leaves the element at opacity:1 for one paint frame after\n // the animation ends — the \"flicker before it animates away\" bug.\n 'ds:data-[leaving=true]:motion-safe:fill-mode-forwards',\n 'ds:data-[leaving=true]:pointer-events-none',\n 'ds:motion-reduce:transition-none',\n 'ds:text-start',\n 'ds:forced-colors:border ds:forced-colors:border-[CanvasText]',\n ].join(' '),\n {\n variants: {\n variant: {\n compact: 'ds:items-start',\n dashboard:\n 'ds:flex-col ds:sm:flex-row ds:items-stretch ds:sm:items-start ds:shadow-[var(--shadow-md)] ds:bg-[color:var(--card)]',\n },\n size: {\n sm: 'ds:p-[var(--spacing-sm)]',\n md: 'ds:p-[var(--spacing-md)]',\n },\n state: {\n unread: '',\n read: 'ds:bg-transparent',\n },\n },\n compoundVariants: [\n {\n variant: 'compact',\n state: 'unread',\n class: 'ds:bg-[color:var(--accent)]/5',\n },\n {\n variant: 'compact',\n state: 'read',\n class: 'ds:hover:bg-[color:var(--muted)]/40',\n },\n {\n variant: 'dashboard',\n state: 'unread',\n class: 'ds:bg-[color:var(--accent)]/5',\n },\n ],\n defaultVariants: {\n variant: 'compact',\n size: 'sm',\n state: 'read',\n },\n },\n);\n\nconst stretchedLinkClass = [\n 'ds:focus-visible:outline-none',\n \"ds:after:content-[''] ds:after:absolute ds:after:inset-0 ds:after:rounded-[var(--radius-sm)]\",\n 'ds:after:pointer-events-auto',\n 'ds:focus-visible:after:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:after:outline-solid',\n 'ds:focus-visible:after:outline-[color:var(--ring)]',\n 'ds:focus-visible:after:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:after:outline-[CanvasText]',\n].join(' ');\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\nexport function isSafeNotificationUrl(url: string): boolean {\n // Reject protocol-relative (//host), javascript:, data:, mailto: etc.\n // Only http(s), same-origin absolute paths (/), and hash (#) anchors pass.\n return /^(https?:\\/\\/(?!\\/)|\\/(?!\\/)|#)/.test(url);\n}\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport const NotificationCard = forwardRef<\n HTMLDivElement,\n NotificationCardProps\n>(\n (\n {\n item,\n variant = 'compact',\n size = 'sm',\n onActivate,\n onDismiss,\n ctaLabel,\n dismissLabel,\n leaving,\n className,\n ...rest\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation();\n // Screen-reader time context — absolute & unambiguous rather than the\n // visible relative phrase, which drifts and reads less clearly aloud.\n const accessibleTime = useMemo(() => {\n const date = new Date(item.createdAt);\n if (Number.isNaN(date.getTime())) return '';\n return new Intl.DateTimeFormat(i18n.language, {\n dateStyle: 'medium',\n timeStyle: 'short',\n }).format(date);\n }, [item.createdAt, i18n.language]);\n\n /* Exit animation.\n * - When `leaving` is undefined (uncontrolled): the card owns the\n * fade-out — dismiss click flips `isLeaving`, waits for\n * --animation-duration, then fires onDismiss.\n * - When `leaving` is boolean (controlled, e.g. NotificationTray): the\n * parent owns the lifecycle — dismiss click fires onDismiss\n * immediately and the parent schedules unmount after the animation. */\n const isControlledLeaving = leaving !== undefined;\n const [isLeaving, setIsLeaving] = useState(false);\n const dismissTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const effectiveLeaving = isControlledLeaving ? leaving : isLeaving;\n\n const prefersReducedMotion =\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n const handleDismiss = useCallback(() => {\n if (!onDismiss) return;\n if (isControlledLeaving || prefersReducedMotion) {\n onDismiss(item);\n return;\n }\n setIsLeaving(true);\n if (dismissTimerRef.current) clearTimeout(dismissTimerRef.current);\n const raw =\n (typeof window !== 'undefined' &&\n window\n .getComputedStyle(document.documentElement)\n .getPropertyValue('--animation-duration')) ||\n '200ms';\n const ms = raw.trim().endsWith('ms')\n ? parseFloat(raw)\n : parseFloat(raw) * 1000;\n dismissTimerRef.current = setTimeout(\n () => onDismiss(item),\n Number.isFinite(ms) ? ms : 200,\n );\n }, [onDismiss, item, isControlledLeaving, prefersReducedMotion]);\n\n const state = item.read ? 'read' : 'unread';\n\n const unreadSuffix = item.read\n ? ''\n : t('ui.notificationCard.unreadSuffix', ', unread');\n const ariaLabel = t('ui.notificationCard.itemLabel', {\n title: item.title,\n time: accessibleTime,\n unreadSuffix,\n defaultValue: '{{title}}, {{time}}{{unreadSuffix}}',\n });\n\n const hasSafeUrl = !!item.url && isSafeNotificationUrl(item.url);\n\n /* ------- Title rendering (stretched link in compact mode) ------- */\n\n const titleText = (\n <span\n className={[\n 'ds:flex-1 ds:min-w-0 ds:truncate',\n item.read ? 'ds:font-normal' : 'ds:font-semibold',\n ].join(' ')}\n >\n {item.title}\n </span>\n );\n\n let titleNode: ReactNode;\n if (variant === 'compact' && hasSafeUrl && onActivate) {\n titleNode = (\n <a\n href={item.url}\n aria-label={ariaLabel}\n className={stretchedLinkClass + ' ds:contents'}\n onClick={(event) => {\n if (\n event.defaultPrevented ||\n event.metaKey ||\n event.ctrlKey ||\n event.shiftKey\n )\n return;\n event.preventDefault();\n onActivate(item);\n }}\n >\n {titleText}\n </a>\n );\n } else if (variant === 'compact' && onActivate) {\n titleNode = (\n <button\n type=\"button\"\n aria-label={ariaLabel}\n className={\n stretchedLinkClass +\n ' ds:contents ds:bg-transparent ds:border-0 ds:p-0'\n }\n onClick={() => onActivate(item)}\n >\n {titleText}\n </button>\n );\n } else if (variant === 'dashboard' && hasSafeUrl && onActivate) {\n titleNode = (\n <a\n href={item.url}\n className=\"ds:text-[color:var(--foreground)] ds:no-underline ds:hover:underline ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]\"\n onClick={(event) => {\n if (\n event.defaultPrevented ||\n event.metaKey ||\n event.ctrlKey ||\n event.shiftKey\n )\n return;\n event.preventDefault();\n onActivate(item);\n }}\n >\n {titleText}\n </a>\n );\n } else {\n titleNode = titleText;\n }\n\n return (\n <div\n ref={ref}\n role=\"listitem\"\n data-component=\"notification-card\"\n data-component-id={item.id}\n data-read={item.read ? 'true' : 'false'}\n data-leaving={effectiveLeaving ? 'true' : undefined}\n aria-hidden={effectiveLeaving || undefined}\n className={cardVariants({ variant, size, state, className })}\n {...rest}\n >\n {item.icon ? (\n <span\n aria-hidden=\"true\"\n className=\"ds:inline-flex ds:shrink-0 ds:items-center ds:justify-center ds:size-8 ds:rounded-[var(--radius-full)] ds:bg-[color:var(--accent)]/10 ds:text-[color:var(--accent)] ds:[&>svg]:size-4\"\n >\n {item.icon}\n </span>\n ) : null}\n\n <div className=\"ds:flex-1 ds:min-w-0 ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n {!item.read ? (\n <span\n aria-hidden=\"true\"\n className=\"ds:inline-block ds:size-1.5 ds:shrink-0 ds:rounded-[var(--radius-full)] ds:bg-[color:var(--primary)] ds:forced-colors:bg-[Highlight]\"\n />\n ) : null}\n {variant === 'dashboard' ? (\n // `h3` keeps the dashboard heading ladder continuous:\n // h1 (page) → h2 (WarningStack + NotificationsPanel) → h3 (notification title).\n <h3 className=\"ds:m-0 ds:flex-1 ds:min-w-0 type-title-item\">\n {titleNode}\n </h3>\n ) : (\n <span className=\"ds:flex-1 ds:min-w-0 type-title-item ds:text-[color:var(--foreground)]\">\n {titleNode}\n </span>\n )}\n </div>\n\n {item.description ? (\n <p className=\"ds:m-0 type-body-sm ds:text-[color:var(--muted-foreground)] ds:[overflow:hidden] ds:[display:-webkit-box] ds:[-webkit-box-orient:vertical] ds:[-webkit-line-clamp:2] ds:break-words\">\n {item.description}\n </p>\n ) : null}\n\n <Timestamp\n value={item.createdAt}\n shape=\"chip\"\n size=\"sm\"\n relativeWindow={12 * 60 * 60 * 1000}\n />\n\n {variant === 'dashboard' && (ctaLabel || dismissLabel) ? (\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-sm)]\">\n {ctaLabel && hasSafeUrl ? (\n <Button\n intent=\"outline\"\n size=\"sm\"\n asChild\n className=\"ds:relative ds:z-[1]\"\n >\n <a\n href={item.url}\n onClick={(event) => {\n if (\n event.defaultPrevented ||\n event.metaKey ||\n event.ctrlKey ||\n event.shiftKey\n )\n return;\n event.preventDefault();\n onActivate?.(item);\n }}\n >\n {ctaLabel}\n </a>\n </Button>\n ) : null}\n {dismissLabel && onDismiss ? (\n <Button\n intent=\"link\"\n size=\"sm\"\n onClick={handleDismiss}\n className=\"ds:relative ds:z-[1]\"\n >\n {dismissLabel}\n </Button>\n ) : null}\n </div>\n ) : null}\n </div>\n\n {variant === 'compact' && onDismiss ? (\n <span className=\"ds:relative ds:z-[1] ds:opacity-0 ds:group-hover:opacity-100 ds:group-focus-within:opacity-100 ds:transition-opacity ds:motion-reduce:transition-none\">\n <IconButton\n icon={<X />}\n intent=\"ghost\"\n size=\"sm\"\n aria-label={t(\n 'ui.notificationCard.dismiss',\n 'Dismiss notification',\n )}\n onClick={handleDismiss}\n />\n </span>\n ) : null}\n </div>\n );\n },\n);\n\nNotificationCard.displayName = 'NotificationCard';\n"],"names":["cardVariants","cva","stretchedLinkClass","isSafeNotificationUrl","url","NotificationCard","forwardRef","item","variant","size","onActivate","onDismiss","ctaLabel","dismissLabel","leaving","className","rest","ref","t","i18n","useTranslation","accessibleTime","useMemo","date","isControlledLeaving","isLeaving","setIsLeaving","useState","dismissTimerRef","useRef","effectiveLeaving","prefersReducedMotion","handleDismiss","useCallback","raw","ms","state","unreadSuffix","ariaLabel","hasSafeUrl","titleText","jsx","titleNode","event","jsxs","Timestamp","Button","IconButton","X"],"mappings":"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"}