@sarunyu/system-one 4.4.1 → 4.5.1

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/AGENTS.md CHANGED
@@ -20,6 +20,10 @@ in this package.** This file is the short version: the rules you must follow.
20
20
  - Custom tables → use `<Table>` + `<TableRow>` + `<TableHeaderCell>` + `<TableCell>`.
21
21
  - Custom modals/dialogs/alerts → use `<Modal>` (wrap it in your own `fixed inset-0` backdrop).
22
22
  - Custom bottom sheets / drawers from the bottom → use `<BottomSheet>` (it ships its own backdrop via Vaul).
23
+ - Custom inline status banners → use `<Alert>` (never hand-roll tinted divs with icons).
24
+ - Custom toast / snackbar notifications → use `<Toast>` / `<ToastStack>` in a `fixed` portal.
25
+ - Filter buttons with count badges → use `<Badge>` (`variant="button"`).
26
+ - Notification bell + list panel → use `<Notification>`. Never use `<Badge variant="notification">` standalone or wire it to a custom `onClick` (toast, popover, etc.) — `<Notification>` handles both the bell and the panel.
23
27
 
24
28
  2. **Use token-backed Tailwind classes for color.** Never emit hard-coded colors:
25
29
  - Hex (`#3b82f6`), arbitrary (`bg-[#...]`), and palette utilities
@@ -43,6 +47,11 @@ in this package.** This file is the short version: the rules you must follow.
43
47
  - One `<Button variant="primary">` per context.
44
48
  - `Modal` renders the panel only — provide your own `fixed inset-0` backdrop + open/close state. One primary action per modal.
45
49
  - `BottomSheet` is mobile-only. On desktop, use `Modal` instead.
50
+ - `Alert` is always-visible (no open state). Pass `status` + `message`; add `onClose` only for dismissible alerts.
51
+ - `Toast` / `ToastStack` are floating — render them in a `fixed` portal (`fixed bottom-4 right-4 z-50`). Never inline them in page flow.
52
+ - `Badge variant="button"` (default) — filter button with optional count. Pass `count`, `label`, `iconOnly`, and `onClick`.
53
+ - `Badge variant="notification"` — internal to `<Notification>`; never use standalone or attach your own `onClick` to it.
54
+ - `Notification` manages its own popover; pass `groups` (array of `{ label, items }`). It renders both the bell trigger and the panel. This is the only correct way to show a notification list.
46
55
 
47
56
  6. **Mobile forms and action-heavy modals MUST use `<BottomSheet>`, not `<Modal>`.**
48
57
  Login, signup, settings panels, profile editors, any multi-field form,
package/README.md CHANGED
@@ -68,6 +68,10 @@ ships no `Page`/`Section`/`Stack` primitives — use whatever layout looks right
68
68
  | `Table` | Data tables (`TableRow` / `TableHeaderCell` / `TableCell`) |
69
69
  | `Modal` | Centered overlay — dialog / content / alert variants |
70
70
  | `BottomSheet` | Mobile-first bottom sheet (Vaul-based, with backdrop) |
71
+ | `Alert` | Inline persistent status banner — information / success / warning / critical |
72
+ | `Toast` / `ToastStack` | Floating transient notification — default and broadcast variants |
73
+ | `Badge` | Count badge overlay on a trigger (notification bell or filter button) |
74
+ | `Notification` | Bell trigger + popover panel with grouped notification items |
71
75
 
72
76
  Full prop reference: [`llms.txt`](./llms.txt).
73
77
 
@@ -124,6 +128,9 @@ import type {
124
128
  InputProps, DropdownOption,
125
129
  ToggleSize, ToggleProps,
126
130
  ModalVariant, ModalActionLayout,
131
+ AlertStatus,
132
+ ToastVariant, ToastStatus,
133
+ NotificationItem, NotificationGroup,
127
134
  } from "@sarunyu/system-one";
128
135
  ```
129
136
 
package/dist/index.cjs CHANGED
@@ -247,6 +247,141 @@ const Button = React.forwardRef(function Button2({
247
247
  );
248
248
  });
249
249
  Button.displayName = "Button";
250
+ function formatCount(count, maxCount) {
251
+ if (count > maxCount) return `${maxCount}+`;
252
+ return String(count);
253
+ }
254
+ function Badge({
255
+ variant = "button",
256
+ count = 0,
257
+ maxCount = 99,
258
+ label = "Filter",
259
+ iconOnly = false,
260
+ icon,
261
+ notificationState,
262
+ className,
263
+ ...props
264
+ }) {
265
+ const hasCount = count > 0;
266
+ const isActive = hasCount;
267
+ const resolvedNotificationState = notificationState ?? (hasCount ? "noti" : "default");
268
+ const notificationIsFilled = resolvedNotificationState === "active" || resolvedNotificationState === "noti";
269
+ const showNotificationDot = resolvedNotificationState === "noti" && hasCount;
270
+ const visualIcon = variant === "notification" ? notificationIsFilled ? /* @__PURE__ */ jsxRuntime.jsx(react.BellSimple, { size: 19, weight: "fill" }) : /* @__PURE__ */ jsxRuntime.jsx(react.BellSimple, { size: 19, weight: "regular" }) : icon ?? /* @__PURE__ */ jsxRuntime.jsx(react.FunnelSimple, { size: 18, weight: "regular" });
271
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative inline-flex", className), children: [
272
+ variant === "notification" ? /* @__PURE__ */ jsxRuntime.jsx(
273
+ Button,
274
+ {
275
+ "aria-label": "Notification",
276
+ size: "icon-xs",
277
+ variant: "plain-black",
278
+ className: cn(
279
+ "text-subtle-text",
280
+ notificationIsFilled && "text-primary-action"
281
+ ),
282
+ ...props,
283
+ children: visualIcon
284
+ }
285
+ ) : iconOnly ? /* @__PURE__ */ jsxRuntime.jsx(
286
+ Button,
287
+ {
288
+ "aria-label": label,
289
+ size: "icon-md",
290
+ variant: isActive ? "outline" : "outline-black",
291
+ className: cn(isActive && "bg-primary-action-light border-primary-action-light"),
292
+ ...props,
293
+ children: visualIcon
294
+ }
295
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
296
+ Button,
297
+ {
298
+ size: "md",
299
+ leftIcon: visualIcon,
300
+ variant: isActive ? "outline" : "outline-black",
301
+ className: cn(isActive && "bg-primary-action-light border-primary-action-light"),
302
+ ...props,
303
+ children: label
304
+ }
305
+ ),
306
+ (variant === "notification" ? showNotificationDot : hasCount) && /* @__PURE__ */ jsxRuntime.jsx(
307
+ "div",
308
+ {
309
+ className: cn(
310
+ "absolute flex items-center justify-center rounded-[60px] px-1",
311
+ 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"
312
+ ),
313
+ children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-center text-xs leading-4 text-on-primary-action", children: formatCount(count, maxCount) })
314
+ }
315
+ )
316
+ ] });
317
+ }
318
+ const alertStyles = {
319
+ normal: {
320
+ container: "bg-default-secondary",
321
+ text: "text-default-secondary",
322
+ icon: "text-default-secondary"
323
+ },
324
+ information: {
325
+ container: "bg-[var(--bg-info-light)]",
326
+ text: "text-[var(--text-info-primary)]",
327
+ icon: "text-[var(--icon-brand-primary)]"
328
+ },
329
+ success: {
330
+ container: "bg-[var(--bg-success-light)]",
331
+ text: "text-[var(--text-success-primary)]",
332
+ icon: "text-[var(--icon-success)]"
333
+ },
334
+ warning: {
335
+ container: "bg-[var(--bg-warning-soft)]",
336
+ text: "text-[var(--text-warning-primary)]",
337
+ icon: "text-[var(--icon-warning)]"
338
+ },
339
+ critical: {
340
+ container: "bg-[var(--bg-danger-light)]",
341
+ text: "text-[var(--text-danger-primary)]",
342
+ icon: "text-[var(--icon-danger)]"
343
+ }
344
+ };
345
+ function AlertStatusIcon({
346
+ status,
347
+ className
348
+ }) {
349
+ if (status === "success") return /* @__PURE__ */ jsxRuntime.jsx(react.CheckCircle, { size: 16, weight: "fill", className });
350
+ if (status === "warning") return /* @__PURE__ */ jsxRuntime.jsx(react.Warning, { size: 16, weight: "fill", className });
351
+ if (status === "critical") return /* @__PURE__ */ jsxRuntime.jsx(react.XCircle, { size: 16, weight: "fill", className });
352
+ return /* @__PURE__ */ jsxRuntime.jsx(react.Info, { size: 16, weight: "fill", className });
353
+ }
354
+ const Alert = React.forwardRef(function Alert2({ status = "normal", message, multiline = false, className }, ref) {
355
+ const style = alertStyles[status];
356
+ return /* @__PURE__ */ jsxRuntime.jsxs(
357
+ "div",
358
+ {
359
+ ref,
360
+ role: "status",
361
+ className: cn(
362
+ "flex w-full items-center gap-1.5 rounded px-2 py-1",
363
+ multiline && "items-start",
364
+ style.container,
365
+ className
366
+ ),
367
+ children: [
368
+ /* @__PURE__ */ jsxRuntime.jsx(AlertStatusIcon, { status, className: cn("shrink-0", multiline && "mt-0.5", style.icon) }),
369
+ /* @__PURE__ */ jsxRuntime.jsx(
370
+ "p",
371
+ {
372
+ className: cn(
373
+ "min-w-0 flex-1 text-sm leading-5 font-normal",
374
+ multiline ? "line-clamp-2" : "truncate",
375
+ style.text
376
+ ),
377
+ children: message
378
+ }
379
+ )
380
+ ]
381
+ }
382
+ );
383
+ });
384
+ Alert.displayName = "Alert";
250
385
  function BannerMedia({ src, alt }) {
251
386
  if (!src) {
252
387
  return /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": "true", className: "absolute inset-0 bg-muted" });
@@ -3740,6 +3875,293 @@ function ModalActions({
3740
3875
  )
3741
3876
  ] });
3742
3877
  }
3878
+ function NotificationDivider({ label }) {
3879
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 px-4 py-2", children: [
3880
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "shrink-0 text-sm leading-5 text-subtle-text", children: label }),
3881
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": "true", className: "h-px min-w-0 flex-1 bg-divider" })
3882
+ ] });
3883
+ }
3884
+ function NotificationRow({
3885
+ item,
3886
+ onItemClick
3887
+ }) {
3888
+ const rowType = item.type ?? "icon";
3889
+ const showImage = rowType === "image";
3890
+ const showUnread = Boolean(item.unread);
3891
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3892
+ "div",
3893
+ {
3894
+ className: cn(
3895
+ "flex w-full items-start gap-3 px-4 py-3",
3896
+ showUnread ? "bg-primary-action-light/40" : "bg-background"
3897
+ ),
3898
+ role: "button",
3899
+ tabIndex: 0,
3900
+ onClick: () => onItemClick == null ? void 0 : onItemClick(item),
3901
+ onKeyDown: (e) => {
3902
+ if (e.key === "Enter" || e.key === " ") {
3903
+ e.preventDefault();
3904
+ onItemClick == null ? void 0 : onItemClick(item);
3905
+ }
3906
+ },
3907
+ children: [
3908
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex w-10 shrink-0 items-start justify-center py-0.5", children: showImage ? item.imageSrc ? /* @__PURE__ */ jsxRuntime.jsx(
3909
+ "img",
3910
+ {
3911
+ alt: "",
3912
+ className: "h-10 w-10 rounded object-cover",
3913
+ src: item.imageSrc
3914
+ }
3915
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded bg-disabled-bg text-disabled", children: /* @__PURE__ */ jsxRuntime.jsx(react.ImageSquare, { size: 20, weight: "regular" }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-6 w-6 items-center justify-center text-subtle-text", children: item.icon ?? /* @__PURE__ */ jsxRuntime.jsx(react.Circle, { size: 20, weight: "regular" }) }) }),
3916
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
3917
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_auto] items-start gap-x-2", children: [
3918
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "min-w-0 flex-1 truncate text-base leading-6 font-bold text-foreground", children: item.title }),
3919
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [
3920
+ showUnread && /* @__PURE__ */ jsxRuntime.jsx(
3921
+ "span",
3922
+ {
3923
+ "aria-hidden": "true",
3924
+ className: "h-2 w-2 rounded-full bg-primary-action"
3925
+ }
3926
+ ),
3927
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs leading-4 text-muted-foreground", children: item.time })
3928
+ ] }),
3929
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "col-start-1 mt-1 line-clamp-2 text-sm leading-5 text-muted-foreground", children: item.description })
3930
+ ] }),
3931
+ item.actionLabel && /* @__PURE__ */ jsxRuntime.jsx(
3932
+ Button,
3933
+ {
3934
+ className: "mt-2",
3935
+ size: "md",
3936
+ variant: "primary",
3937
+ onClick: (e) => {
3938
+ var _a;
3939
+ e.stopPropagation();
3940
+ (_a = item.onActionClick) == null ? void 0 : _a.call(item);
3941
+ },
3942
+ children: item.actionLabel
3943
+ }
3944
+ )
3945
+ ] })
3946
+ ]
3947
+ }
3948
+ );
3949
+ }
3950
+ const Notification = React.forwardRef(
3951
+ function Notification2({
3952
+ groups,
3953
+ badgeCount,
3954
+ panelWidth = 375,
3955
+ emptyText = "No notifications",
3956
+ clearBadgeOnOpen = true,
3957
+ open,
3958
+ defaultOpen,
3959
+ onOpenChange,
3960
+ onBadgeCleared,
3961
+ onItemClick,
3962
+ className,
3963
+ panelClassName
3964
+ }, ref) {
3965
+ const [internalOpen, setInternalOpen] = React.useState(defaultOpen ?? false);
3966
+ const [isBadgeCleared, setIsBadgeCleared] = React.useState(false);
3967
+ const controlled = open !== void 0;
3968
+ const resolvedOpen = controlled ? open : internalOpen;
3969
+ const unreadCount = React.useMemo(
3970
+ () => groups.reduce(
3971
+ (acc, group) => acc + group.items.filter((item) => Boolean(item.unread)).length,
3972
+ 0
3973
+ ),
3974
+ [groups]
3975
+ );
3976
+ const nextCount = badgeCount ?? unreadCount;
3977
+ const prevCountRef = React.useRef(nextCount);
3978
+ React.useEffect(() => {
3979
+ const prevCount = prevCountRef.current;
3980
+ if (nextCount <= 0 || nextCount > prevCount) {
3981
+ setIsBadgeCleared(false);
3982
+ }
3983
+ prevCountRef.current = nextCount;
3984
+ }, [nextCount]);
3985
+ const displayCount = clearBadgeOnOpen && isBadgeCleared ? 0 : nextCount;
3986
+ const hasItems = groups.some((group) => group.items.length > 0);
3987
+ const handleOpenChange = (next) => {
3988
+ if (next && clearBadgeOnOpen && nextCount > 0) {
3989
+ setIsBadgeCleared(true);
3990
+ onBadgeCleared == null ? void 0 : onBadgeCleared();
3991
+ }
3992
+ if (!controlled) setInternalOpen(next);
3993
+ onOpenChange == null ? void 0 : onOpenChange(next);
3994
+ };
3995
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: resolvedOpen, onOpenChange: handleOpenChange, children: [
3996
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("inline-flex", className), children: /* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsx(
3997
+ Badge,
3998
+ {
3999
+ variant: "notification",
4000
+ count: displayCount,
4001
+ maxCount: 99,
4002
+ notificationState: displayCount > 0 ? "noti" : resolvedOpen ? "active" : "default",
4003
+ "aria-label": "Open notifications"
4004
+ }
4005
+ ) }) }) }),
4006
+ /* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
4007
+ Popover__namespace.Content,
4008
+ {
4009
+ align: "end",
4010
+ sideOffset: 10,
4011
+ className: cn(
4012
+ "z-50 overflow-hidden rounded-lg border border-border bg-background shadow-lg",
4013
+ panelClassName
4014
+ ),
4015
+ style: { width: panelWidth },
4016
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-h-[480px] overflow-y-auto py-2", children: [
4017
+ !hasItems && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-8 text-center text-sm text-muted-foreground", children: emptyText }),
4018
+ groups.map((group) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full", children: [
4019
+ /* @__PURE__ */ jsxRuntime.jsx(NotificationDivider, { label: group.label }),
4020
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-divider", children: group.items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
4021
+ NotificationRow,
4022
+ {
4023
+ item,
4024
+ onItemClick
4025
+ },
4026
+ item.id
4027
+ )) })
4028
+ ] }, group.label))
4029
+ ] })
4030
+ }
4031
+ ) })
4032
+ ] });
4033
+ }
4034
+ );
4035
+ Notification.displayName = "Notification";
4036
+ const statusStyles = {
4037
+ information: {
4038
+ bg: "bg-[var(--bg-info-light)]",
4039
+ text: "text-[var(--text-info-primary)]",
4040
+ icon: "text-[var(--icon-brand-primary)]",
4041
+ link: "text-[var(--text-brand-link-primary)]"
4042
+ },
4043
+ success: {
4044
+ bg: "bg-[var(--bg-success-light)]",
4045
+ text: "text-[var(--text-success-primary)]",
4046
+ icon: "text-[var(--icon-success)]",
4047
+ link: "text-[var(--text-success-link)]"
4048
+ },
4049
+ warning: {
4050
+ bg: "bg-[var(--bg-warning-soft)]",
4051
+ text: "text-[var(--text-warning-primary)]",
4052
+ icon: "text-[var(--icon-warning)]",
4053
+ link: "text-[var(--text-warning-link)]"
4054
+ },
4055
+ critical: {
4056
+ bg: "bg-[var(--bg-danger-light)]",
4057
+ text: "text-[var(--text-danger-primary)]",
4058
+ icon: "text-[var(--icon-danger)]",
4059
+ link: "text-[var(--text-danger-link)]"
4060
+ }
4061
+ };
4062
+ function DefaultIcon({
4063
+ status,
4064
+ className
4065
+ }) {
4066
+ if (status === "success") return /* @__PURE__ */ jsxRuntime.jsx(react.CheckCircle, { className, size: 24, weight: "fill" });
4067
+ if (status === "warning") return /* @__PURE__ */ jsxRuntime.jsx(react.Warning, { className, size: 24, weight: "fill" });
4068
+ if (status === "critical") return /* @__PURE__ */ jsxRuntime.jsx(react.XCircle, { className, size: 24, weight: "fill" });
4069
+ return /* @__PURE__ */ jsxRuntime.jsx(react.Info, { className, size: 24, weight: "fill" });
4070
+ }
4071
+ function BroadcastIcon({
4072
+ status,
4073
+ className
4074
+ }) {
4075
+ if (status === "information") {
4076
+ return /* @__PURE__ */ jsxRuntime.jsx(react.MegaphoneSimple, { className, size: 20, weight: "fill" });
4077
+ }
4078
+ return /* @__PURE__ */ jsxRuntime.jsx(react.GearSix, { className, size: 20, weight: "fill" });
4079
+ }
4080
+ function ToastCloseButton({
4081
+ colorClass,
4082
+ onClose
4083
+ }) {
4084
+ return /* @__PURE__ */ jsxRuntime.jsx(
4085
+ "button",
4086
+ {
4087
+ type: "button",
4088
+ "aria-label": "Close toast",
4089
+ className: cn(
4090
+ "inline-flex h-[18px] w-[18px] shrink-0 cursor-pointer items-center justify-center",
4091
+ colorClass
4092
+ ),
4093
+ onClick: onClose,
4094
+ children: /* @__PURE__ */ jsxRuntime.jsx(react.X, { size: 12, weight: "bold" })
4095
+ }
4096
+ );
4097
+ }
4098
+ const Toast = React.forwardRef(function Toast2({
4099
+ variant = "default",
4100
+ status = "information",
4101
+ message,
4102
+ actionLabel,
4103
+ multiline = false,
4104
+ onActionClick,
4105
+ onClose,
4106
+ className
4107
+ }, ref) {
4108
+ const hasAction = Boolean(actionLabel);
4109
+ const effectiveStatus = variant === "broadcast" && status === "success" ? "information" : status;
4110
+ const effectiveStyle = statusStyles[effectiveStatus];
4111
+ const Icon = variant === "broadcast" ? BroadcastIcon : DefaultIcon;
4112
+ const showActions = variant === "default";
4113
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4114
+ "div",
4115
+ {
4116
+ ref,
4117
+ role: "status",
4118
+ className: cn(
4119
+ "flex w-full p-3",
4120
+ variant === "default" ? "items-center gap-2 rounded-lg shadow-[0px_1px_2px_0px_rgba(0,0,0,0.10),0px_1px_3px_1px_rgba(0,0,0,0.05)]" : "items-center gap-2",
4121
+ multiline && "items-start",
4122
+ effectiveStyle.bg,
4123
+ className
4124
+ ),
4125
+ children: [
4126
+ /* @__PURE__ */ jsxRuntime.jsxs(
4127
+ "div",
4128
+ {
4129
+ className: cn(
4130
+ "flex min-w-0 flex-1 gap-2",
4131
+ multiline ? "items-start" : "items-center",
4132
+ variant === "default" && !hasAction && "opacity-80"
4133
+ ),
4134
+ children: [
4135
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("shrink-0", multiline && "pt-0.5"), children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { status: effectiveStatus, className: effectiveStyle.icon }) }),
4136
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("min-w-0 flex-1 text-sm leading-5 font-normal", effectiveStyle.text), children: message })
4137
+ ]
4138
+ }
4139
+ ),
4140
+ showActions && hasAction ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-3", children: [
4141
+ /* @__PURE__ */ jsxRuntime.jsx(
4142
+ "button",
4143
+ {
4144
+ type: "button",
4145
+ className: cn(
4146
+ "cursor-pointer text-sm leading-5 underline underline-offset-2",
4147
+ effectiveStyle.link
4148
+ ),
4149
+ onClick: onActionClick,
4150
+ children: actionLabel
4151
+ }
4152
+ ),
4153
+ /* @__PURE__ */ jsxRuntime.jsx(ToastCloseButton, { colorClass: effectiveStyle.icon, onClose })
4154
+ ] }) : showActions ? /* @__PURE__ */ jsxRuntime.jsx(ToastCloseButton, { colorClass: effectiveStyle.icon, onClose }) : null
4155
+ ]
4156
+ }
4157
+ );
4158
+ });
4159
+ Toast.displayName = "Toast";
4160
+ function ToastStack({ items, className, renderItem }) {
4161
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col gap-2", className), children: items.map(
4162
+ (item) => renderItem ? /* @__PURE__ */ jsxRuntime.jsx("div", { children: renderItem(item) }, item.id) : /* @__PURE__ */ jsxRuntime.jsx(Toast, { ...item }, item.id)
4163
+ ) });
4164
+ }
3743
4165
  const OptionList = React.forwardRef(
3744
4166
  function OptionList2({
3745
4167
  options,
@@ -5372,6 +5794,8 @@ const TimeInput = React.forwardRef(
5372
5794
  }
5373
5795
  );
5374
5796
  TimeInput.displayName = "TimeInput";
5797
+ exports.Alert = Alert;
5798
+ exports.Badge = Badge;
5375
5799
  exports.BottomSheet = BottomSheet;
5376
5800
  exports.Button = Button;
5377
5801
  exports.Card = Card;
@@ -5382,6 +5806,7 @@ exports.Dropdown = Dropdown;
5382
5806
  exports.DropdownMultiple = DropdownMultiple;
5383
5807
  exports.Input = Input;
5384
5808
  exports.Modal = Modal;
5809
+ exports.Notification = Notification;
5385
5810
  exports.OptionList = OptionList;
5386
5811
  exports.Radio = Radio;
5387
5812
  exports.SearchInput = SearchInput;
@@ -5395,6 +5820,8 @@ exports.TableRow = TableRow;
5395
5820
  exports.Tag = Tag;
5396
5821
  exports.TextArea = TextArea;
5397
5822
  exports.TimeInput = TimeInput;
5823
+ exports.Toast = Toast;
5824
+ exports.ToastStack = ToastStack;
5398
5825
  exports.Toggle = Toggle;
5399
5826
  exports.cn = cn;
5400
5827
  exports.useIsMobile = useIsMobile;