lecom-ui 2.4.9 → 2.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.
@@ -0,0 +1,34 @@
1
+ import * as React from 'react';
2
+ import { useReactTable, getCoreRowModel, getSortedRowModel, flexRender } from '@tanstack/react-table';
3
+ import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../Table/Table.js';
4
+
5
+ function DataTable({
6
+ columns,
7
+ data,
8
+ noResults
9
+ }) {
10
+ const [sorting, setSorting] = React.useState([]);
11
+ const table = useReactTable({
12
+ data,
13
+ columns,
14
+ getCoreRowModel: getCoreRowModel(),
15
+ onSortingChange: setSorting,
16
+ getSortedRowModel: getSortedRowModel(),
17
+ state: {
18
+ sorting
19
+ }
20
+ });
21
+ return /* @__PURE__ */ React.createElement("div", { className: "rounded-md border" }, /* @__PURE__ */ React.createElement(Table, null, /* @__PURE__ */ React.createElement(TableHeader, null, table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ React.createElement(TableRow, { key: headerGroup.id }, headerGroup.headers.map((header) => /* @__PURE__ */ React.createElement(TableHead, { key: header.id }, header.isPlaceholder ? null : flexRender(
22
+ header.column.columnDef.header,
23
+ header.getContext()
24
+ )))))), /* @__PURE__ */ React.createElement(TableBody, null, table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) => /* @__PURE__ */ React.createElement(
25
+ TableRow,
26
+ {
27
+ key: row.id,
28
+ "data-state": row.getIsSelected() && "selected"
29
+ },
30
+ row.getVisibleCells().map((cell) => /* @__PURE__ */ React.createElement(TableCell, { key: cell.id }, flexRender(cell.column.columnDef.cell, cell.getContext())))
31
+ )) : /* @__PURE__ */ React.createElement(TableRow, null, /* @__PURE__ */ React.createElement(TableCell, { colSpan: columns.length }, noResults ?? /* @__PURE__ */ React.createElement("div", { className: "text-center" }, "No results."))))));
32
+ }
33
+
34
+ export { DataTable };
@@ -0,0 +1,77 @@
1
+ import { forwardRef } from 'react';
2
+ import { cn } from '../../lib/utils.js';
3
+ import { cva } from 'class-variance-authority';
4
+ import { NotificationCallout } from './NotificationCallout.js';
5
+ import { NotificationInline } from './NotificationInline.js';
6
+ import { MemoizedNotificationToast } from './NotificationToast.js';
7
+
8
+ var TypeMessageNotification = /* @__PURE__ */ ((TypeMessageNotification2) => {
9
+ TypeMessageNotification2["SUCCESS"] = "success";
10
+ TypeMessageNotification2["ERROR"] = "error";
11
+ TypeMessageNotification2["INFORMATION"] = "information";
12
+ TypeMessageNotification2["WARNING"] = "warning";
13
+ return TypeMessageNotification2;
14
+ })(TypeMessageNotification || {});
15
+ const notificationVariants = cva(
16
+ "px-4 py-2 rounded-lg gap-4 relative grid w-full m-0",
17
+ {
18
+ variants: {
19
+ variant: {
20
+ success: "bg-green-100",
21
+ error: "bg-red-100",
22
+ information: "bg-blue-100",
23
+ warning: "bg-yellow-100"
24
+ }
25
+ },
26
+ defaultVariants: {
27
+ variant: "information"
28
+ }
29
+ }
30
+ );
31
+ const posistionMap = {
32
+ topRight: "top-0 right-0",
33
+ topLeft: "top-0 left-0",
34
+ bottomRight: "bottom-0 right-0",
35
+ bottomLeft: "bottom-0 left-0"
36
+ };
37
+ const renderNotification = (props) => {
38
+ switch (props.type) {
39
+ case "toast":
40
+ return /* @__PURE__ */ React.createElement(MemoizedNotificationToast, { ...props });
41
+ case "inline":
42
+ return /* @__PURE__ */ React.createElement(NotificationInline, { ...props });
43
+ case "callout":
44
+ return /* @__PURE__ */ React.createElement(NotificationCallout, { ...props });
45
+ default:
46
+ return null;
47
+ }
48
+ };
49
+ const getPositionClass = (type, placement = "topRight") => {
50
+ if (type === "toast" && placement) {
51
+ return posistionMap[placement];
52
+ }
53
+ return "";
54
+ };
55
+ const Notification = forwardRef(
56
+ ({ ...props }, ref) => {
57
+ const { type, placement } = props;
58
+ const { shouldExpand } = props;
59
+ const widthStyle = shouldExpand ? "w-full" : "inline-block";
60
+ const positionClass = getPositionClass(type, placement);
61
+ return /* @__PURE__ */ React.createElement(
62
+ "main",
63
+ {
64
+ className: cn(
65
+ widthStyle,
66
+ type === "toast" && "fixed z-50 p-4 space-y-2",
67
+ positionClass
68
+ ),
69
+ ref
70
+ },
71
+ renderNotification(props)
72
+ );
73
+ }
74
+ );
75
+ Notification.displayName = "Notification";
76
+
77
+ export { Notification, TypeMessageNotification, getPositionClass, notificationVariants };
@@ -0,0 +1,23 @@
1
+ import { cn } from '../../lib/utils.js';
2
+ import { notificationVariants } from './Notification.js';
3
+
4
+ const NotificationBase = ({
5
+ variant,
6
+ onMouseEnter,
7
+ onMouseLeave,
8
+ children,
9
+ className,
10
+ dataTestId
11
+ }) => /* @__PURE__ */ React.createElement(
12
+ "div",
13
+ {
14
+ className: cn(notificationVariants({ variant }), className),
15
+ onMouseEnter,
16
+ onMouseLeave,
17
+ "data-testid": dataTestId,
18
+ "aria-hidden": "true"
19
+ },
20
+ children
21
+ );
22
+
23
+ export { NotificationBase };
@@ -0,0 +1,84 @@
1
+ import { useState, useRef, useEffect } from 'react';
2
+ import { cn } from '../../lib/utils.js';
3
+ import { ChevronUpIcon } from 'lucide-react';
4
+ import { NotificationBase } from './NotificationBase.js';
5
+ import { NotificationContent } from './NotificationContent.js';
6
+ import { NotificationIcon } from './NotificationIcon.js';
7
+
8
+ const NotificationCallout = ({ ...props }) => {
9
+ const [isCollapsed, setIsCollapsed] = useState(false);
10
+ const [shouldCollapse, setShouldCollapse] = useState(false);
11
+ const [contentHeight, setContentHeight] = useState(0);
12
+ const [lineHeight, setLineHeight] = useState(0);
13
+ const refCollapse = useRef(null);
14
+ const contentRef = useRef(null);
15
+ useEffect(() => {
16
+ if (contentRef.current) {
17
+ const computedStyle = window.getComputedStyle(contentRef.current);
18
+ const lineHeight2 = parseFloat(computedStyle.lineHeight);
19
+ setLineHeight(lineHeight2);
20
+ setContentHeight(contentRef.current.scrollHeight);
21
+ }
22
+ }, [props.content]);
23
+ useEffect(() => {
24
+ const shouldCollapse2 = contentHeight > lineHeight * (props.action ? 3 : 2);
25
+ setShouldCollapse(shouldCollapse2);
26
+ }, [contentHeight, lineHeight]);
27
+ useEffect(() => {
28
+ if (isCollapsed) {
29
+ refCollapse.current?.style.setProperty("transform", "rotate(180deg)");
30
+ } else {
31
+ refCollapse.current?.style.setProperty("transform", "rotate(0deg)");
32
+ }
33
+ }, [isCollapsed]);
34
+ const handleCollapse = () => setIsCollapsed(!isCollapsed);
35
+ const defaultVariant = props.variant ?? "information";
36
+ const getGridColumns = () => {
37
+ if (props.shouldExpand) {
38
+ return shouldCollapse ? "grid-cols-[1.25rem_1fr_minmax(1.25rem,_auto)]" : "grid-cols-[1.25rem_1fr]";
39
+ } else {
40
+ return shouldCollapse ? "grid-cols-[1.25rem_auto_minmax(1.25rem,_auto)]" : "grid-cols-[1.25rem_auto]";
41
+ }
42
+ };
43
+ const getCollapseClass = () => {
44
+ if (isCollapsed && !props.title)
45
+ return "max-h-6 overflow-hidden line-clamp-1";
46
+ if (isCollapsed && props.title) return "max-h-0 overflow-hidden";
47
+ return "no-collapse";
48
+ };
49
+ return /* @__PURE__ */ React.createElement(
50
+ NotificationBase,
51
+ {
52
+ variant: defaultVariant,
53
+ className: cn(getGridColumns(), isCollapsed && "place-items-center"),
54
+ dataTestId: "notification-callout"
55
+ },
56
+ /* @__PURE__ */ React.createElement(NotificationIcon, { variant: defaultVariant }),
57
+ /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-0.5" }, /* @__PURE__ */ React.createElement(
58
+ NotificationContent,
59
+ {
60
+ title: props.title,
61
+ content: props.content,
62
+ ref: contentRef,
63
+ className: cn(
64
+ "transition-all duration-300",
65
+ isCollapsed && getCollapseClass()
66
+ )
67
+ }
68
+ ), props.action),
69
+ /* @__PURE__ */ React.createElement(
70
+ ChevronUpIcon,
71
+ {
72
+ "data-testid": "collapse-icon",
73
+ onClick: handleCollapse,
74
+ ref: refCollapse,
75
+ className: cn(
76
+ shouldCollapse ? "opacity-100 size-5 text-grey-800 transition-transform duration-200 cursor-pointer hover:text-foreground group-hover:opacity-100" : "opacity-0 pointer-events-none h-0 w-0 absolute"
77
+ )
78
+ }
79
+ )
80
+ );
81
+ };
82
+ NotificationCallout.displayName = "NotificationCallout";
83
+
84
+ export { NotificationCallout };
@@ -0,0 +1,18 @@
1
+ import { cn } from '../../lib/utils.js';
2
+ import { XIcon } from 'lucide-react';
3
+
4
+ const NotificationCloseButton = ({
5
+ onClose,
6
+ enableClose
7
+ }) => /* @__PURE__ */ React.createElement(
8
+ XIcon,
9
+ {
10
+ className: cn(
11
+ enableClose ? "opacity-100 size-5 text-grey-800 cursor-pointer hover:text-foreground group-hover:opacity-100" : "opacity-0 pointer-events-none h-0 w-0 absolute"
12
+ ),
13
+ onClick: onClose,
14
+ "data-testid": "close-icon"
15
+ }
16
+ );
17
+
18
+ export { NotificationCloseButton };
@@ -0,0 +1,24 @@
1
+ import { forwardRef } from 'react';
2
+ import { Typography } from '../Typography/Typography.js';
3
+
4
+ const NotificationContent = forwardRef(({ title, content, className, children }, ref) => /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-0.5 flex-1" }, title && /* @__PURE__ */ React.createElement(
5
+ Typography,
6
+ {
7
+ variant: "body-medium-500",
8
+ color: "grey-800",
9
+ "data-testid": "title"
10
+ },
11
+ title
12
+ ), /* @__PURE__ */ React.createElement("div", { ref, className, "data-testid": "collapse-content" }, /* @__PURE__ */ React.createElement(
13
+ Typography,
14
+ {
15
+ variant: "body-medium-400",
16
+ color: "grey-800",
17
+ "data-testid": "content"
18
+ },
19
+ content,
20
+ children
21
+ ))));
22
+ NotificationContent.displayName = "NotificationContent";
23
+
24
+ export { NotificationContent };
@@ -0,0 +1,13 @@
1
+ import { CircleCheckIcon, CircleAlertIcon, InfoIcon, TriangleAlertIcon } from 'lucide-react';
2
+
3
+ const iconMap = {
4
+ success: /* @__PURE__ */ React.createElement(CircleCheckIcon, { className: "text-green-600 size-5" }),
5
+ error: /* @__PURE__ */ React.createElement(CircleAlertIcon, { className: "text-red-600 size-5" }),
6
+ information: /* @__PURE__ */ React.createElement(InfoIcon, { className: "text-blue-600 size-5" }),
7
+ warning: /* @__PURE__ */ React.createElement(TriangleAlertIcon, { className: "size-5 text-yellow-600" })
8
+ };
9
+ const NotificationIcon = ({
10
+ variant
11
+ }) => iconMap[variant];
12
+
13
+ export { NotificationIcon };
@@ -0,0 +1,76 @@
1
+ import { useState } from 'react';
2
+ import { cn } from '../../lib/utils.js';
3
+ import { NotificationBase } from './NotificationBase.js';
4
+ import { NotificationCloseButton } from './NotificationCloseButton.js';
5
+ import { NotificationContent } from './NotificationContent.js';
6
+ import { NotificationIcon } from './NotificationIcon.js';
7
+
8
+ const NotificationInline = ({
9
+ variant,
10
+ enableClose,
11
+ content,
12
+ title,
13
+ action,
14
+ shouldExpand
15
+ }) => {
16
+ const [isVisible, setIsVisible] = useState(true);
17
+ if (!isVisible) return null;
18
+ const defaultVariant = variant ?? "information";
19
+ const getFullWidthColumns = () => {
20
+ if (action && enableClose) {
21
+ return "grid grid-cols-[1.25rem_1fr_auto_minmax(1.25rem,_auto)]";
22
+ } else if (action) {
23
+ return "grid grid-cols-[1.25rem_1fr_auto]";
24
+ } else if (enableClose) {
25
+ return "grid grid-cols-[1.25rem_1fr_minmax(1.25rem,_auto)]";
26
+ } else {
27
+ return "grid grid-cols-[1.25rem_1fr]";
28
+ }
29
+ };
30
+ const getNonFullWidthColumns = () => {
31
+ if (action && enableClose) {
32
+ return "grid-cols-[1.25rem_auto_auto_1.25rem]";
33
+ } else if (action) {
34
+ return "grid-cols-[1.25rem_auto_auto]";
35
+ } else if (enableClose) {
36
+ return "grid-cols-[1.25rem_auto_1.25rem]";
37
+ } else {
38
+ return "grid-cols-[1.25rem_auto]";
39
+ }
40
+ };
41
+ const getGridColumns = () => {
42
+ if (shouldExpand) {
43
+ return getFullWidthColumns();
44
+ } else {
45
+ return getNonFullWidthColumns();
46
+ }
47
+ };
48
+ return /* @__PURE__ */ React.createElement(
49
+ NotificationBase,
50
+ {
51
+ variant: defaultVariant,
52
+ className: cn(getGridColumns()),
53
+ dataTestId: "notification-inline"
54
+ },
55
+ /* @__PURE__ */ React.createElement(NotificationIcon, { variant: defaultVariant }),
56
+ /* @__PURE__ */ React.createElement(
57
+ NotificationContent,
58
+ {
59
+ title,
60
+ content,
61
+ className: "max-h-10 overflow-hidden"
62
+ }
63
+ ),
64
+ action,
65
+ /* @__PURE__ */ React.createElement(
66
+ NotificationCloseButton,
67
+ {
68
+ enableClose: enableClose ?? false,
69
+ onClose: () => setIsVisible(false)
70
+ }
71
+ )
72
+ );
73
+ };
74
+ NotificationInline.displayName = "NotificationInline";
75
+
76
+ export { NotificationInline };
@@ -0,0 +1,128 @@
1
+ import { memo, useState, useRef, useEffect, useMemo } from 'react';
2
+ import { cn } from '../../lib/utils.js';
3
+ import { NotificationBase } from './NotificationBase.js';
4
+ import { NotificationCloseButton } from './NotificationCloseButton.js';
5
+ import { NotificationContent } from './NotificationContent.js';
6
+ import { NotificationIcon } from './NotificationIcon.js';
7
+ import { useNotificationToast, TOAST_REMOVE_DELAY } from './useNotificationToast.js';
8
+
9
+ const NotificationToast = (props) => {
10
+ const { toasts, closeNotification, pauseNotification, resumeNotification } = useNotificationToast();
11
+ const [progressMap, setProgressMap] = useState({});
12
+ const progressMapRef = useRef({});
13
+ const isPausedMapRef = useRef({});
14
+ const remainingTimeMapRef = useRef({});
15
+ const lastUpdateMapRef = useRef({});
16
+ useEffect(() => {
17
+ const now = Date.now();
18
+ const newProgress = { ...progressMapRef.current };
19
+ const newRemainingTime = { ...remainingTimeMapRef.current };
20
+ const newLastUpdate = { ...lastUpdateMapRef.current };
21
+ toasts.forEach((toast) => {
22
+ if (!progressMapRef.current[toast.id]) {
23
+ newProgress[toast.id] = 100;
24
+ newRemainingTime[toast.id] = TOAST_REMOVE_DELAY;
25
+ newLastUpdate[toast.id] = now;
26
+ }
27
+ });
28
+ progressMapRef.current = newProgress;
29
+ remainingTimeMapRef.current = newRemainingTime;
30
+ lastUpdateMapRef.current = newLastUpdate;
31
+ setProgressMap(newProgress);
32
+ }, [toasts]);
33
+ useEffect(() => {
34
+ if (toasts.length === 0) return;
35
+ const interval = setInterval(() => {
36
+ const now = Date.now();
37
+ const newProgress = { ...progressMapRef.current };
38
+ Object.keys(newProgress).forEach((id) => {
39
+ if (!isPausedMapRef.current[id]) {
40
+ const elapsedTime = now - lastUpdateMapRef.current[id];
41
+ const remainingTime = remainingTimeMapRef.current[id] - elapsedTime;
42
+ newProgress[id] = remainingTime / TOAST_REMOVE_DELAY * 100;
43
+ remainingTimeMapRef.current[id] = remainingTime;
44
+ lastUpdateMapRef.current[id] = now;
45
+ if (remainingTime <= 0) {
46
+ closeNotification(id);
47
+ }
48
+ }
49
+ });
50
+ progressMapRef.current = newProgress;
51
+ setProgressMap(newProgress);
52
+ }, 100);
53
+ return () => clearInterval(interval);
54
+ }, [toasts, closeNotification]);
55
+ const handleMouseEnter = (id) => {
56
+ if (props.pauseOnHover) {
57
+ pauseNotification(id);
58
+ isPausedMapRef.current[id] = true;
59
+ }
60
+ };
61
+ const handleMouseLeave = (id) => {
62
+ if (props.pauseOnHover) {
63
+ resumeNotification(id);
64
+ isPausedMapRef.current[id] = false;
65
+ lastUpdateMapRef.current[id] = Date.now();
66
+ }
67
+ };
68
+ const getGridColumns = () => {
69
+ if (props.enableClose) {
70
+ return "grid-cols-[1.25rem_minmax(_auto,11rem)_minmax(1.25rem,_auto)]";
71
+ } else {
72
+ return "grid-cols-[1.25rem_minmax(_auto,13.25rem)]";
73
+ }
74
+ };
75
+ const colorMap = useMemo(
76
+ () => ({
77
+ information: "bg-blue-600",
78
+ success: "bg-green-600",
79
+ error: "bg-red-600",
80
+ warning: "bg-yellow-600"
81
+ }),
82
+ []
83
+ );
84
+ const renderAction = () => {
85
+ if (props.action) {
86
+ return /* @__PURE__ */ React.createElement("div", { className: cn(props.showProgress ? "py-2" : "pt-2") }, props.action);
87
+ }
88
+ return null;
89
+ };
90
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, toasts.map((toast) => /* @__PURE__ */ React.createElement(
91
+ NotificationBase,
92
+ {
93
+ key: toast.id,
94
+ variant: toast.variant,
95
+ className: cn(
96
+ "sm:w-[17.5rem] min-w-auto cursor-pointer",
97
+ getGridColumns()
98
+ ),
99
+ onMouseEnter: () => handleMouseEnter(toast.id),
100
+ onMouseLeave: () => handleMouseLeave(toast.id),
101
+ dataTestId: "notification-toast"
102
+ },
103
+ /* @__PURE__ */ React.createElement(NotificationIcon, { variant: toast.variant }),
104
+ /* @__PURE__ */ React.createElement(NotificationContent, { title: toast.title, content: toast.content }, renderAction()),
105
+ /* @__PURE__ */ React.createElement(
106
+ NotificationCloseButton,
107
+ {
108
+ enableClose: props.enableClose ?? false,
109
+ onClose: () => closeNotification(toast.id)
110
+ }
111
+ ),
112
+ props.showProgress && /* @__PURE__ */ React.createElement(
113
+ "div",
114
+ {
115
+ "data-testid": "progress-bar",
116
+ className: cn(
117
+ `absolute bottom-0 left-0 h-1 rounded-b-lg transition-all`,
118
+ colorMap[toast.variant]
119
+ ),
120
+ style: { width: `${progressMap[toast.id] ?? 100}%` }
121
+ }
122
+ )
123
+ )));
124
+ };
125
+ NotificationToast.displayName = "NotificationToast";
126
+ const MemoizedNotificationToast = memo(NotificationToast);
127
+
128
+ export { MemoizedNotificationToast };
@@ -0,0 +1,170 @@
1
+ import React__default from 'react';
2
+
3
+ const TOAST_LIMIT = Infinity;
4
+ const TOAST_REMOVE_DELAY = 5e3;
5
+ const actionTypes = {
6
+ ADD_TOAST: "ADD_TOAST",
7
+ UPDATE_TOAST: "UPDATE_TOAST",
8
+ DISMISS_TOAST: "DISMISS_TOAST",
9
+ REMOVE_TOAST: "REMOVE_TOAST",
10
+ PAUSE_TOAST: "PAUSE_TOAST",
11
+ RESUME_TOAST: "RESUME_TOAST"
12
+ };
13
+ let count = 0;
14
+ function genId() {
15
+ count = (count + 1) % Number.MAX_SAFE_INTEGER;
16
+ return count.toString();
17
+ }
18
+ const toastTimeouts = /* @__PURE__ */ new Map();
19
+ const toastStartTimes = /* @__PURE__ */ new Map();
20
+ const remainingTimes = /* @__PURE__ */ new Map();
21
+ const addToRemoveQueue = (toastId) => {
22
+ if (toastTimeouts.has(toastId)) return;
23
+ const startTime = Date.now();
24
+ toastStartTimes.set(toastId, startTime);
25
+ const timeout = setTimeout(() => {
26
+ dispatch({ type: actionTypes.REMOVE_TOAST, toastId });
27
+ }, TOAST_REMOVE_DELAY);
28
+ toastTimeouts.set(toastId, timeout);
29
+ };
30
+ const pauseToastTimeout = (toastId) => {
31
+ if (!toastId || !toastTimeouts.has(toastId)) return;
32
+ const startTime = toastStartTimes.get(toastId) ?? Date.now();
33
+ const elapsedTime = Date.now() - startTime;
34
+ const remainingTime = Math.max(TOAST_REMOVE_DELAY - elapsedTime, 0);
35
+ remainingTimes.set(toastId, remainingTime);
36
+ clearTimeout(toastTimeouts.get(toastId));
37
+ toastTimeouts.delete(toastId);
38
+ };
39
+ const resumeToastTimeout = (toastId) => {
40
+ if (!toastId || toastTimeouts.has(toastId)) return;
41
+ const remainingTime = remainingTimes.get(toastId) ?? TOAST_REMOVE_DELAY;
42
+ const timeout = setTimeout(() => {
43
+ dispatch({ type: actionTypes.REMOVE_TOAST, toastId });
44
+ }, remainingTime);
45
+ toastTimeouts.set(toastId, timeout);
46
+ toastStartTimes.set(toastId, Date.now());
47
+ remainingTimes.delete(toastId);
48
+ };
49
+ const handleAddToast = (state, toast2) => {
50
+ addToRemoveQueue(toast2.id);
51
+ const newToast = {
52
+ ...toast2,
53
+ timeout: null
54
+ };
55
+ const toastLimit = toast2.toastLimit ?? TOAST_LIMIT;
56
+ return {
57
+ ...state,
58
+ toasts: [...state.toasts, newToast].slice(0, toastLimit)
59
+ };
60
+ };
61
+ const handleUpdateToast = (state, toast2) => ({
62
+ ...state,
63
+ toasts: state.toasts.map((t) => t.id === toast2.id ? { ...t, ...toast2 } : t)
64
+ });
65
+ const handleDismissToast = (state, toastId) => {
66
+ if (toastId) {
67
+ pauseToastTimeout(toastId);
68
+ } else {
69
+ state.toasts.forEach((t) => pauseToastTimeout(t.id));
70
+ }
71
+ return {
72
+ ...state,
73
+ toasts: state.toasts.filter((t) => t.id !== toastId)
74
+ };
75
+ };
76
+ const handleRemoveToast = (state, toastId) => {
77
+ if (!toastId) return state;
78
+ toastTimeouts.delete(toastId);
79
+ toastStartTimes.delete(toastId);
80
+ remainingTimes.delete(toastId);
81
+ return {
82
+ ...state,
83
+ toasts: state.toasts.filter((t) => t.id !== toastId)
84
+ };
85
+ };
86
+ const handleAddToastAction = (state, action) => {
87
+ if (action.type === "ADD_TOAST") {
88
+ return handleAddToast(state, action.toast);
89
+ }
90
+ return state;
91
+ };
92
+ const handleUpdateToastAction = (state, action) => {
93
+ if (action.type === "UPDATE_TOAST") {
94
+ return handleUpdateToast(state, action.toast);
95
+ }
96
+ return state;
97
+ };
98
+ const handleDismissToastAction = (state, action) => {
99
+ if (action.type === "DISMISS_TOAST") {
100
+ return handleDismissToast(state, action.toastId);
101
+ }
102
+ return state;
103
+ };
104
+ const handleRemoveToastAction = (state, action) => {
105
+ if (action.type === "REMOVE_TOAST") {
106
+ return handleRemoveToast(state, action.toastId);
107
+ }
108
+ return state;
109
+ };
110
+ const handlePauseToastAction = (state, action) => {
111
+ if (action.type === "PAUSE_TOAST") {
112
+ pauseToastTimeout(action.toastId);
113
+ }
114
+ return state;
115
+ };
116
+ const handleResumeToastAction = (state, action) => {
117
+ if (action.type === "RESUME_TOAST") {
118
+ resumeToastTimeout(action.toastId);
119
+ }
120
+ return state;
121
+ };
122
+ const reducer = (state, action) => {
123
+ state = handleAddToastAction(state, action);
124
+ state = handleUpdateToastAction(state, action);
125
+ state = handleDismissToastAction(state, action);
126
+ state = handleRemoveToastAction(state, action);
127
+ state = handlePauseToastAction(state, action);
128
+ state = handleResumeToastAction(state, action);
129
+ return state;
130
+ };
131
+ const listeners = {};
132
+ let memoryState = { toasts: [] };
133
+ function dispatch(action) {
134
+ memoryState = reducer(memoryState, action);
135
+ for (const listener of Object.values(listeners)) {
136
+ listener(memoryState);
137
+ }
138
+ }
139
+ function toast({ ...props }) {
140
+ const id = genId();
141
+ const newToast = {
142
+ ...props,
143
+ id,
144
+ open: true,
145
+ timeout: null,
146
+ onOpenChange: (open) => {
147
+ if (!open) dispatch({ type: actionTypes.DISMISS_TOAST, toastId: id });
148
+ }
149
+ };
150
+ dispatch({ type: actionTypes.ADD_TOAST, toast: newToast });
151
+ }
152
+ function useNotificationToast() {
153
+ const [state, setState] = React__default.useState(memoryState);
154
+ React__default.useEffect(() => {
155
+ const id = genId();
156
+ listeners[id] = setState;
157
+ return () => {
158
+ delete listeners[id];
159
+ };
160
+ }, []);
161
+ return {
162
+ toasts: state.toasts,
163
+ toast,
164
+ closeNotification: (toastId) => dispatch({ type: actionTypes.DISMISS_TOAST, toastId }),
165
+ resumeNotification: (toastId) => dispatch({ type: actionTypes.RESUME_TOAST, toastId }),
166
+ pauseNotification: (toastId) => dispatch({ type: actionTypes.PAUSE_TOAST, toastId })
167
+ };
168
+ }
169
+
170
+ export { TOAST_REMOVE_DELAY, reducer, toast, useNotificationToast };
@@ -1,3 +1,4 @@
1
+ import * as React from 'react';
1
2
  import { cn } from '../../lib/utils.js';
2
3
 
3
4
  const Skeleton = ({