@sarunyu/system-one 4.5.1 → 4.6.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.
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import * as React from "react";
4
4
  import React__default, { forwardRef, useState, useRef, useEffect, useCallback, useId, useMemo, useLayoutEffect, useContext, createContext } from "react";
5
5
  import { clsx } from "clsx";
6
6
  import { twMerge } from "tailwind-merge";
7
- import { BellSimple, FunnelSimple, CheckCircle, Warning, XCircle, Info, BookmarkSimpleIcon, BroadcastIcon as BroadcastIcon$1, CalendarBlank, MapPin, Users, Lock, Check, Plus, Circle, Minus, CaretLeft, CaretRight, CaretDoubleLeft, CaretDoubleRight, CaretUp, CaretDown, X, ImageSquare, MegaphoneSimple, GearSix, MagnifyingGlass, ArrowUp, ArrowDown, ArrowsDownUp, Clock } from "@phosphor-icons/react";
7
+ import { BellSimple, FunnelSimple, CheckCircle, Warning, XCircle, Info, BookmarkSimpleIcon, BroadcastIcon as BroadcastIcon$1, CalendarBlank, MapPin, Users, Lock, Check, Plus, Circle, Minus, CaretLeft, CaretRight, CaretDoubleLeft, CaretDoubleRight, CaretUp, CaretDown, X, ImageSquare, Gift, MegaphoneSimple, GearSix, MagnifyingGlass, ArrowUp, ArrowDown, ArrowsDownUp, Clock } from "@phosphor-icons/react";
8
8
  import { DayPicker, useNavigation } from "react-day-picker";
9
9
  import * as Popover from "@radix-ui/react-popover";
10
10
  import { Drawer as Drawer$1 } from "vaul";
@@ -244,11 +244,10 @@ function Badge({
244
244
  ...props
245
245
  }) {
246
246
  const hasCount = count > 0;
247
- const isActive = hasCount;
248
247
  const resolvedNotificationState = notificationState ?? (hasCount ? "noti" : "default");
249
248
  const notificationIsFilled = resolvedNotificationState === "active" || resolvedNotificationState === "noti";
250
249
  const showNotificationDot = resolvedNotificationState === "noti" && hasCount;
251
- const visualIcon = variant === "notification" ? notificationIsFilled ? /* @__PURE__ */ jsx(BellSimple, { size: 19, weight: "fill" }) : /* @__PURE__ */ jsx(BellSimple, { size: 19, weight: "regular" }) : icon ?? /* @__PURE__ */ jsx(FunnelSimple, { size: 18, weight: "regular" });
250
+ const visualIcon = variant === "notification" ? /* @__PURE__ */ jsx(BellSimple, { size: 18, weight: notificationIsFilled ? "fill" : "regular" }) : icon ?? /* @__PURE__ */ jsx(FunnelSimple, { size: 18, weight: "regular" });
252
251
  return /* @__PURE__ */ jsxs("div", { className: cn("relative inline-flex", className), children: [
253
252
  variant === "notification" ? /* @__PURE__ */ jsx(
254
253
  Button,
@@ -256,10 +255,7 @@ function Badge({
256
255
  "aria-label": "Notification",
257
256
  size: "icon-xs",
258
257
  variant: "plain-black",
259
- className: cn(
260
- "text-subtle-text",
261
- notificationIsFilled && "text-primary-action"
262
- ),
258
+ className: "text-icon-brand [&>span]:!h-[18px] [&>span]:!w-[18px]",
263
259
  ...props,
264
260
  children: visualIcon
265
261
  }
@@ -268,8 +264,8 @@ function Badge({
268
264
  {
269
265
  "aria-label": label,
270
266
  size: "icon-md",
271
- variant: isActive ? "outline" : "outline-black",
272
- className: cn(isActive && "bg-primary-action-light border-primary-action-light"),
267
+ variant: hasCount ? "outline" : "outline-black",
268
+ className: cn(hasCount && "bg-primary-action-light border-primary-action-light"),
273
269
  ...props,
274
270
  children: visualIcon
275
271
  }
@@ -278,8 +274,8 @@ function Badge({
278
274
  {
279
275
  size: "md",
280
276
  leftIcon: visualIcon,
281
- variant: isActive ? "outline" : "outline-black",
282
- className: cn(isActive && "bg-primary-action-light border-primary-action-light"),
277
+ variant: hasCount ? "outline" : "outline-black",
278
+ className: cn(hasCount && "bg-primary-action-light border-primary-action-light"),
283
279
  ...props,
284
280
  children: label
285
281
  }
@@ -288,10 +284,10 @@ function Badge({
288
284
  "div",
289
285
  {
290
286
  className: cn(
291
- "absolute flex items-center justify-center rounded-[60px] px-1",
292
- variant === "notification" ? "-right-0.5 -top-0.5 h-[14px] min-w-[14px] bg-destructive" : "-right-1 -top-[7px] h-4 min-w-4 bg-primary-action"
287
+ "absolute flex h-[14px] min-h-[14px] min-w-[14px] items-center justify-center rounded-[60px]",
288
+ variant === "notification" ? "-right-0.5 -top-0.5 bg-destructive px-[2.5px]" : "-right-1 -top-[7px] h-4 min-w-4 bg-primary-action"
293
289
  ),
294
- children: /* @__PURE__ */ jsx("p", { className: "text-center text-xs leading-4 text-on-primary-action", children: formatCount(count, maxCount) })
290
+ children: /* @__PURE__ */ jsx("p", { className: "text-center text-xs leading-4 font-normal text-text-default-white", children: formatCount(count, maxCount) })
295
291
  }
296
292
  )
297
293
  ] });
@@ -363,6 +359,22 @@ const Alert = forwardRef(function Alert2({ status = "normal", message, multiline
363
359
  );
364
360
  });
365
361
  Alert.displayName = "Alert";
362
+ const MOBILE_BREAKPOINT = 768;
363
+ function useIsMobile() {
364
+ const [isMobile, setIsMobile] = React.useState(
365
+ void 0
366
+ );
367
+ React.useEffect(() => {
368
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
369
+ const onChange = () => {
370
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
371
+ };
372
+ mql.addEventListener("change", onChange);
373
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
374
+ return () => mql.removeEventListener("change", onChange);
375
+ }, []);
376
+ return !!isMobile;
377
+ }
366
378
  function BannerMedia({ src, alt }) {
367
379
  if (!src) {
368
380
  return /* @__PURE__ */ jsx("div", { "aria-hidden": "true", className: "absolute inset-0 bg-muted" });
@@ -470,7 +482,7 @@ const tagConfig = {
470
482
  };
471
483
  const Card = forwardRef(function Card2({
472
484
  variant = "default",
473
- size = "desktop",
485
+ size: sizeProp,
474
486
  children,
475
487
  title,
476
488
  locked = true,
@@ -494,9 +506,11 @@ const Card = forwardRef(function Card2({
494
506
  // live
495
507
  duration
496
508
  }, ref) {
509
+ const isMobile = useIsMobile();
510
+ const size = sizeProp ?? (isMobile ? "mobile" : "desktop");
497
511
  const bannerSrc = image ?? "";
498
512
  if (variant === "default") {
499
- const shellPadding = size === "desktop" ? "p-4" : size === "tablet" ? "p-3" : "p-2.5";
513
+ const shellPadding = size === "desktop" ? "p-4" : "p-3";
500
514
  const shellRadius = size === "mobile" ? "rounded-[6px]" : "rounded-[8px]";
501
515
  return /* @__PURE__ */ jsx(
502
516
  "div",
@@ -954,7 +968,8 @@ function NewsContent({
954
968
  }
955
969
  function CheckboxVisual({
956
970
  state,
957
- disabled
971
+ disabled,
972
+ error
958
973
  }) {
959
974
  if (state === "default") {
960
975
  return /* @__PURE__ */ jsx(
@@ -963,12 +978,12 @@ function CheckboxVisual({
963
978
  "aria-hidden": "true",
964
979
  className: cn(
965
980
  "block w-4 h-4 rounded-[2px] border-[1.5px]",
966
- disabled ? "bg-disabled-bg border-[var(--fill-black-100)]" : "bg-background border-[var(--fill-black-200)]"
981
+ disabled ? "bg-disabled-bg border-[var(--fill-black-100)]" : error ? "bg-background border-destructive" : "bg-background border-[var(--fill-black-200)]"
967
982
  )
968
983
  }
969
984
  );
970
985
  }
971
- const containerFill = disabled ? "var(--fill-gray-300)" : "var(--fill-p1-600)";
986
+ const containerFill = disabled ? "var(--disabled-bg)" : "var(--fill-p1-600)";
972
987
  const iconFill = disabled ? "var(--fill-gray-400)" : "var(--fill-white-1000)";
973
988
  if (state === "checked") {
974
989
  return /* @__PURE__ */ jsxs(
@@ -1030,6 +1045,8 @@ function CheckboxVisual({
1030
1045
  const Checkbox = forwardRef(function Checkbox2({
1031
1046
  checked = false,
1032
1047
  disabled = false,
1048
+ error = false,
1049
+ errorMessage = "Error message",
1033
1050
  label,
1034
1051
  description,
1035
1052
  variant = "text",
@@ -1061,59 +1078,72 @@ const Checkbox = forwardRef(function Checkbox2({
1061
1078
  const hasText = label !== void 0 || description !== void 0;
1062
1079
  const hasActiveBorder = state === "checked" || state === "indeterminate";
1063
1080
  const isButton = variant === "button";
1064
- const buttonBorder = disabled ? "border-[var(--fill-black-100)]" : hasActiveBorder ? "border-primary-action" : "border-[var(--fill-black-200)]";
1081
+ const buttonBorder = disabled ? "border-[var(--fill-black-100)]" : error ? "border-destructive" : hasActiveBorder ? "border-primary-action" : "border-[var(--fill-black-200)]";
1082
+ const showError = error && !disabled;
1065
1083
  return /* @__PURE__ */ jsxs(
1066
1084
  "label",
1067
1085
  {
1068
1086
  className: cn(
1069
- "inline-flex gap-1 select-none",
1070
- description ? "items-start" : "items-center",
1087
+ "flex flex-col select-none",
1071
1088
  disabled ? "cursor-not-allowed" : "cursor-pointer",
1072
- isButton && cn("bg-background rounded-lg border py-2.5 pl-3 pr-4", buttonBorder),
1073
1089
  className
1074
1090
  ),
1075
1091
  children: [
1076
- /* @__PURE__ */ jsxs("span", { className: "relative inline-flex items-center justify-center w-6 h-6 shrink-0", children: [
1077
- /* @__PURE__ */ jsx(
1078
- "input",
1079
- {
1080
- ref: setRefs,
1081
- id,
1082
- name,
1083
- value,
1084
- type: "checkbox",
1085
- checked: checked === true,
1086
- disabled,
1087
- onChange: handleChange,
1088
- "aria-label": ariaLabel,
1089
- "aria-checked": checked === "indeterminate" ? "mixed" : checked,
1090
- className: "absolute inset-0 w-full h-full opacity-0 m-0 cursor-[inherit] disabled:cursor-[inherit]"
1091
- }
1092
- ),
1093
- /* @__PURE__ */ jsx(CheckboxVisual, { state, disabled })
1094
- ] }),
1095
- hasText && /* @__PURE__ */ jsxs("span", { className: "flex flex-col", children: [
1096
- label !== void 0 && /* @__PURE__ */ jsx(
1097
- "span",
1098
- {
1099
- className: cn(
1100
- "text-base leading-6",
1101
- disabled ? "text-disabled" : "text-foreground"
1102
- ),
1103
- children: label
1104
- }
1105
- ),
1106
- description !== void 0 && /* @__PURE__ */ jsx(
1107
- "span",
1108
- {
1109
- className: cn(
1110
- "text-xs leading-4",
1111
- disabled ? "text-disabled" : "text-subtle-text"
1112
- ),
1113
- children: description
1114
- }
1115
- )
1116
- ] })
1092
+ /* @__PURE__ */ jsxs(
1093
+ "span",
1094
+ {
1095
+ className: cn(
1096
+ "inline-flex gap-1",
1097
+ description ? "items-start" : "items-center",
1098
+ isButton && cn("bg-background rounded-lg border py-2.5 pl-3 pr-4", buttonBorder)
1099
+ ),
1100
+ children: [
1101
+ /* @__PURE__ */ jsxs("span", { className: "relative inline-flex items-center justify-center w-6 h-6 shrink-0", children: [
1102
+ /* @__PURE__ */ jsx(
1103
+ "input",
1104
+ {
1105
+ ref: setRefs,
1106
+ id,
1107
+ name,
1108
+ value,
1109
+ type: "checkbox",
1110
+ checked: checked === true,
1111
+ disabled,
1112
+ onChange: handleChange,
1113
+ "aria-label": ariaLabel,
1114
+ "aria-checked": checked === "indeterminate" ? "mixed" : checked,
1115
+ "aria-invalid": showError || void 0,
1116
+ className: "absolute inset-0 w-full h-full opacity-0 m-0 cursor-[inherit] disabled:cursor-[inherit]"
1117
+ }
1118
+ ),
1119
+ /* @__PURE__ */ jsx(CheckboxVisual, { state, disabled, error: showError })
1120
+ ] }),
1121
+ hasText && /* @__PURE__ */ jsxs("span", { className: "flex flex-col", children: [
1122
+ label !== void 0 && /* @__PURE__ */ jsx(
1123
+ "span",
1124
+ {
1125
+ className: cn(
1126
+ "text-base leading-6",
1127
+ disabled ? "text-disabled" : "text-foreground"
1128
+ ),
1129
+ children: label
1130
+ }
1131
+ ),
1132
+ description !== void 0 && /* @__PURE__ */ jsx(
1133
+ "span",
1134
+ {
1135
+ className: cn(
1136
+ "text-xs leading-4",
1137
+ disabled ? "text-disabled" : "text-subtle-text"
1138
+ ),
1139
+ children: description
1140
+ }
1141
+ )
1142
+ ] })
1143
+ ]
1144
+ }
1145
+ ),
1146
+ showError && /* @__PURE__ */ jsx("span", { className: "mt-1 ml-7 text-xs text-destructive", children: errorMessage })
1117
1147
  ]
1118
1148
  }
1119
1149
  );
@@ -1381,22 +1411,6 @@ const Chip = forwardRef(function Chip2({
1381
1411
  );
1382
1412
  });
1383
1413
  Chip.displayName = "Chip";
1384
- const MOBILE_BREAKPOINT = 768;
1385
- function useIsMobile() {
1386
- const [isMobile, setIsMobile] = React.useState(
1387
- void 0
1388
- );
1389
- React.useEffect(() => {
1390
- const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
1391
- const onChange = () => {
1392
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
1393
- };
1394
- mql.addEventListener("change", onChange);
1395
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
1396
- return () => mql.removeEventListener("change", onChange);
1397
- }, []);
1398
- return !!isMobile;
1399
- }
1400
1414
  function Drawer({
1401
1415
  ...props
1402
1416
  }) {
@@ -3647,7 +3661,7 @@ const Input = forwardRef(function Input2({
3647
3661
  Input.displayName = "Input";
3648
3662
  const ALERT_CONFIG = {
3649
3663
  warning: {
3650
- titleColor: "var(--accent-orange)",
3664
+ titleColor: "var(--text-warning-primary)",
3651
3665
  background: "https://www.figma.com/api/mcp/asset/f4ca68ad-5732-4124-9ff4-cfb69330cc02",
3652
3666
  layers: [
3653
3667
  {
@@ -3665,7 +3679,7 @@ const ALERT_CONFIG = {
3665
3679
  ]
3666
3680
  },
3667
3681
  success: {
3668
- titleColor: "var(--success)",
3682
+ titleColor: "var(--text-success-primary)",
3669
3683
  background: "https://www.figma.com/api/mcp/asset/2a865e6f-8a92-4496-88b5-71ac99e2c385",
3670
3684
  layers: [
3671
3685
  {
@@ -3679,7 +3693,7 @@ const ALERT_CONFIG = {
3679
3693
  ]
3680
3694
  },
3681
3695
  danger: {
3682
- titleColor: "var(--destructive)",
3696
+ titleColor: "var(--text-danger-primary)",
3683
3697
  background: "https://www.figma.com/api/mcp/asset/c7a65595-684e-4a04-b7fd-d443951f680a",
3684
3698
  layers: [
3685
3699
  {
@@ -3864,18 +3878,19 @@ function NotificationDivider({ label }) {
3864
3878
  }
3865
3879
  function NotificationRow({
3866
3880
  item,
3867
- onItemClick
3881
+ onItemClick,
3882
+ hideIndicator = false,
3883
+ demoteNewBackground = false
3868
3884
  }) {
3869
3885
  const rowType = item.type ?? "icon";
3870
3886
  const showImage = rowType === "image";
3871
- const showUnread = Boolean(item.unread);
3887
+ const status = item.status ?? (item.unread ? "unread" : "read");
3888
+ const showIndicator = (status === "new" || status === "unread") && !hideIndicator;
3889
+ const rowBackground = status === "new" && !demoteNewBackground ? "bg-muted" : "bg-background";
3872
3890
  return /* @__PURE__ */ jsxs(
3873
3891
  "div",
3874
3892
  {
3875
- className: cn(
3876
- "flex w-full items-start gap-3 px-4 py-3",
3877
- showUnread ? "bg-primary-action-light/40" : "bg-background"
3878
- ),
3893
+ className: cn("flex w-full items-start gap-3 px-4 py-3", rowBackground),
3879
3894
  role: "button",
3880
3895
  tabIndex: 0,
3881
3896
  onClick: () => onItemClick == null ? void 0 : onItemClick(item),
@@ -3893,22 +3908,11 @@ function NotificationRow({
3893
3908
  className: "h-10 w-10 rounded object-cover",
3894
3909
  src: item.imageSrc
3895
3910
  }
3896
- ) : /* @__PURE__ */ jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded bg-disabled-bg text-disabled", children: /* @__PURE__ */ jsx(ImageSquare, { size: 20, weight: "regular" }) }) : /* @__PURE__ */ jsx("div", { className: "flex h-6 w-6 items-center justify-center text-subtle-text", children: item.icon ?? /* @__PURE__ */ jsx(Circle, { size: 20, weight: "regular" }) }) }),
3897
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
3898
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_auto] items-start gap-x-2", children: [
3899
- /* @__PURE__ */ jsx("p", { className: "min-w-0 flex-1 truncate text-base leading-6 font-bold text-foreground", children: item.title }),
3900
- /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [
3901
- showUnread && /* @__PURE__ */ jsx(
3902
- "span",
3903
- {
3904
- "aria-hidden": "true",
3905
- className: "h-2 w-2 rounded-full bg-primary-action"
3906
- }
3907
- ),
3908
- /* @__PURE__ */ jsx("p", { className: "text-xs leading-4 text-muted-foreground", children: item.time })
3909
- ] }),
3910
- /* @__PURE__ */ jsx("p", { className: "col-start-1 mt-1 line-clamp-2 text-sm leading-5 text-muted-foreground", children: item.description })
3911
- ] }),
3911
+ ) : /* @__PURE__ */ jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded bg-disabled-bg text-disabled", children: /* @__PURE__ */ jsx(ImageSquare, { size: 20, weight: "regular" }) }) : /* @__PURE__ */ jsx("div", { className: "flex h-6 w-6 items-center justify-center text-subtle-text", children: item.icon ?? /* @__PURE__ */ jsx(Gift, { size: 20, weight: "regular" }) }) }),
3912
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
3913
+ /* @__PURE__ */ jsx("p", { className: "line-clamp-2 text-base leading-6 font-semibold text-foreground", children: item.title }),
3914
+ /* @__PURE__ */ jsx("p", { className: "line-clamp-3 text-sm leading-5 text-muted-foreground", children: item.description }),
3915
+ /* @__PURE__ */ jsx("p", { className: "text-xs leading-4 text-muted-foreground", children: item.time }),
3912
3916
  item.actionLabel && /* @__PURE__ */ jsx(
3913
3917
  Button,
3914
3918
  {
@@ -3923,7 +3927,14 @@ function NotificationRow({
3923
3927
  children: item.actionLabel
3924
3928
  }
3925
3929
  )
3926
- ] })
3930
+ ] }),
3931
+ /* @__PURE__ */ jsx("div", { className: "flex w-2 shrink-0 items-start justify-center pt-2", children: showIndicator ? /* @__PURE__ */ jsx(
3932
+ "span",
3933
+ {
3934
+ "aria-hidden": "true",
3935
+ className: "h-2 w-2 rounded-full bg-destructive"
3936
+ }
3937
+ ) : null })
3927
3938
  ]
3928
3939
  }
3929
3940
  );
@@ -3934,6 +3945,7 @@ const Notification = forwardRef(
3934
3945
  badgeCount,
3935
3946
  panelWidth = 375,
3936
3947
  emptyText = "No notifications",
3948
+ showGroupLabels = true,
3937
3949
  clearBadgeOnOpen = true,
3938
3950
  open,
3939
3951
  defaultOpen,
@@ -3945,16 +3957,23 @@ const Notification = forwardRef(
3945
3957
  }, ref) {
3946
3958
  const [internalOpen, setInternalOpen] = useState(defaultOpen ?? false);
3947
3959
  const [isBadgeCleared, setIsBadgeCleared] = useState(false);
3960
+ const [clickedItemIds, setClickedItemIds] = useState(/* @__PURE__ */ new Set());
3961
+ const [wasDismissed, setWasDismissed] = useState(false);
3962
+ const [mobileAlign, setMobileAlign] = useState(null);
3963
+ const triggerRef = useRef(null);
3948
3964
  const controlled = open !== void 0;
3949
3965
  const resolvedOpen = controlled ? open : internalOpen;
3950
- const unreadCount = useMemo(
3966
+ const newCount = useMemo(
3951
3967
  () => groups.reduce(
3952
- (acc, group) => acc + group.items.filter((item) => Boolean(item.unread)).length,
3968
+ (acc, group) => acc + group.items.filter((item) => {
3969
+ const status = item.status ?? (item.unread ? "unread" : "read");
3970
+ return status === "new";
3971
+ }).length,
3953
3972
  0
3954
3973
  ),
3955
3974
  [groups]
3956
3975
  );
3957
- const nextCount = badgeCount ?? unreadCount;
3976
+ const nextCount = badgeCount ?? newCount;
3958
3977
  const prevCountRef = useRef(nextCount);
3959
3978
  useEffect(() => {
3960
3979
  const prevCount = prevCountRef.current;
@@ -3963,9 +3982,29 @@ const Notification = forwardRef(
3963
3982
  }
3964
3983
  prevCountRef.current = nextCount;
3965
3984
  }, [nextCount]);
3985
+ useEffect(() => {
3986
+ const update = () => {
3987
+ if (window.innerWidth > 640 || !triggerRef.current) {
3988
+ setMobileAlign(null);
3989
+ return;
3990
+ }
3991
+ const contentWidth = Math.min(panelWidth, window.innerWidth - 32);
3992
+ const triggerLeft = triggerRef.current.getBoundingClientRect().left;
3993
+ setMobileAlign({
3994
+ alignOffset: (window.innerWidth - contentWidth) / 2 - triggerLeft,
3995
+ width: contentWidth
3996
+ });
3997
+ };
3998
+ update();
3999
+ window.addEventListener("resize", update);
4000
+ return () => window.removeEventListener("resize", update);
4001
+ }, [panelWidth]);
3966
4002
  const displayCount = clearBadgeOnOpen && isBadgeCleared ? 0 : nextCount;
3967
4003
  const hasItems = groups.some((group) => group.items.length > 0);
3968
4004
  const handleOpenChange = (next) => {
4005
+ if (resolvedOpen && !next) {
4006
+ setWasDismissed(true);
4007
+ }
3969
4008
  if (next && clearBadgeOnOpen && nextCount > 0) {
3970
4009
  setIsBadgeCleared(true);
3971
4010
  onBadgeCleared == null ? void 0 : onBadgeCleared();
@@ -3973,8 +4012,17 @@ const Notification = forwardRef(
3973
4012
  if (!controlled) setInternalOpen(next);
3974
4013
  onOpenChange == null ? void 0 : onOpenChange(next);
3975
4014
  };
4015
+ const handleItemClick = (item) => {
4016
+ setClickedItemIds((prev) => {
4017
+ if (prev.has(item.id)) return prev;
4018
+ const next = new Set(prev);
4019
+ next.add(item.id);
4020
+ return next;
4021
+ });
4022
+ onItemClick == null ? void 0 : onItemClick(item);
4023
+ };
3976
4024
  return /* @__PURE__ */ jsxs(Popover.Root, { open: resolvedOpen, onOpenChange: handleOpenChange, children: [
3977
- /* @__PURE__ */ jsx("div", { ref, className: cn("inline-flex", className), children: /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsx(
4025
+ /* @__PURE__ */ jsx("div", { ref, className: cn("inline-flex", className), children: /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsx("div", { ref: triggerRef, className: "relative", children: /* @__PURE__ */ jsx(
3978
4026
  Badge,
3979
4027
  {
3980
4028
  variant: "notification",
@@ -3987,22 +4035,26 @@ const Notification = forwardRef(
3987
4035
  /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(
3988
4036
  Popover.Content,
3989
4037
  {
3990
- align: "end",
4038
+ align: mobileAlign ? "start" : "end",
4039
+ alignOffset: (mobileAlign == null ? void 0 : mobileAlign.alignOffset) ?? 0,
4040
+ avoidCollisions: !mobileAlign,
3991
4041
  sideOffset: 10,
3992
4042
  className: cn(
3993
4043
  "z-50 overflow-hidden rounded-lg border border-border bg-background shadow-lg",
3994
4044
  panelClassName
3995
4045
  ),
3996
- style: { width: panelWidth },
3997
- children: /* @__PURE__ */ jsxs("div", { className: "max-h-[480px] overflow-y-auto py-2", children: [
4046
+ style: { width: (mobileAlign == null ? void 0 : mobileAlign.width) ?? panelWidth },
4047
+ children: /* @__PURE__ */ jsxs("div", { className: "max-h-[480px] overflow-y-auto", children: [
3998
4048
  !hasItems && /* @__PURE__ */ jsx("div", { className: "px-4 py-8 text-center text-sm text-muted-foreground", children: emptyText }),
3999
4049
  groups.map((group) => /* @__PURE__ */ jsxs("div", { className: "w-full", children: [
4000
- /* @__PURE__ */ jsx(NotificationDivider, { label: group.label }),
4050
+ showGroupLabels && group.label ? /* @__PURE__ */ jsx(NotificationDivider, { label: group.label }) : null,
4001
4051
  /* @__PURE__ */ jsx("div", { className: "divide-y divide-divider", children: group.items.map((item) => /* @__PURE__ */ jsx(
4002
4052
  NotificationRow,
4003
4053
  {
4004
4054
  item,
4005
- onItemClick
4055
+ onItemClick: handleItemClick,
4056
+ hideIndicator: clickedItemIds.has(item.id),
4057
+ demoteNewBackground: wasDismissed
4006
4058
  },
4007
4059
  item.id
4008
4060
  )) })