@pk-design/react-tailwind 1.10.3 → 1.11.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/dist/cjs/components/SegmentedControl/SegmentedControl.js +6 -2
- package/dist/cjs/components/SegmentedControl/SegmentedControl.js.map +1 -1
- package/dist/cjs/components/Toast/Toast.js +3 -1
- package/dist/cjs/components/Toast/Toast.js.map +1 -1
- package/dist/cjs/components/Toast/ToastProvider.js +10 -5
- package/dist/cjs/components/Toast/ToastProvider.js.map +1 -1
- package/dist/es/components/SegmentedControl/SegmentedControl.js +6 -2
- package/dist/es/components/SegmentedControl/SegmentedControl.js.map +1 -1
- package/dist/es/components/Toast/Toast.js +3 -1
- package/dist/es/components/Toast/Toast.js.map +1 -1
- package/dist/es/components/Toast/ToastProvider.js +10 -5
- package/dist/es/components/Toast/ToastProvider.js.map +1 -1
- package/dist/react-tailwind.cjs.js +19 -9
- package/dist/react-tailwind.cjs.js.map +1 -1
- package/dist/react-tailwind.es.js +19 -9
- package/dist/react-tailwind.es.js.map +1 -1
- package/dist/types/components/Toast/Toast.types.d.ts +18 -2
- package/package.json +1 -1
|
@@ -53,9 +53,13 @@ const SegmentedControl = React.forwardRef((props, ref) => {
|
|
|
53
53
|
if (!isOptionDisabled) {
|
|
54
54
|
onChange(option.value);
|
|
55
55
|
}
|
|
56
|
-
}, onKeyDown: (e) => handleKeyDown(e, index), className: buildClassname.buildClassName('inline-flex items-center justify-center gap-1.5 transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary-ring)]', SIZE_OPTION_CLASS[size],
|
|
56
|
+
}, onKeyDown: (e) => handleKeyDown(e, index), className: buildClassname.buildClassName('inline-flex items-center justify-center gap-1.5 transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary-ring)]', SIZE_OPTION_CLASS[size],
|
|
57
|
+
// Full width splits the row equally, so the width comes from the
|
|
58
|
+
// row, not padding; tight side padding keeps labels on one line
|
|
59
|
+
// on narrow screens.
|
|
60
|
+
fullWidth ? 'min-w-0 flex-1 px-1.5' : '', isOptionDisabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer', isSelected
|
|
57
61
|
? 'bg-white text-[var(--ui-primary)] dark:bg-gray-700 dark:text-blue-400 shadow-xs font-semibold'
|
|
58
|
-
: 'text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100'), "data-testid": `segmented-option-${option.value}`, children: [option.icon && (jsxRuntime.jsx("span", { className: buildClassname.buildClassName('shrink-0 inline-flex items-center justify-center', SIZE_ICON_CLASS[size]), children: option.icon })), jsxRuntime.jsx("span", { children: option.label })] }, option.value));
|
|
62
|
+
: 'text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100'), "data-testid": `segmented-option-${option.value}`, children: [option.icon && (jsxRuntime.jsx("span", { className: buildClassname.buildClassName('shrink-0 inline-flex items-center justify-center', SIZE_ICON_CLASS[size]), children: option.icon })), jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: option.label })] }, option.value));
|
|
59
63
|
}) }));
|
|
60
64
|
});
|
|
61
65
|
SegmentedControl.displayName = 'SegmentedControl';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SegmentedControl.js","sources":["../../../../../src/components/SegmentedControl/SegmentedControl.tsx"],"sourcesContent":["import React, { forwardRef } from 'react'\nimport { buildClassName } from '../../utils/build-classname'\nimport type { SegmentedControlProps } from './SegmentedControl.types'\n\nconst SIZE_CONTAINER_CLASS = {\n sm: 'p-0.5 gap-0.5 rounded-lg text-xs',\n md: 'p-1 gap-1 rounded-xl text-sm',\n lg: 'p-1.5 gap-1.5 rounded-xl text-base',\n}\n\nconst SIZE_OPTION_CLASS = {\n sm: 'px-2 py-1 text-xs font-medium rounded-md',\n md: 'px-3 py-1.5 text-sm font-semibold rounded-lg',\n lg: 'px-4 py-2 text-base font-semibold rounded-lg',\n}\n\nconst SIZE_ICON_CLASS = {\n sm: 'size-3.5',\n md: 'size-4',\n lg: 'size-5',\n}\n\nexport const SegmentedControl = forwardRef<HTMLDivElement, SegmentedControlProps>((props, ref) => {\n const {\n options,\n value,\n onChange,\n disabled = false,\n size = 'md',\n fullWidth = false,\n className,\n ...restProps\n } = props\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLButtonElement>, currentIndex: number) => {\n const enabledOptions = options.filter((opt) => !opt.disabled && !disabled)\n if (enabledOptions.length === 0) return\n\n if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {\n e.preventDefault()\n const currentPos = enabledOptions.findIndex(\n (opt) => opt.value === options[currentIndex].value,\n )\n const nextPos = (currentPos + 1) % enabledOptions.length\n onChange(enabledOptions[nextPos].value)\n } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {\n e.preventDefault()\n const currentPos = enabledOptions.findIndex(\n (opt) => opt.value === options[currentIndex].value,\n )\n const prevPos = (currentPos - 1 + enabledOptions.length) % enabledOptions.length\n onChange(enabledOptions[prevPos].value)\n } else if (e.key === 'Home') {\n e.preventDefault()\n onChange(enabledOptions[0].value)\n } else if (e.key === 'End') {\n e.preventDefault()\n onChange(enabledOptions[enabledOptions.length - 1].value)\n }\n }\n\n return (\n <div\n ref={ref}\n role=\"tablist\"\n aria-orientation=\"horizontal\"\n className={buildClassName(\n 'inline-flex items-center border border-[var(--ui-border)] bg-gray-100/80 dark:bg-gray-800/80',\n SIZE_CONTAINER_CLASS[size],\n fullWidth ? 'w-full flex' : '',\n disabled ? 'opacity-60 cursor-not-allowed' : '',\n className,\n )}\n data-testid=\"segmented-control\"\n {...restProps}\n >\n {options.map((option, index) => {\n const isSelected = value === option.value\n const isOptionDisabled = disabled || option.disabled\n\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"tab\"\n aria-selected={isSelected}\n aria-disabled={isOptionDisabled}\n tabIndex={isSelected && !isOptionDisabled ? 0 : -1}\n disabled={isOptionDisabled}\n title={option.title}\n onClick={() => {\n if (!isOptionDisabled) {\n onChange(option.value)\n }\n }}\n onKeyDown={(e) => handleKeyDown(e, index)}\n className={buildClassName(\n 'inline-flex items-center justify-center gap-1.5 transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary-ring)]',\n SIZE_OPTION_CLASS[size],\n fullWidth ? 'flex-1' : '',\n isOptionDisabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer',\n isSelected\n ? 'bg-white text-[var(--ui-primary)] dark:bg-gray-700 dark:text-blue-400 shadow-xs font-semibold'\n : 'text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100',\n )}\n data-testid={`segmented-option-${option.value}`}\n >\n {option.icon && (\n <span\n className={buildClassName(\n 'shrink-0 inline-flex items-center justify-center',\n SIZE_ICON_CLASS[size],\n )}\n >\n {option.icon}\n </span>\n )}\n <span>{option.label}</span>\n </button>\n )\n })}\n </div>\n )\n})\n\nSegmentedControl.displayName = 'SegmentedControl'\n"],"names":["forwardRef","_jsx","buildClassName","_jsxs"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"SegmentedControl.js","sources":["../../../../../src/components/SegmentedControl/SegmentedControl.tsx"],"sourcesContent":["import React, { forwardRef } from 'react'\nimport { buildClassName } from '../../utils/build-classname'\nimport type { SegmentedControlProps } from './SegmentedControl.types'\n\nconst SIZE_CONTAINER_CLASS = {\n sm: 'p-0.5 gap-0.5 rounded-lg text-xs',\n md: 'p-1 gap-1 rounded-xl text-sm',\n lg: 'p-1.5 gap-1.5 rounded-xl text-base',\n}\n\nconst SIZE_OPTION_CLASS = {\n sm: 'px-2 py-1 text-xs font-medium rounded-md',\n md: 'px-3 py-1.5 text-sm font-semibold rounded-lg',\n lg: 'px-4 py-2 text-base font-semibold rounded-lg',\n}\n\nconst SIZE_ICON_CLASS = {\n sm: 'size-3.5',\n md: 'size-4',\n lg: 'size-5',\n}\n\nexport const SegmentedControl = forwardRef<HTMLDivElement, SegmentedControlProps>((props, ref) => {\n const {\n options,\n value,\n onChange,\n disabled = false,\n size = 'md',\n fullWidth = false,\n className,\n ...restProps\n } = props\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLButtonElement>, currentIndex: number) => {\n const enabledOptions = options.filter((opt) => !opt.disabled && !disabled)\n if (enabledOptions.length === 0) return\n\n if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {\n e.preventDefault()\n const currentPos = enabledOptions.findIndex(\n (opt) => opt.value === options[currentIndex].value,\n )\n const nextPos = (currentPos + 1) % enabledOptions.length\n onChange(enabledOptions[nextPos].value)\n } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {\n e.preventDefault()\n const currentPos = enabledOptions.findIndex(\n (opt) => opt.value === options[currentIndex].value,\n )\n const prevPos = (currentPos - 1 + enabledOptions.length) % enabledOptions.length\n onChange(enabledOptions[prevPos].value)\n } else if (e.key === 'Home') {\n e.preventDefault()\n onChange(enabledOptions[0].value)\n } else if (e.key === 'End') {\n e.preventDefault()\n onChange(enabledOptions[enabledOptions.length - 1].value)\n }\n }\n\n return (\n <div\n ref={ref}\n role=\"tablist\"\n aria-orientation=\"horizontal\"\n className={buildClassName(\n 'inline-flex items-center border border-[var(--ui-border)] bg-gray-100/80 dark:bg-gray-800/80',\n SIZE_CONTAINER_CLASS[size],\n fullWidth ? 'w-full flex' : '',\n disabled ? 'opacity-60 cursor-not-allowed' : '',\n className,\n )}\n data-testid=\"segmented-control\"\n {...restProps}\n >\n {options.map((option, index) => {\n const isSelected = value === option.value\n const isOptionDisabled = disabled || option.disabled\n\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"tab\"\n aria-selected={isSelected}\n aria-disabled={isOptionDisabled}\n tabIndex={isSelected && !isOptionDisabled ? 0 : -1}\n disabled={isOptionDisabled}\n title={option.title}\n onClick={() => {\n if (!isOptionDisabled) {\n onChange(option.value)\n }\n }}\n onKeyDown={(e) => handleKeyDown(e, index)}\n className={buildClassName(\n 'inline-flex items-center justify-center gap-1.5 transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary-ring)]',\n SIZE_OPTION_CLASS[size],\n // Full width splits the row equally, so the width comes from the\n // row, not padding; tight side padding keeps labels on one line\n // on narrow screens.\n fullWidth ? 'min-w-0 flex-1 px-1.5' : '',\n isOptionDisabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer',\n isSelected\n ? 'bg-white text-[var(--ui-primary)] dark:bg-gray-700 dark:text-blue-400 shadow-xs font-semibold'\n : 'text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100',\n )}\n data-testid={`segmented-option-${option.value}`}\n >\n {option.icon && (\n <span\n className={buildClassName(\n 'shrink-0 inline-flex items-center justify-center',\n SIZE_ICON_CLASS[size],\n )}\n >\n {option.icon}\n </span>\n )}\n {/* A label never wraps; if there's truly no room it's cut off. */}\n <span className=\"min-w-0 truncate\">{option.label}</span>\n </button>\n )\n })}\n </div>\n )\n})\n\nSegmentedControl.displayName = 'SegmentedControl'\n"],"names":["forwardRef","_jsx","buildClassName","_jsxs"],"mappings":"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"}
|
|
@@ -86,7 +86,9 @@ const Toast = ({ id, title, message, type, variant = 'accent', action, icon, sho
|
|
|
86
86
|
const enterFrom = isTop ? 'opacity-0 -translate-y-3 scale-95' : 'opacity-0 translate-y-3 scale-95';
|
|
87
87
|
const leaveTo = isTop ? 'opacity-0 -translate-y-2 scale-95' : 'opacity-0 translate-y-2 scale-95';
|
|
88
88
|
const renderedIcon = icon !== null && icon !== void 0 ? icon : (variant === 'filled' ? filledIconMap[type] : iconMap[type]);
|
|
89
|
-
return (jsxRuntime.jsx(react.Transition, { appear: true, show: true, enter: "transform transition duration-300 ease-out", enterFrom: enterFrom, enterTo: "opacity-100 translate-y-0 scale-100", leave: "transition duration-200 ease-in", leaveFrom: "opacity-100 translate-y-0 scale-100", leaveTo: leaveTo, children: jsxRuntime.jsxs("div", { role: "status", id: id.toString(), className: buildClassname.buildClassName(
|
|
89
|
+
return (jsxRuntime.jsx(react.Transition, { appear: true, show: true, enter: "transform transition duration-300 ease-out", enterFrom: enterFrom, enterTo: "opacity-100 translate-y-0 scale-100", leave: "transition duration-200 ease-in", leaveFrom: "opacity-100 translate-y-0 scale-100", leaveTo: leaveTo, children: jsxRuntime.jsxs("div", { role: "status", id: id.toString(), className: buildClassname.buildClassName(
|
|
90
|
+
// Never wider than the viewport minus a 16px gutter each side.
|
|
91
|
+
'relative overflow-hidden flex items-start gap-3 rounded-xl px-4 py-3.5 min-w-[min(280px,calc(100vw-2rem))] max-w-[min(28rem,calc(100vw-2rem))] transition-all', variantStyleMap[variant][type], className), children: [jsxRuntime.jsx("div", { className: "shrink-0 mt-0.5", children: variant === 'filled' ? (renderedIcon) : (jsxRuntime.jsx(TextContent.TextContent, { className: buildClassname.buildClassName(textColorMap[type]), children: renderedIcon })) }), jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col gap-0.5", children: [title && (jsxRuntime.jsx("div", { className: buildClassname.buildClassName('font-semibold text-sm leading-snug', variant === 'filled' ? 'text-white' : 'text-gray-900 dark:text-gray-100'), children: title })), jsxRuntime.jsx("div", { className: buildClassname.buildClassName('text-sm font-medium leading-relaxed', variant === 'filled' ? 'text-white/95' : 'text-gray-700 dark:text-gray-300'), children: message }), action && (jsxRuntime.jsx("div", { className: "mt-1.5", children: jsxRuntime.jsx("button", { type: "button", onClick: action.onClick, className: buildClassname.buildClassName('text-xs font-semibold underline underline-offset-2 transition-opacity focus:outline-none', variant === 'filled'
|
|
90
92
|
? 'text-white hover:opacity-85'
|
|
91
93
|
: 'text-[var(--ui-primary)] hover:opacity-80'), children: action.label }) }))] }), jsxRuntime.jsx(Button.Button, { onClick: onClose, "aria-label": "Close toast", className: buildClassname.buildClassName('shrink-0 mt-0.5 opacity-60 hover:opacity-100 focus-visible:opacity-100 transition', variant === 'filled' && 'text-white hover:text-white focus-visible:outline-current'), iconOnly: true, size: "xs", variant: "plain", theme: variant === 'filled' ? 'primary' : 'secondary', children: jsxRuntime.jsx(X.default, { className: "size-4" }) }), showProgressBar && duration > 0 && (jsxRuntime.jsx("div", { className: "absolute bottom-0 left-0 right-0 h-1 bg-black/10 dark:bg-white/10 overflow-hidden", children: jsxRuntime.jsx("div", { className: buildClassname.buildClassName('h-full transition-all duration-75 ease-linear', variant === 'filled' ? 'bg-white/70' : progressBarColorMap[type]), style: { width: `${Math.max(0, progress)}%` } }) }))] }) }));
|
|
92
94
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toast.js","sources":["../../../../../src/components/Toast/Toast.tsx"],"sourcesContent":["import React, { useEffect, useState } from 'react'\nimport { Transition } from '@headlessui/react'\nimport XIcon from '../Icons/X.svg'\nimport CheckCircle from '../Icons/CircleCheck.svg'\nimport AlertCircle from '../Icons/CircleAlert.svg'\nimport Info from '../Icons/Info.svg'\nimport AlertTriangle from '../Icons/TriangleAlert.svg'\n\nimport { Button } from '../Button'\nimport { TextContent } from '../TextContent'\nimport { buildClassName } from '../../utils/build-classname'\n\nimport type { ToastProps, ToastType, ToastVariant } from './Toast.types'\n\n/**\n * Icons for each toast type\n */\nconst iconMap: Record<ToastType, React.ReactNode> = {\n success: <CheckCircle className=\"size-5 text-[var(--ui-success)]\" />,\n error: <AlertCircle className=\"size-5 text-[var(--ui-danger)]\" />,\n info: <Info className=\"size-5 text-[var(--ui-info)]\" />,\n warning: <AlertTriangle className=\"size-5 text-[var(--ui-warning)]\" />,\n}\n\nconst filledIconMap: Record<ToastType, React.ReactNode> = {\n success: <CheckCircle className=\"size-5 text-white\" />,\n error: <AlertCircle className=\"size-5 text-white\" />,\n info: <Info className=\"size-5 text-white\" />,\n warning: <AlertTriangle className=\"size-5 text-white\" />,\n}\n\nconst textColorMap: Record<ToastType, string> = {\n success: 'text-[var(--ui-success-text)]',\n error: 'text-[var(--ui-danger-text)]',\n info: 'text-[var(--ui-info-text)]',\n warning: 'text-[var(--ui-warning-text)]',\n}\n\nconst progressBarColorMap: Record<ToastType, string> = {\n success: 'bg-[var(--ui-success)]',\n error: 'bg-[var(--ui-danger)]',\n info: 'bg-[var(--ui-info)]',\n warning: 'bg-[var(--ui-warning)]',\n}\n\nconst variantStyleMap: Record<ToastVariant, Record<ToastType, string>> = {\n accent: {\n success:\n 'bg-white dark:bg-gray-900 border-l-4 border-[var(--ui-success)] text-gray-900 dark:text-gray-100 shadow-lg border-y border-r border-[var(--ui-border)]',\n error:\n 'bg-white dark:bg-gray-900 border-l-4 border-[var(--ui-danger)] text-gray-900 dark:text-gray-100 shadow-lg border-y border-r border-[var(--ui-border)]',\n info: 'bg-white dark:bg-gray-900 border-l-4 border-[var(--ui-info)] text-gray-900 dark:text-gray-100 shadow-lg border-y border-r border-[var(--ui-border)]',\n warning:\n 'bg-white dark:bg-gray-900 border-l-4 border-[var(--ui-warning)] text-gray-900 dark:text-gray-100 shadow-lg border-y border-r border-[var(--ui-border)]',\n },\n filled: {\n success: 'bg-[var(--ui-success)] text-white shadow-lg',\n error: 'bg-[var(--ui-danger)] text-white shadow-lg',\n info: 'bg-[var(--ui-info)] text-white shadow-lg',\n warning: 'bg-[var(--ui-warning)] text-white shadow-lg',\n },\n outlined: {\n success:\n 'bg-white dark:bg-gray-900 border-2 border-[var(--ui-success)] text-gray-900 dark:text-gray-100 shadow-md',\n error:\n 'bg-white dark:bg-gray-900 border-2 border-[var(--ui-danger)] text-gray-900 dark:text-gray-100 shadow-md',\n info: 'bg-white dark:bg-gray-900 border-2 border-[var(--ui-info)] text-gray-900 dark:text-gray-100 shadow-md',\n warning:\n 'bg-white dark:bg-gray-900 border-2 border-[var(--ui-warning)] text-gray-900 dark:text-gray-100 shadow-md',\n },\n glass: {\n success:\n 'backdrop-blur-md bg-white/85 dark:bg-gray-900/85 border border-emerald-500/30 text-gray-900 dark:text-gray-100 shadow-xl',\n error:\n 'backdrop-blur-md bg-white/85 dark:bg-gray-900/85 border border-rose-500/30 text-gray-900 dark:text-gray-100 shadow-xl',\n info: 'backdrop-blur-md bg-white/85 dark:bg-gray-900/85 border border-blue-500/30 text-gray-900 dark:text-gray-100 shadow-xl',\n warning:\n 'backdrop-blur-md bg-white/85 dark:bg-gray-900/85 border border-amber-500/30 text-gray-900 dark:text-gray-100 shadow-xl',\n },\n}\n\nexport const Toast: React.FC<ToastProps & { isTop?: boolean }> = ({\n id,\n title,\n message,\n type,\n variant = 'accent',\n action,\n icon,\n showProgressBar = true,\n duration = 4000,\n isPaused = false,\n onClose,\n className,\n isTop = true,\n}) => {\n const [progress, setProgress] = useState(100)\n\n useEffect(() => {\n if (!showProgressBar || !duration || isPaused) return\n\n const intervalTime = 50\n const step = (intervalTime / duration) * 100\n\n const timer = setInterval(() => {\n setProgress((prev) => {\n if (prev <= 0) {\n clearInterval(timer)\n return 0\n }\n return prev - step\n })\n }, intervalTime)\n\n return () => clearInterval(timer)\n }, [showProgressBar, duration, isPaused])\n\n const enterFrom = isTop ? 'opacity-0 -translate-y-3 scale-95' : 'opacity-0 translate-y-3 scale-95'\n const leaveTo = isTop ? 'opacity-0 -translate-y-2 scale-95' : 'opacity-0 translate-y-2 scale-95'\n\n const renderedIcon = icon ?? (variant === 'filled' ? filledIconMap[type] : iconMap[type])\n\n return (\n <Transition\n appear\n show\n enter=\"transform transition duration-300 ease-out\"\n enterFrom={enterFrom}\n enterTo=\"opacity-100 translate-y-0 scale-100\"\n leave=\"transition duration-200 ease-in\"\n leaveFrom=\"opacity-100 translate-y-0 scale-100\"\n leaveTo={leaveTo}\n >\n <div\n role=\"status\"\n id={id.toString()}\n className={buildClassName(\n 'relative overflow-hidden flex items-start gap-3 rounded-xl px-4 py-3.5 min-w-[280px] max-w-md transition-all',\n variantStyleMap[variant][type],\n className,\n )}\n >\n {/* Icon */}\n <div className=\"shrink-0 mt-0.5\">\n {variant === 'filled' ? (\n renderedIcon\n ) : (\n <TextContent className={buildClassName(textColorMap[type])}>{renderedIcon}</TextContent>\n )}\n </div>\n\n {/* Content Body */}\n <div className=\"flex-1 flex flex-col gap-0.5\">\n {title && (\n <div\n className={buildClassName(\n 'font-semibold text-sm leading-snug',\n variant === 'filled' ? 'text-white' : 'text-gray-900 dark:text-gray-100',\n )}\n >\n {title}\n </div>\n )}\n <div\n className={buildClassName(\n 'text-sm font-medium leading-relaxed',\n variant === 'filled' ? 'text-white/95' : 'text-gray-700 dark:text-gray-300',\n )}\n >\n {message}\n </div>\n\n {/* Action Button */}\n {action && (\n <div className=\"mt-1.5\">\n <button\n type=\"button\"\n onClick={action.onClick}\n className={buildClassName(\n 'text-xs font-semibold underline underline-offset-2 transition-opacity focus:outline-none',\n variant === 'filled'\n ? 'text-white hover:opacity-85'\n : 'text-[var(--ui-primary)] hover:opacity-80',\n )}\n >\n {action.label}\n </button>\n </div>\n )}\n </div>\n\n {/* Close button */}\n <Button\n onClick={onClose}\n aria-label=\"Close toast\"\n className={buildClassName(\n 'shrink-0 mt-0.5 opacity-60 hover:opacity-100 focus-visible:opacity-100 transition',\n variant === 'filled' && 'text-white hover:text-white focus-visible:outline-current',\n )}\n iconOnly\n size=\"xs\"\n variant=\"plain\"\n theme={variant === 'filled' ? 'primary' : 'secondary'}\n >\n <XIcon className=\"size-4\" />\n </Button>\n\n {/* Progress Bar Countdown */}\n {showProgressBar && duration > 0 && (\n <div className=\"absolute bottom-0 left-0 right-0 h-1 bg-black/10 dark:bg-white/10 overflow-hidden\">\n <div\n className={buildClassName(\n 'h-full transition-all duration-75 ease-linear',\n variant === 'filled' ? 'bg-white/70' : progressBarColorMap[type],\n )}\n style={{ width: `${Math.max(0, progress)}%` }}\n />\n </div>\n )}\n </div>\n </Transition>\n )\n}\n\nToast.displayName = 'Toast'\n"],"names":["_jsx","CheckCircle","AlertCircle","Info","AlertTriangle","useState","useEffect","Transition","_jsxs","buildClassName","TextContent","Button","XIcon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Toast.js","sources":["../../../../../src/components/Toast/Toast.tsx"],"sourcesContent":["import React, { useEffect, useState } from 'react'\nimport { Transition } from '@headlessui/react'\nimport XIcon from '../Icons/X.svg'\nimport CheckCircle from '../Icons/CircleCheck.svg'\nimport AlertCircle from '../Icons/CircleAlert.svg'\nimport Info from '../Icons/Info.svg'\nimport AlertTriangle from '../Icons/TriangleAlert.svg'\n\nimport { Button } from '../Button'\nimport { TextContent } from '../TextContent'\nimport { buildClassName } from '../../utils/build-classname'\n\nimport type { ToastProps, ToastType, ToastVariant } from './Toast.types'\n\n/**\n * Icons for each toast type\n */\nconst iconMap: Record<ToastType, React.ReactNode> = {\n success: <CheckCircle className=\"size-5 text-[var(--ui-success)]\" />,\n error: <AlertCircle className=\"size-5 text-[var(--ui-danger)]\" />,\n info: <Info className=\"size-5 text-[var(--ui-info)]\" />,\n warning: <AlertTriangle className=\"size-5 text-[var(--ui-warning)]\" />,\n}\n\nconst filledIconMap: Record<ToastType, React.ReactNode> = {\n success: <CheckCircle className=\"size-5 text-white\" />,\n error: <AlertCircle className=\"size-5 text-white\" />,\n info: <Info className=\"size-5 text-white\" />,\n warning: <AlertTriangle className=\"size-5 text-white\" />,\n}\n\nconst textColorMap: Record<ToastType, string> = {\n success: 'text-[var(--ui-success-text)]',\n error: 'text-[var(--ui-danger-text)]',\n info: 'text-[var(--ui-info-text)]',\n warning: 'text-[var(--ui-warning-text)]',\n}\n\nconst progressBarColorMap: Record<ToastType, string> = {\n success: 'bg-[var(--ui-success)]',\n error: 'bg-[var(--ui-danger)]',\n info: 'bg-[var(--ui-info)]',\n warning: 'bg-[var(--ui-warning)]',\n}\n\nconst variantStyleMap: Record<ToastVariant, Record<ToastType, string>> = {\n accent: {\n success:\n 'bg-white dark:bg-gray-900 border-l-4 border-[var(--ui-success)] text-gray-900 dark:text-gray-100 shadow-lg border-y border-r border-[var(--ui-border)]',\n error:\n 'bg-white dark:bg-gray-900 border-l-4 border-[var(--ui-danger)] text-gray-900 dark:text-gray-100 shadow-lg border-y border-r border-[var(--ui-border)]',\n info: 'bg-white dark:bg-gray-900 border-l-4 border-[var(--ui-info)] text-gray-900 dark:text-gray-100 shadow-lg border-y border-r border-[var(--ui-border)]',\n warning:\n 'bg-white dark:bg-gray-900 border-l-4 border-[var(--ui-warning)] text-gray-900 dark:text-gray-100 shadow-lg border-y border-r border-[var(--ui-border)]',\n },\n filled: {\n success: 'bg-[var(--ui-success)] text-white shadow-lg',\n error: 'bg-[var(--ui-danger)] text-white shadow-lg',\n info: 'bg-[var(--ui-info)] text-white shadow-lg',\n warning: 'bg-[var(--ui-warning)] text-white shadow-lg',\n },\n outlined: {\n success:\n 'bg-white dark:bg-gray-900 border-2 border-[var(--ui-success)] text-gray-900 dark:text-gray-100 shadow-md',\n error:\n 'bg-white dark:bg-gray-900 border-2 border-[var(--ui-danger)] text-gray-900 dark:text-gray-100 shadow-md',\n info: 'bg-white dark:bg-gray-900 border-2 border-[var(--ui-info)] text-gray-900 dark:text-gray-100 shadow-md',\n warning:\n 'bg-white dark:bg-gray-900 border-2 border-[var(--ui-warning)] text-gray-900 dark:text-gray-100 shadow-md',\n },\n glass: {\n success:\n 'backdrop-blur-md bg-white/85 dark:bg-gray-900/85 border border-emerald-500/30 text-gray-900 dark:text-gray-100 shadow-xl',\n error:\n 'backdrop-blur-md bg-white/85 dark:bg-gray-900/85 border border-rose-500/30 text-gray-900 dark:text-gray-100 shadow-xl',\n info: 'backdrop-blur-md bg-white/85 dark:bg-gray-900/85 border border-blue-500/30 text-gray-900 dark:text-gray-100 shadow-xl',\n warning:\n 'backdrop-blur-md bg-white/85 dark:bg-gray-900/85 border border-amber-500/30 text-gray-900 dark:text-gray-100 shadow-xl',\n },\n}\n\nexport const Toast: React.FC<ToastProps & { isTop?: boolean }> = ({\n id,\n title,\n message,\n type,\n variant = 'accent',\n action,\n icon,\n showProgressBar = true,\n duration = 4000,\n isPaused = false,\n onClose,\n className,\n isTop = true,\n}) => {\n const [progress, setProgress] = useState(100)\n\n useEffect(() => {\n if (!showProgressBar || !duration || isPaused) return\n\n const intervalTime = 50\n const step = (intervalTime / duration) * 100\n\n const timer = setInterval(() => {\n setProgress((prev) => {\n if (prev <= 0) {\n clearInterval(timer)\n return 0\n }\n return prev - step\n })\n }, intervalTime)\n\n return () => clearInterval(timer)\n }, [showProgressBar, duration, isPaused])\n\n const enterFrom = isTop ? 'opacity-0 -translate-y-3 scale-95' : 'opacity-0 translate-y-3 scale-95'\n const leaveTo = isTop ? 'opacity-0 -translate-y-2 scale-95' : 'opacity-0 translate-y-2 scale-95'\n\n const renderedIcon = icon ?? (variant === 'filled' ? filledIconMap[type] : iconMap[type])\n\n return (\n <Transition\n appear\n show\n enter=\"transform transition duration-300 ease-out\"\n enterFrom={enterFrom}\n enterTo=\"opacity-100 translate-y-0 scale-100\"\n leave=\"transition duration-200 ease-in\"\n leaveFrom=\"opacity-100 translate-y-0 scale-100\"\n leaveTo={leaveTo}\n >\n <div\n role=\"status\"\n id={id.toString()}\n className={buildClassName(\n // Never wider than the viewport minus a 16px gutter each side.\n 'relative overflow-hidden flex items-start gap-3 rounded-xl px-4 py-3.5 min-w-[min(280px,calc(100vw-2rem))] max-w-[min(28rem,calc(100vw-2rem))] transition-all',\n variantStyleMap[variant][type],\n className,\n )}\n >\n {/* Icon */}\n <div className=\"shrink-0 mt-0.5\">\n {variant === 'filled' ? (\n renderedIcon\n ) : (\n <TextContent className={buildClassName(textColorMap[type])}>{renderedIcon}</TextContent>\n )}\n </div>\n\n {/* Content Body */}\n <div className=\"flex-1 flex flex-col gap-0.5\">\n {title && (\n <div\n className={buildClassName(\n 'font-semibold text-sm leading-snug',\n variant === 'filled' ? 'text-white' : 'text-gray-900 dark:text-gray-100',\n )}\n >\n {title}\n </div>\n )}\n <div\n className={buildClassName(\n 'text-sm font-medium leading-relaxed',\n variant === 'filled' ? 'text-white/95' : 'text-gray-700 dark:text-gray-300',\n )}\n >\n {message}\n </div>\n\n {/* Action Button */}\n {action && (\n <div className=\"mt-1.5\">\n <button\n type=\"button\"\n onClick={action.onClick}\n className={buildClassName(\n 'text-xs font-semibold underline underline-offset-2 transition-opacity focus:outline-none',\n variant === 'filled'\n ? 'text-white hover:opacity-85'\n : 'text-[var(--ui-primary)] hover:opacity-80',\n )}\n >\n {action.label}\n </button>\n </div>\n )}\n </div>\n\n {/* Close button */}\n <Button\n onClick={onClose}\n aria-label=\"Close toast\"\n className={buildClassName(\n 'shrink-0 mt-0.5 opacity-60 hover:opacity-100 focus-visible:opacity-100 transition',\n variant === 'filled' && 'text-white hover:text-white focus-visible:outline-current',\n )}\n iconOnly\n size=\"xs\"\n variant=\"plain\"\n theme={variant === 'filled' ? 'primary' : 'secondary'}\n >\n <XIcon className=\"size-4\" />\n </Button>\n\n {/* Progress Bar Countdown */}\n {showProgressBar && duration > 0 && (\n <div className=\"absolute bottom-0 left-0 right-0 h-1 bg-black/10 dark:bg-white/10 overflow-hidden\">\n <div\n className={buildClassName(\n 'h-full transition-all duration-75 ease-linear',\n variant === 'filled' ? 'bg-white/70' : progressBarColorMap[type],\n )}\n style={{ width: `${Math.max(0, progress)}%` }}\n />\n </div>\n )}\n </div>\n </Transition>\n )\n}\n\nToast.displayName = 'Toast'\n"],"names":["_jsx","CheckCircle","AlertCircle","Info","AlertTriangle","useState","useEffect","Transition","_jsxs","buildClassName","TextContent","Button","XIcon"],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
4
4
|
var React = require('react');
|
|
5
5
|
var Toast = require('./Toast.js');
|
|
6
6
|
var buildClassname = require('../../utils/build-classname.js');
|
|
7
|
+
var useBreakpoint = require('../../hooks/use-breakpoint.js');
|
|
7
8
|
|
|
8
9
|
const ToastContext = React.createContext(undefined);
|
|
9
10
|
let toastCounter = 0;
|
|
@@ -17,11 +18,15 @@ const placementClass = {
|
|
|
17
18
|
'top-right': 'top-20 right-6 items-end',
|
|
18
19
|
'top-left': 'top-20 left-6 items-start',
|
|
19
20
|
'top-center': 'top-20 left-1/2 -translate-x-1/2 items-center',
|
|
20
|
-
|
|
21
|
-
'bottom-
|
|
22
|
-
'bottom-
|
|
21
|
+
// Bottom placements clear the home indicator on notched phones (0 elsewhere).
|
|
22
|
+
'bottom-right': 'bottom-[calc(1.5rem+env(safe-area-inset-bottom,0px))] right-6 items-end',
|
|
23
|
+
'bottom-left': 'bottom-[calc(1.5rem+env(safe-area-inset-bottom,0px))] left-6 items-start',
|
|
24
|
+
'bottom-center': 'bottom-[calc(1.5rem+env(safe-area-inset-bottom,0px))] left-1/2 -translate-x-1/2 items-center',
|
|
23
25
|
};
|
|
24
|
-
const ToastProvider = ({ children, placement = 'top-right', maxToasts = 5, className, }) => {
|
|
26
|
+
const ToastProvider = ({ children, placement: placementProp = 'top-right', maxToasts = 5, offset, className, }) => {
|
|
27
|
+
const placement = useBreakpoint.useResponsiveValue(placementProp);
|
|
28
|
+
const isTop = placement.startsWith('top');
|
|
29
|
+
const edgeOffset = isTop ? offset === null || offset === void 0 ? void 0 : offset.top : offset === null || offset === void 0 ? void 0 : offset.bottom;
|
|
25
30
|
const [toasts, setToasts] = React.useState([]);
|
|
26
31
|
const [pausedIds, setPausedIds] = React.useState(new Set());
|
|
27
32
|
const metaRefs = React.useRef(new Map());
|
|
@@ -142,7 +147,7 @@ const ToastProvider = ({ children, placement = 'top-right', maxToasts = 5, class
|
|
|
142
147
|
dismiss: (id) => closeToast(id),
|
|
143
148
|
dismissAll: () => dismissAll(),
|
|
144
149
|
}), [showToast, closeToast, dismissAll]);
|
|
145
|
-
return (jsxRuntime.jsxs(ToastContext.Provider, { value: { showToast, closeToast, toast: toastHelpers }, children: [children, jsxRuntime.jsx("div", { className: buildClassname.buildClassName('fixed z-[9999] flex flex-col gap-3 pointer-events-none', placementClass[placement], className), children: toasts.map((toastItem) => (jsxRuntime.jsx("div", { className: "pointer-events-auto", onMouseEnter: () => handleMouseEnter(toastItem), onMouseLeave: () => handleMouseLeave(toastItem), children: jsxRuntime.jsx(Toast.Toast, { ...toastItem, isPaused: pausedIds.has(toastItem.id), isTop:
|
|
150
|
+
return (jsxRuntime.jsxs(ToastContext.Provider, { value: { showToast, closeToast, toast: toastHelpers }, children: [children, jsxRuntime.jsx("div", { className: buildClassname.buildClassName('fixed z-[9999] flex flex-col gap-3 pointer-events-none', placementClass[placement], className), style: edgeOffset ? (isTop ? { top: edgeOffset } : { bottom: edgeOffset }) : undefined, "data-testid": "toast-container", "data-placement": placement, children: toasts.map((toastItem) => (jsxRuntime.jsx("div", { className: "pointer-events-auto", onMouseEnter: () => handleMouseEnter(toastItem), onMouseLeave: () => handleMouseLeave(toastItem), children: jsxRuntime.jsx(Toast.Toast, { ...toastItem, isPaused: pausedIds.has(toastItem.id), isTop: isTop, onClose: () => closeToast(toastItem.id) }) }, toastItem.id))) })] }));
|
|
146
151
|
};
|
|
147
152
|
ToastProvider.displayName = 'ToastProvider';
|
|
148
153
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToastProvider.js","sources":["../../../../../src/components/Toast/ToastProvider.tsx"],"sourcesContent":["import React, {\n createContext,\n useContext,\n useEffect,\n useState,\n type ReactNode,\n useRef,\n useCallback,\n useMemo,\n} from 'react'\nimport { Toast } from './Toast'\nimport type {\n IToast,\n ToastContextType,\n ToastOptions,\n ToastPlacement,\n ToastProviderProps,\n} from './Toast.types'\nimport { buildClassName } from '../../utils/build-classname'\n\nconst ToastContext = createContext<ToastContextType | undefined>(undefined)\nlet toastCounter = 0\n\nexport const useToast = (): ToastContextType => {\n const context = useContext(ToastContext)\n if (!context) throw new Error('useToast must be used within ToastProvider')\n return context\n}\n\nconst placementClass: Record<ToastPlacement, string> = {\n 'top-right': 'top-20 right-6 items-end',\n 'top-left': 'top-20 left-6 items-start',\n 'top-center': 'top-20 left-1/2 -translate-x-1/2 items-center',\n\n 'bottom-right': 'bottom-6 right-6 items-end',\n 'bottom-left': 'bottom-6 left-6 items-start',\n 'bottom-center': 'bottom-6 left-1/2 -translate-x-1/2 items-center',\n}\n\ninterface ToastMeta {\n timerId: any\n startTime: number\n remainingTime: number\n}\n\nexport const ToastProvider: React.FC<ToastProviderProps> = ({\n children,\n placement = 'top-right',\n maxToasts = 5,\n className,\n}) => {\n const [toasts, setToasts] = useState<IToast[]>([])\n const [pausedIds, setPausedIds] = useState<Set<number>>(new Set())\n const metaRefs = useRef<Map<number, ToastMeta>>(new Map())\n\n const clearTimer = (id: number) => {\n const meta = metaRefs.current.get(id)\n if (meta?.timerId) {\n clearTimeout(meta.timerId)\n meta.timerId = null\n }\n }\n\n const closeToast = useCallback((id: number) => {\n clearTimer(id)\n metaRefs.current.delete(id)\n setPausedIds((prev) => {\n const next = new Set(prev)\n next.delete(id)\n return next\n })\n setToasts((prev) => prev.filter((t) => t.id !== id))\n }, [])\n\n const dismissAll = useCallback(() => {\n metaRefs.current.forEach((meta) => {\n if (meta.timerId) clearTimeout(meta.timerId)\n })\n metaRefs.current.clear()\n setPausedIds(new Set())\n setToasts([])\n }, [])\n\n const startAutoClose = useCallback(\n (toastId: number, delay: number) => {\n clearTimer(toastId)\n\n const timerId = setTimeout(() => {\n closeToast(toastId)\n }, delay)\n\n const meta = metaRefs.current.get(toastId)\n if (meta) {\n meta.timerId = timerId\n meta.startTime = Date.now()\n meta.remainingTime = delay\n } else {\n metaRefs.current.set(toastId, {\n timerId,\n startTime: Date.now(),\n remainingTime: delay,\n })\n }\n },\n [closeToast],\n )\n\n useEffect(() => {\n const refs = metaRefs.current\n return () =>\n refs.forEach((meta) => {\n if (meta.timerId) clearTimeout(meta.timerId)\n })\n }, [])\n\n const showToast = useCallback(\n (message: ReactNode, options?: ToastOptions): number => {\n const id = ++toastCounter\n\n const newToast: IToast = {\n id,\n title: options?.title,\n message,\n type: options?.type ?? 'info',\n variant: options?.variant ?? 'accent',\n duration: options?.duration ?? 4000,\n autoClose: options?.autoClose ?? true,\n pauseOnHover: options?.pauseOnHover ?? true,\n showProgressBar: options?.showProgressBar ?? options?.autoClose !== false,\n action: options?.action,\n icon: options?.icon,\n }\n\n setToasts((prev) => {\n const updated = [...prev, newToast]\n if (updated.length > maxToasts) updated.shift()\n return updated\n })\n\n if (newToast.autoClose) {\n startAutoClose(id, newToast.duration)\n }\n\n return id\n },\n [maxToasts, startAutoClose],\n )\n\n // Hover pauses timer and tracks exact remaining milliseconds\n const handleMouseEnter = (toast: IToast) => {\n if (!toast.pauseOnHover || !toast.autoClose) return\n\n const meta = metaRefs.current.get(toast.id)\n if (meta) {\n const elapsed = Date.now() - meta.startTime\n meta.remainingTime = Math.max(0, meta.remainingTime - elapsed)\n clearTimer(toast.id)\n setPausedIds((prev) => new Set(prev).add(toast.id))\n }\n }\n\n // Mouse leave resumes timer with exact remaining milliseconds\n const handleMouseLeave = (toast: IToast) => {\n if (!toast.pauseOnHover || !toast.autoClose) return\n\n setPausedIds((prev) => {\n const next = new Set(prev)\n next.delete(toast.id)\n return next\n })\n\n const meta = metaRefs.current.get(toast.id)\n if (meta && meta.remainingTime > 0) {\n startAutoClose(toast.id, meta.remainingTime)\n } else if (meta && meta.remainingTime <= 0) {\n closeToast(toast.id)\n }\n }\n\n const toastHelpers = useMemo(\n () => ({\n show: (message: ReactNode, options?: ToastOptions) => showToast(message, options),\n success: (message: ReactNode, options?: ToastOptions) =>\n showToast(message, { ...options, type: 'success' }),\n error: (message: ReactNode, options?: ToastOptions) =>\n showToast(message, { ...options, type: 'error' }),\n info: (message: ReactNode, options?: ToastOptions) =>\n showToast(message, { ...options, type: 'info' }),\n warning: (message: ReactNode, options?: ToastOptions) =>\n showToast(message, { ...options, type: 'warning' }),\n dismiss: (id: number) => closeToast(id),\n dismissAll: () => dismissAll(),\n }),\n [showToast, closeToast, dismissAll],\n )\n\n return (\n <ToastContext.Provider value={{ showToast, closeToast, toast: toastHelpers }}>\n {children}\n\n {/* Toast Container */}\n <div\n className={buildClassName(\n 'fixed z-[9999] flex flex-col gap-3 pointer-events-none',\n placementClass[placement],\n className,\n )}\n >\n {toasts.map((toastItem) => (\n <div\n key={toastItem.id}\n className=\"pointer-events-auto\"\n onMouseEnter={() => handleMouseEnter(toastItem)}\n onMouseLeave={() => handleMouseLeave(toastItem)}\n >\n <Toast\n {...toastItem}\n isPaused={pausedIds.has(toastItem.id)}\n isTop={placement.startsWith('top')}\n onClose={() => closeToast(toastItem.id)}\n />\n </div>\n ))}\n </div>\n </ToastContext.Provider>\n )\n}\n\nToastProvider.displayName = 'ToastProvider'\n"],"names":["createContext","useContext","useState","useRef","useCallback","useEffect","useMemo","_jsxs","_jsx","buildClassName","Toast"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ToastProvider.js","sources":["../../../../../src/components/Toast/ToastProvider.tsx"],"sourcesContent":["import React, {\n createContext,\n useContext,\n useEffect,\n useState,\n type ReactNode,\n useRef,\n useCallback,\n useMemo,\n} from 'react'\nimport { Toast } from './Toast'\nimport type {\n IToast,\n ToastContextType,\n ToastOptions,\n ToastPlacement,\n ToastProviderProps,\n} from './Toast.types'\nimport { buildClassName } from '../../utils/build-classname'\nimport { useResponsiveValue } from '../../hooks/use-breakpoint'\n\nconst ToastContext = createContext<ToastContextType | undefined>(undefined)\nlet toastCounter = 0\n\nexport const useToast = (): ToastContextType => {\n const context = useContext(ToastContext)\n if (!context) throw new Error('useToast must be used within ToastProvider')\n return context\n}\n\nconst placementClass: Record<ToastPlacement, string> = {\n 'top-right': 'top-20 right-6 items-end',\n 'top-left': 'top-20 left-6 items-start',\n 'top-center': 'top-20 left-1/2 -translate-x-1/2 items-center',\n\n // Bottom placements clear the home indicator on notched phones (0 elsewhere).\n 'bottom-right': 'bottom-[calc(1.5rem+env(safe-area-inset-bottom,0px))] right-6 items-end',\n 'bottom-left': 'bottom-[calc(1.5rem+env(safe-area-inset-bottom,0px))] left-6 items-start',\n 'bottom-center':\n 'bottom-[calc(1.5rem+env(safe-area-inset-bottom,0px))] left-1/2 -translate-x-1/2 items-center',\n}\n\ninterface ToastMeta {\n timerId: any\n startTime: number\n remainingTime: number\n}\n\nexport const ToastProvider: React.FC<ToastProviderProps> = ({\n children,\n placement: placementProp = 'top-right',\n maxToasts = 5,\n offset,\n className,\n}) => {\n const placement = useResponsiveValue(placementProp)\n const isTop = placement.startsWith('top')\n const edgeOffset = isTop ? offset?.top : offset?.bottom\n const [toasts, setToasts] = useState<IToast[]>([])\n const [pausedIds, setPausedIds] = useState<Set<number>>(new Set())\n const metaRefs = useRef<Map<number, ToastMeta>>(new Map())\n\n const clearTimer = (id: number) => {\n const meta = metaRefs.current.get(id)\n if (meta?.timerId) {\n clearTimeout(meta.timerId)\n meta.timerId = null\n }\n }\n\n const closeToast = useCallback((id: number) => {\n clearTimer(id)\n metaRefs.current.delete(id)\n setPausedIds((prev) => {\n const next = new Set(prev)\n next.delete(id)\n return next\n })\n setToasts((prev) => prev.filter((t) => t.id !== id))\n }, [])\n\n const dismissAll = useCallback(() => {\n metaRefs.current.forEach((meta) => {\n if (meta.timerId) clearTimeout(meta.timerId)\n })\n metaRefs.current.clear()\n setPausedIds(new Set())\n setToasts([])\n }, [])\n\n const startAutoClose = useCallback(\n (toastId: number, delay: number) => {\n clearTimer(toastId)\n\n const timerId = setTimeout(() => {\n closeToast(toastId)\n }, delay)\n\n const meta = metaRefs.current.get(toastId)\n if (meta) {\n meta.timerId = timerId\n meta.startTime = Date.now()\n meta.remainingTime = delay\n } else {\n metaRefs.current.set(toastId, {\n timerId,\n startTime: Date.now(),\n remainingTime: delay,\n })\n }\n },\n [closeToast],\n )\n\n useEffect(() => {\n const refs = metaRefs.current\n return () =>\n refs.forEach((meta) => {\n if (meta.timerId) clearTimeout(meta.timerId)\n })\n }, [])\n\n const showToast = useCallback(\n (message: ReactNode, options?: ToastOptions): number => {\n const id = ++toastCounter\n\n const newToast: IToast = {\n id,\n title: options?.title,\n message,\n type: options?.type ?? 'info',\n variant: options?.variant ?? 'accent',\n duration: options?.duration ?? 4000,\n autoClose: options?.autoClose ?? true,\n pauseOnHover: options?.pauseOnHover ?? true,\n showProgressBar: options?.showProgressBar ?? options?.autoClose !== false,\n action: options?.action,\n icon: options?.icon,\n }\n\n setToasts((prev) => {\n const updated = [...prev, newToast]\n if (updated.length > maxToasts) updated.shift()\n return updated\n })\n\n if (newToast.autoClose) {\n startAutoClose(id, newToast.duration)\n }\n\n return id\n },\n [maxToasts, startAutoClose],\n )\n\n // Hover pauses timer and tracks exact remaining milliseconds\n const handleMouseEnter = (toast: IToast) => {\n if (!toast.pauseOnHover || !toast.autoClose) return\n\n const meta = metaRefs.current.get(toast.id)\n if (meta) {\n const elapsed = Date.now() - meta.startTime\n meta.remainingTime = Math.max(0, meta.remainingTime - elapsed)\n clearTimer(toast.id)\n setPausedIds((prev) => new Set(prev).add(toast.id))\n }\n }\n\n // Mouse leave resumes timer with exact remaining milliseconds\n const handleMouseLeave = (toast: IToast) => {\n if (!toast.pauseOnHover || !toast.autoClose) return\n\n setPausedIds((prev) => {\n const next = new Set(prev)\n next.delete(toast.id)\n return next\n })\n\n const meta = metaRefs.current.get(toast.id)\n if (meta && meta.remainingTime > 0) {\n startAutoClose(toast.id, meta.remainingTime)\n } else if (meta && meta.remainingTime <= 0) {\n closeToast(toast.id)\n }\n }\n\n const toastHelpers = useMemo(\n () => ({\n show: (message: ReactNode, options?: ToastOptions) => showToast(message, options),\n success: (message: ReactNode, options?: ToastOptions) =>\n showToast(message, { ...options, type: 'success' }),\n error: (message: ReactNode, options?: ToastOptions) =>\n showToast(message, { ...options, type: 'error' }),\n info: (message: ReactNode, options?: ToastOptions) =>\n showToast(message, { ...options, type: 'info' }),\n warning: (message: ReactNode, options?: ToastOptions) =>\n showToast(message, { ...options, type: 'warning' }),\n dismiss: (id: number) => closeToast(id),\n dismissAll: () => dismissAll(),\n }),\n [showToast, closeToast, dismissAll],\n )\n\n return (\n <ToastContext.Provider value={{ showToast, closeToast, toast: toastHelpers }}>\n {children}\n\n {/* Toast Container */}\n <div\n className={buildClassName(\n 'fixed z-[9999] flex flex-col gap-3 pointer-events-none',\n placementClass[placement],\n className,\n )}\n style={edgeOffset ? (isTop ? { top: edgeOffset } : { bottom: edgeOffset }) : undefined}\n data-testid=\"toast-container\"\n data-placement={placement}\n >\n {toasts.map((toastItem) => (\n <div\n key={toastItem.id}\n className=\"pointer-events-auto\"\n onMouseEnter={() => handleMouseEnter(toastItem)}\n onMouseLeave={() => handleMouseLeave(toastItem)}\n >\n <Toast\n {...toastItem}\n isPaused={pausedIds.has(toastItem.id)}\n isTop={isTop}\n onClose={() => closeToast(toastItem.id)}\n />\n </div>\n ))}\n </div>\n </ToastContext.Provider>\n )\n}\n\nToastProvider.displayName = 'ToastProvider'\n"],"names":["createContext","useContext","useResponsiveValue","useState","useRef","useCallback","useEffect","useMemo","_jsxs","_jsx","buildClassName","Toast"],"mappings":"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"}
|
|
@@ -51,9 +51,13 @@ const SegmentedControl = forwardRef((props, ref) => {
|
|
|
51
51
|
if (!isOptionDisabled) {
|
|
52
52
|
onChange(option.value);
|
|
53
53
|
}
|
|
54
|
-
}, onKeyDown: (e) => handleKeyDown(e, index), className: buildClassName('inline-flex items-center justify-center gap-1.5 transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary-ring)]', SIZE_OPTION_CLASS[size],
|
|
54
|
+
}, onKeyDown: (e) => handleKeyDown(e, index), className: buildClassName('inline-flex items-center justify-center gap-1.5 transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary-ring)]', SIZE_OPTION_CLASS[size],
|
|
55
|
+
// Full width splits the row equally, so the width comes from the
|
|
56
|
+
// row, not padding; tight side padding keeps labels on one line
|
|
57
|
+
// on narrow screens.
|
|
58
|
+
fullWidth ? 'min-w-0 flex-1 px-1.5' : '', isOptionDisabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer', isSelected
|
|
55
59
|
? 'bg-white text-[var(--ui-primary)] dark:bg-gray-700 dark:text-blue-400 shadow-xs font-semibold'
|
|
56
|
-
: 'text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100'), "data-testid": `segmented-option-${option.value}`, children: [option.icon && (jsx("span", { className: buildClassName('shrink-0 inline-flex items-center justify-center', SIZE_ICON_CLASS[size]), children: option.icon })), jsx("span", { children: option.label })] }, option.value));
|
|
60
|
+
: 'text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100'), "data-testid": `segmented-option-${option.value}`, children: [option.icon && (jsx("span", { className: buildClassName('shrink-0 inline-flex items-center justify-center', SIZE_ICON_CLASS[size]), children: option.icon })), jsx("span", { className: "min-w-0 truncate", children: option.label })] }, option.value));
|
|
57
61
|
}) }));
|
|
58
62
|
});
|
|
59
63
|
SegmentedControl.displayName = 'SegmentedControl';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SegmentedControl.js","sources":["../../../../../src/components/SegmentedControl/SegmentedControl.tsx"],"sourcesContent":["import React, { forwardRef } from 'react'\nimport { buildClassName } from '../../utils/build-classname'\nimport type { SegmentedControlProps } from './SegmentedControl.types'\n\nconst SIZE_CONTAINER_CLASS = {\n sm: 'p-0.5 gap-0.5 rounded-lg text-xs',\n md: 'p-1 gap-1 rounded-xl text-sm',\n lg: 'p-1.5 gap-1.5 rounded-xl text-base',\n}\n\nconst SIZE_OPTION_CLASS = {\n sm: 'px-2 py-1 text-xs font-medium rounded-md',\n md: 'px-3 py-1.5 text-sm font-semibold rounded-lg',\n lg: 'px-4 py-2 text-base font-semibold rounded-lg',\n}\n\nconst SIZE_ICON_CLASS = {\n sm: 'size-3.5',\n md: 'size-4',\n lg: 'size-5',\n}\n\nexport const SegmentedControl = forwardRef<HTMLDivElement, SegmentedControlProps>((props, ref) => {\n const {\n options,\n value,\n onChange,\n disabled = false,\n size = 'md',\n fullWidth = false,\n className,\n ...restProps\n } = props\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLButtonElement>, currentIndex: number) => {\n const enabledOptions = options.filter((opt) => !opt.disabled && !disabled)\n if (enabledOptions.length === 0) return\n\n if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {\n e.preventDefault()\n const currentPos = enabledOptions.findIndex(\n (opt) => opt.value === options[currentIndex].value,\n )\n const nextPos = (currentPos + 1) % enabledOptions.length\n onChange(enabledOptions[nextPos].value)\n } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {\n e.preventDefault()\n const currentPos = enabledOptions.findIndex(\n (opt) => opt.value === options[currentIndex].value,\n )\n const prevPos = (currentPos - 1 + enabledOptions.length) % enabledOptions.length\n onChange(enabledOptions[prevPos].value)\n } else if (e.key === 'Home') {\n e.preventDefault()\n onChange(enabledOptions[0].value)\n } else if (e.key === 'End') {\n e.preventDefault()\n onChange(enabledOptions[enabledOptions.length - 1].value)\n }\n }\n\n return (\n <div\n ref={ref}\n role=\"tablist\"\n aria-orientation=\"horizontal\"\n className={buildClassName(\n 'inline-flex items-center border border-[var(--ui-border)] bg-gray-100/80 dark:bg-gray-800/80',\n SIZE_CONTAINER_CLASS[size],\n fullWidth ? 'w-full flex' : '',\n disabled ? 'opacity-60 cursor-not-allowed' : '',\n className,\n )}\n data-testid=\"segmented-control\"\n {...restProps}\n >\n {options.map((option, index) => {\n const isSelected = value === option.value\n const isOptionDisabled = disabled || option.disabled\n\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"tab\"\n aria-selected={isSelected}\n aria-disabled={isOptionDisabled}\n tabIndex={isSelected && !isOptionDisabled ? 0 : -1}\n disabled={isOptionDisabled}\n title={option.title}\n onClick={() => {\n if (!isOptionDisabled) {\n onChange(option.value)\n }\n }}\n onKeyDown={(e) => handleKeyDown(e, index)}\n className={buildClassName(\n 'inline-flex items-center justify-center gap-1.5 transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary-ring)]',\n SIZE_OPTION_CLASS[size],\n fullWidth ? 'flex-1' : '',\n isOptionDisabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer',\n isSelected\n ? 'bg-white text-[var(--ui-primary)] dark:bg-gray-700 dark:text-blue-400 shadow-xs font-semibold'\n : 'text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100',\n )}\n data-testid={`segmented-option-${option.value}`}\n >\n {option.icon && (\n <span\n className={buildClassName(\n 'shrink-0 inline-flex items-center justify-center',\n SIZE_ICON_CLASS[size],\n )}\n >\n {option.icon}\n </span>\n )}\n <span>{option.label}</span>\n </button>\n )\n })}\n </div>\n )\n})\n\nSegmentedControl.displayName = 'SegmentedControl'\n"],"names":["_jsx","_jsxs"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"SegmentedControl.js","sources":["../../../../../src/components/SegmentedControl/SegmentedControl.tsx"],"sourcesContent":["import React, { forwardRef } from 'react'\nimport { buildClassName } from '../../utils/build-classname'\nimport type { SegmentedControlProps } from './SegmentedControl.types'\n\nconst SIZE_CONTAINER_CLASS = {\n sm: 'p-0.5 gap-0.5 rounded-lg text-xs',\n md: 'p-1 gap-1 rounded-xl text-sm',\n lg: 'p-1.5 gap-1.5 rounded-xl text-base',\n}\n\nconst SIZE_OPTION_CLASS = {\n sm: 'px-2 py-1 text-xs font-medium rounded-md',\n md: 'px-3 py-1.5 text-sm font-semibold rounded-lg',\n lg: 'px-4 py-2 text-base font-semibold rounded-lg',\n}\n\nconst SIZE_ICON_CLASS = {\n sm: 'size-3.5',\n md: 'size-4',\n lg: 'size-5',\n}\n\nexport const SegmentedControl = forwardRef<HTMLDivElement, SegmentedControlProps>((props, ref) => {\n const {\n options,\n value,\n onChange,\n disabled = false,\n size = 'md',\n fullWidth = false,\n className,\n ...restProps\n } = props\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLButtonElement>, currentIndex: number) => {\n const enabledOptions = options.filter((opt) => !opt.disabled && !disabled)\n if (enabledOptions.length === 0) return\n\n if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {\n e.preventDefault()\n const currentPos = enabledOptions.findIndex(\n (opt) => opt.value === options[currentIndex].value,\n )\n const nextPos = (currentPos + 1) % enabledOptions.length\n onChange(enabledOptions[nextPos].value)\n } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {\n e.preventDefault()\n const currentPos = enabledOptions.findIndex(\n (opt) => opt.value === options[currentIndex].value,\n )\n const prevPos = (currentPos - 1 + enabledOptions.length) % enabledOptions.length\n onChange(enabledOptions[prevPos].value)\n } else if (e.key === 'Home') {\n e.preventDefault()\n onChange(enabledOptions[0].value)\n } else if (e.key === 'End') {\n e.preventDefault()\n onChange(enabledOptions[enabledOptions.length - 1].value)\n }\n }\n\n return (\n <div\n ref={ref}\n role=\"tablist\"\n aria-orientation=\"horizontal\"\n className={buildClassName(\n 'inline-flex items-center border border-[var(--ui-border)] bg-gray-100/80 dark:bg-gray-800/80',\n SIZE_CONTAINER_CLASS[size],\n fullWidth ? 'w-full flex' : '',\n disabled ? 'opacity-60 cursor-not-allowed' : '',\n className,\n )}\n data-testid=\"segmented-control\"\n {...restProps}\n >\n {options.map((option, index) => {\n const isSelected = value === option.value\n const isOptionDisabled = disabled || option.disabled\n\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"tab\"\n aria-selected={isSelected}\n aria-disabled={isOptionDisabled}\n tabIndex={isSelected && !isOptionDisabled ? 0 : -1}\n disabled={isOptionDisabled}\n title={option.title}\n onClick={() => {\n if (!isOptionDisabled) {\n onChange(option.value)\n }\n }}\n onKeyDown={(e) => handleKeyDown(e, index)}\n className={buildClassName(\n 'inline-flex items-center justify-center gap-1.5 transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary-ring)]',\n SIZE_OPTION_CLASS[size],\n // Full width splits the row equally, so the width comes from the\n // row, not padding; tight side padding keeps labels on one line\n // on narrow screens.\n fullWidth ? 'min-w-0 flex-1 px-1.5' : '',\n isOptionDisabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer',\n isSelected\n ? 'bg-white text-[var(--ui-primary)] dark:bg-gray-700 dark:text-blue-400 shadow-xs font-semibold'\n : 'text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100',\n )}\n data-testid={`segmented-option-${option.value}`}\n >\n {option.icon && (\n <span\n className={buildClassName(\n 'shrink-0 inline-flex items-center justify-center',\n SIZE_ICON_CLASS[size],\n )}\n >\n {option.icon}\n </span>\n )}\n {/* A label never wraps; if there's truly no room it's cut off. */}\n <span className=\"min-w-0 truncate\">{option.label}</span>\n </button>\n )\n })}\n </div>\n )\n})\n\nSegmentedControl.displayName = 'SegmentedControl'\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
|
|
@@ -84,7 +84,9 @@ const Toast = ({ id, title, message, type, variant = 'accent', action, icon, sho
|
|
|
84
84
|
const enterFrom = isTop ? 'opacity-0 -translate-y-3 scale-95' : 'opacity-0 translate-y-3 scale-95';
|
|
85
85
|
const leaveTo = isTop ? 'opacity-0 -translate-y-2 scale-95' : 'opacity-0 translate-y-2 scale-95';
|
|
86
86
|
const renderedIcon = icon !== null && icon !== void 0 ? icon : (variant === 'filled' ? filledIconMap[type] : iconMap[type]);
|
|
87
|
-
return (jsx(Transition, { appear: true, show: true, enter: "transform transition duration-300 ease-out", enterFrom: enterFrom, enterTo: "opacity-100 translate-y-0 scale-100", leave: "transition duration-200 ease-in", leaveFrom: "opacity-100 translate-y-0 scale-100", leaveTo: leaveTo, children: jsxs("div", { role: "status", id: id.toString(), className: buildClassName(
|
|
87
|
+
return (jsx(Transition, { appear: true, show: true, enter: "transform transition duration-300 ease-out", enterFrom: enterFrom, enterTo: "opacity-100 translate-y-0 scale-100", leave: "transition duration-200 ease-in", leaveFrom: "opacity-100 translate-y-0 scale-100", leaveTo: leaveTo, children: jsxs("div", { role: "status", id: id.toString(), className: buildClassName(
|
|
88
|
+
// Never wider than the viewport minus a 16px gutter each side.
|
|
89
|
+
'relative overflow-hidden flex items-start gap-3 rounded-xl px-4 py-3.5 min-w-[min(280px,calc(100vw-2rem))] max-w-[min(28rem,calc(100vw-2rem))] transition-all', variantStyleMap[variant][type], className), children: [jsx("div", { className: "shrink-0 mt-0.5", children: variant === 'filled' ? (renderedIcon) : (jsx(TextContent, { className: buildClassName(textColorMap[type]), children: renderedIcon })) }), jsxs("div", { className: "flex-1 flex flex-col gap-0.5", children: [title && (jsx("div", { className: buildClassName('font-semibold text-sm leading-snug', variant === 'filled' ? 'text-white' : 'text-gray-900 dark:text-gray-100'), children: title })), jsx("div", { className: buildClassName('text-sm font-medium leading-relaxed', variant === 'filled' ? 'text-white/95' : 'text-gray-700 dark:text-gray-300'), children: message }), action && (jsx("div", { className: "mt-1.5", children: jsx("button", { type: "button", onClick: action.onClick, className: buildClassName('text-xs font-semibold underline underline-offset-2 transition-opacity focus:outline-none', variant === 'filled'
|
|
88
90
|
? 'text-white hover:opacity-85'
|
|
89
91
|
: 'text-[var(--ui-primary)] hover:opacity-80'), children: action.label }) }))] }), jsx(Button, { onClick: onClose, "aria-label": "Close toast", className: buildClassName('shrink-0 mt-0.5 opacity-60 hover:opacity-100 focus-visible:opacity-100 transition', variant === 'filled' && 'text-white hover:text-white focus-visible:outline-current'), iconOnly: true, size: "xs", variant: "plain", theme: variant === 'filled' ? 'primary' : 'secondary', children: jsx(SvgX, { className: "size-4" }) }), showProgressBar && duration > 0 && (jsx("div", { className: "absolute bottom-0 left-0 right-0 h-1 bg-black/10 dark:bg-white/10 overflow-hidden", children: jsx("div", { className: buildClassName('h-full transition-all duration-75 ease-linear', variant === 'filled' ? 'bg-white/70' : progressBarColorMap[type]), style: { width: `${Math.max(0, progress)}%` } }) }))] }) }));
|
|
90
92
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toast.js","sources":["../../../../../src/components/Toast/Toast.tsx"],"sourcesContent":["import React, { useEffect, useState } from 'react'\nimport { Transition } from '@headlessui/react'\nimport XIcon from '../Icons/X.svg'\nimport CheckCircle from '../Icons/CircleCheck.svg'\nimport AlertCircle from '../Icons/CircleAlert.svg'\nimport Info from '../Icons/Info.svg'\nimport AlertTriangle from '../Icons/TriangleAlert.svg'\n\nimport { Button } from '../Button'\nimport { TextContent } from '../TextContent'\nimport { buildClassName } from '../../utils/build-classname'\n\nimport type { ToastProps, ToastType, ToastVariant } from './Toast.types'\n\n/**\n * Icons for each toast type\n */\nconst iconMap: Record<ToastType, React.ReactNode> = {\n success: <CheckCircle className=\"size-5 text-[var(--ui-success)]\" />,\n error: <AlertCircle className=\"size-5 text-[var(--ui-danger)]\" />,\n info: <Info className=\"size-5 text-[var(--ui-info)]\" />,\n warning: <AlertTriangle className=\"size-5 text-[var(--ui-warning)]\" />,\n}\n\nconst filledIconMap: Record<ToastType, React.ReactNode> = {\n success: <CheckCircle className=\"size-5 text-white\" />,\n error: <AlertCircle className=\"size-5 text-white\" />,\n info: <Info className=\"size-5 text-white\" />,\n warning: <AlertTriangle className=\"size-5 text-white\" />,\n}\n\nconst textColorMap: Record<ToastType, string> = {\n success: 'text-[var(--ui-success-text)]',\n error: 'text-[var(--ui-danger-text)]',\n info: 'text-[var(--ui-info-text)]',\n warning: 'text-[var(--ui-warning-text)]',\n}\n\nconst progressBarColorMap: Record<ToastType, string> = {\n success: 'bg-[var(--ui-success)]',\n error: 'bg-[var(--ui-danger)]',\n info: 'bg-[var(--ui-info)]',\n warning: 'bg-[var(--ui-warning)]',\n}\n\nconst variantStyleMap: Record<ToastVariant, Record<ToastType, string>> = {\n accent: {\n success:\n 'bg-white dark:bg-gray-900 border-l-4 border-[var(--ui-success)] text-gray-900 dark:text-gray-100 shadow-lg border-y border-r border-[var(--ui-border)]',\n error:\n 'bg-white dark:bg-gray-900 border-l-4 border-[var(--ui-danger)] text-gray-900 dark:text-gray-100 shadow-lg border-y border-r border-[var(--ui-border)]',\n info: 'bg-white dark:bg-gray-900 border-l-4 border-[var(--ui-info)] text-gray-900 dark:text-gray-100 shadow-lg border-y border-r border-[var(--ui-border)]',\n warning:\n 'bg-white dark:bg-gray-900 border-l-4 border-[var(--ui-warning)] text-gray-900 dark:text-gray-100 shadow-lg border-y border-r border-[var(--ui-border)]',\n },\n filled: {\n success: 'bg-[var(--ui-success)] text-white shadow-lg',\n error: 'bg-[var(--ui-danger)] text-white shadow-lg',\n info: 'bg-[var(--ui-info)] text-white shadow-lg',\n warning: 'bg-[var(--ui-warning)] text-white shadow-lg',\n },\n outlined: {\n success:\n 'bg-white dark:bg-gray-900 border-2 border-[var(--ui-success)] text-gray-900 dark:text-gray-100 shadow-md',\n error:\n 'bg-white dark:bg-gray-900 border-2 border-[var(--ui-danger)] text-gray-900 dark:text-gray-100 shadow-md',\n info: 'bg-white dark:bg-gray-900 border-2 border-[var(--ui-info)] text-gray-900 dark:text-gray-100 shadow-md',\n warning:\n 'bg-white dark:bg-gray-900 border-2 border-[var(--ui-warning)] text-gray-900 dark:text-gray-100 shadow-md',\n },\n glass: {\n success:\n 'backdrop-blur-md bg-white/85 dark:bg-gray-900/85 border border-emerald-500/30 text-gray-900 dark:text-gray-100 shadow-xl',\n error:\n 'backdrop-blur-md bg-white/85 dark:bg-gray-900/85 border border-rose-500/30 text-gray-900 dark:text-gray-100 shadow-xl',\n info: 'backdrop-blur-md bg-white/85 dark:bg-gray-900/85 border border-blue-500/30 text-gray-900 dark:text-gray-100 shadow-xl',\n warning:\n 'backdrop-blur-md bg-white/85 dark:bg-gray-900/85 border border-amber-500/30 text-gray-900 dark:text-gray-100 shadow-xl',\n },\n}\n\nexport const Toast: React.FC<ToastProps & { isTop?: boolean }> = ({\n id,\n title,\n message,\n type,\n variant = 'accent',\n action,\n icon,\n showProgressBar = true,\n duration = 4000,\n isPaused = false,\n onClose,\n className,\n isTop = true,\n}) => {\n const [progress, setProgress] = useState(100)\n\n useEffect(() => {\n if (!showProgressBar || !duration || isPaused) return\n\n const intervalTime = 50\n const step = (intervalTime / duration) * 100\n\n const timer = setInterval(() => {\n setProgress((prev) => {\n if (prev <= 0) {\n clearInterval(timer)\n return 0\n }\n return prev - step\n })\n }, intervalTime)\n\n return () => clearInterval(timer)\n }, [showProgressBar, duration, isPaused])\n\n const enterFrom = isTop ? 'opacity-0 -translate-y-3 scale-95' : 'opacity-0 translate-y-3 scale-95'\n const leaveTo = isTop ? 'opacity-0 -translate-y-2 scale-95' : 'opacity-0 translate-y-2 scale-95'\n\n const renderedIcon = icon ?? (variant === 'filled' ? filledIconMap[type] : iconMap[type])\n\n return (\n <Transition\n appear\n show\n enter=\"transform transition duration-300 ease-out\"\n enterFrom={enterFrom}\n enterTo=\"opacity-100 translate-y-0 scale-100\"\n leave=\"transition duration-200 ease-in\"\n leaveFrom=\"opacity-100 translate-y-0 scale-100\"\n leaveTo={leaveTo}\n >\n <div\n role=\"status\"\n id={id.toString()}\n className={buildClassName(\n 'relative overflow-hidden flex items-start gap-3 rounded-xl px-4 py-3.5 min-w-[280px] max-w-md transition-all',\n variantStyleMap[variant][type],\n className,\n )}\n >\n {/* Icon */}\n <div className=\"shrink-0 mt-0.5\">\n {variant === 'filled' ? (\n renderedIcon\n ) : (\n <TextContent className={buildClassName(textColorMap[type])}>{renderedIcon}</TextContent>\n )}\n </div>\n\n {/* Content Body */}\n <div className=\"flex-1 flex flex-col gap-0.5\">\n {title && (\n <div\n className={buildClassName(\n 'font-semibold text-sm leading-snug',\n variant === 'filled' ? 'text-white' : 'text-gray-900 dark:text-gray-100',\n )}\n >\n {title}\n </div>\n )}\n <div\n className={buildClassName(\n 'text-sm font-medium leading-relaxed',\n variant === 'filled' ? 'text-white/95' : 'text-gray-700 dark:text-gray-300',\n )}\n >\n {message}\n </div>\n\n {/* Action Button */}\n {action && (\n <div className=\"mt-1.5\">\n <button\n type=\"button\"\n onClick={action.onClick}\n className={buildClassName(\n 'text-xs font-semibold underline underline-offset-2 transition-opacity focus:outline-none',\n variant === 'filled'\n ? 'text-white hover:opacity-85'\n : 'text-[var(--ui-primary)] hover:opacity-80',\n )}\n >\n {action.label}\n </button>\n </div>\n )}\n </div>\n\n {/* Close button */}\n <Button\n onClick={onClose}\n aria-label=\"Close toast\"\n className={buildClassName(\n 'shrink-0 mt-0.5 opacity-60 hover:opacity-100 focus-visible:opacity-100 transition',\n variant === 'filled' && 'text-white hover:text-white focus-visible:outline-current',\n )}\n iconOnly\n size=\"xs\"\n variant=\"plain\"\n theme={variant === 'filled' ? 'primary' : 'secondary'}\n >\n <XIcon className=\"size-4\" />\n </Button>\n\n {/* Progress Bar Countdown */}\n {showProgressBar && duration > 0 && (\n <div className=\"absolute bottom-0 left-0 right-0 h-1 bg-black/10 dark:bg-white/10 overflow-hidden\">\n <div\n className={buildClassName(\n 'h-full transition-all duration-75 ease-linear',\n variant === 'filled' ? 'bg-white/70' : progressBarColorMap[type],\n )}\n style={{ width: `${Math.max(0, progress)}%` }}\n />\n </div>\n )}\n </div>\n </Transition>\n )\n}\n\nToast.displayName = 'Toast'\n"],"names":["_jsx","CheckCircle","AlertCircle","Info","AlertTriangle","_jsxs","XIcon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Toast.js","sources":["../../../../../src/components/Toast/Toast.tsx"],"sourcesContent":["import React, { useEffect, useState } from 'react'\nimport { Transition } from '@headlessui/react'\nimport XIcon from '../Icons/X.svg'\nimport CheckCircle from '../Icons/CircleCheck.svg'\nimport AlertCircle from '../Icons/CircleAlert.svg'\nimport Info from '../Icons/Info.svg'\nimport AlertTriangle from '../Icons/TriangleAlert.svg'\n\nimport { Button } from '../Button'\nimport { TextContent } from '../TextContent'\nimport { buildClassName } from '../../utils/build-classname'\n\nimport type { ToastProps, ToastType, ToastVariant } from './Toast.types'\n\n/**\n * Icons for each toast type\n */\nconst iconMap: Record<ToastType, React.ReactNode> = {\n success: <CheckCircle className=\"size-5 text-[var(--ui-success)]\" />,\n error: <AlertCircle className=\"size-5 text-[var(--ui-danger)]\" />,\n info: <Info className=\"size-5 text-[var(--ui-info)]\" />,\n warning: <AlertTriangle className=\"size-5 text-[var(--ui-warning)]\" />,\n}\n\nconst filledIconMap: Record<ToastType, React.ReactNode> = {\n success: <CheckCircle className=\"size-5 text-white\" />,\n error: <AlertCircle className=\"size-5 text-white\" />,\n info: <Info className=\"size-5 text-white\" />,\n warning: <AlertTriangle className=\"size-5 text-white\" />,\n}\n\nconst textColorMap: Record<ToastType, string> = {\n success: 'text-[var(--ui-success-text)]',\n error: 'text-[var(--ui-danger-text)]',\n info: 'text-[var(--ui-info-text)]',\n warning: 'text-[var(--ui-warning-text)]',\n}\n\nconst progressBarColorMap: Record<ToastType, string> = {\n success: 'bg-[var(--ui-success)]',\n error: 'bg-[var(--ui-danger)]',\n info: 'bg-[var(--ui-info)]',\n warning: 'bg-[var(--ui-warning)]',\n}\n\nconst variantStyleMap: Record<ToastVariant, Record<ToastType, string>> = {\n accent: {\n success:\n 'bg-white dark:bg-gray-900 border-l-4 border-[var(--ui-success)] text-gray-900 dark:text-gray-100 shadow-lg border-y border-r border-[var(--ui-border)]',\n error:\n 'bg-white dark:bg-gray-900 border-l-4 border-[var(--ui-danger)] text-gray-900 dark:text-gray-100 shadow-lg border-y border-r border-[var(--ui-border)]',\n info: 'bg-white dark:bg-gray-900 border-l-4 border-[var(--ui-info)] text-gray-900 dark:text-gray-100 shadow-lg border-y border-r border-[var(--ui-border)]',\n warning:\n 'bg-white dark:bg-gray-900 border-l-4 border-[var(--ui-warning)] text-gray-900 dark:text-gray-100 shadow-lg border-y border-r border-[var(--ui-border)]',\n },\n filled: {\n success: 'bg-[var(--ui-success)] text-white shadow-lg',\n error: 'bg-[var(--ui-danger)] text-white shadow-lg',\n info: 'bg-[var(--ui-info)] text-white shadow-lg',\n warning: 'bg-[var(--ui-warning)] text-white shadow-lg',\n },\n outlined: {\n success:\n 'bg-white dark:bg-gray-900 border-2 border-[var(--ui-success)] text-gray-900 dark:text-gray-100 shadow-md',\n error:\n 'bg-white dark:bg-gray-900 border-2 border-[var(--ui-danger)] text-gray-900 dark:text-gray-100 shadow-md',\n info: 'bg-white dark:bg-gray-900 border-2 border-[var(--ui-info)] text-gray-900 dark:text-gray-100 shadow-md',\n warning:\n 'bg-white dark:bg-gray-900 border-2 border-[var(--ui-warning)] text-gray-900 dark:text-gray-100 shadow-md',\n },\n glass: {\n success:\n 'backdrop-blur-md bg-white/85 dark:bg-gray-900/85 border border-emerald-500/30 text-gray-900 dark:text-gray-100 shadow-xl',\n error:\n 'backdrop-blur-md bg-white/85 dark:bg-gray-900/85 border border-rose-500/30 text-gray-900 dark:text-gray-100 shadow-xl',\n info: 'backdrop-blur-md bg-white/85 dark:bg-gray-900/85 border border-blue-500/30 text-gray-900 dark:text-gray-100 shadow-xl',\n warning:\n 'backdrop-blur-md bg-white/85 dark:bg-gray-900/85 border border-amber-500/30 text-gray-900 dark:text-gray-100 shadow-xl',\n },\n}\n\nexport const Toast: React.FC<ToastProps & { isTop?: boolean }> = ({\n id,\n title,\n message,\n type,\n variant = 'accent',\n action,\n icon,\n showProgressBar = true,\n duration = 4000,\n isPaused = false,\n onClose,\n className,\n isTop = true,\n}) => {\n const [progress, setProgress] = useState(100)\n\n useEffect(() => {\n if (!showProgressBar || !duration || isPaused) return\n\n const intervalTime = 50\n const step = (intervalTime / duration) * 100\n\n const timer = setInterval(() => {\n setProgress((prev) => {\n if (prev <= 0) {\n clearInterval(timer)\n return 0\n }\n return prev - step\n })\n }, intervalTime)\n\n return () => clearInterval(timer)\n }, [showProgressBar, duration, isPaused])\n\n const enterFrom = isTop ? 'opacity-0 -translate-y-3 scale-95' : 'opacity-0 translate-y-3 scale-95'\n const leaveTo = isTop ? 'opacity-0 -translate-y-2 scale-95' : 'opacity-0 translate-y-2 scale-95'\n\n const renderedIcon = icon ?? (variant === 'filled' ? filledIconMap[type] : iconMap[type])\n\n return (\n <Transition\n appear\n show\n enter=\"transform transition duration-300 ease-out\"\n enterFrom={enterFrom}\n enterTo=\"opacity-100 translate-y-0 scale-100\"\n leave=\"transition duration-200 ease-in\"\n leaveFrom=\"opacity-100 translate-y-0 scale-100\"\n leaveTo={leaveTo}\n >\n <div\n role=\"status\"\n id={id.toString()}\n className={buildClassName(\n // Never wider than the viewport minus a 16px gutter each side.\n 'relative overflow-hidden flex items-start gap-3 rounded-xl px-4 py-3.5 min-w-[min(280px,calc(100vw-2rem))] max-w-[min(28rem,calc(100vw-2rem))] transition-all',\n variantStyleMap[variant][type],\n className,\n )}\n >\n {/* Icon */}\n <div className=\"shrink-0 mt-0.5\">\n {variant === 'filled' ? (\n renderedIcon\n ) : (\n <TextContent className={buildClassName(textColorMap[type])}>{renderedIcon}</TextContent>\n )}\n </div>\n\n {/* Content Body */}\n <div className=\"flex-1 flex flex-col gap-0.5\">\n {title && (\n <div\n className={buildClassName(\n 'font-semibold text-sm leading-snug',\n variant === 'filled' ? 'text-white' : 'text-gray-900 dark:text-gray-100',\n )}\n >\n {title}\n </div>\n )}\n <div\n className={buildClassName(\n 'text-sm font-medium leading-relaxed',\n variant === 'filled' ? 'text-white/95' : 'text-gray-700 dark:text-gray-300',\n )}\n >\n {message}\n </div>\n\n {/* Action Button */}\n {action && (\n <div className=\"mt-1.5\">\n <button\n type=\"button\"\n onClick={action.onClick}\n className={buildClassName(\n 'text-xs font-semibold underline underline-offset-2 transition-opacity focus:outline-none',\n variant === 'filled'\n ? 'text-white hover:opacity-85'\n : 'text-[var(--ui-primary)] hover:opacity-80',\n )}\n >\n {action.label}\n </button>\n </div>\n )}\n </div>\n\n {/* Close button */}\n <Button\n onClick={onClose}\n aria-label=\"Close toast\"\n className={buildClassName(\n 'shrink-0 mt-0.5 opacity-60 hover:opacity-100 focus-visible:opacity-100 transition',\n variant === 'filled' && 'text-white hover:text-white focus-visible:outline-current',\n )}\n iconOnly\n size=\"xs\"\n variant=\"plain\"\n theme={variant === 'filled' ? 'primary' : 'secondary'}\n >\n <XIcon className=\"size-4\" />\n </Button>\n\n {/* Progress Bar Countdown */}\n {showProgressBar && duration > 0 && (\n <div className=\"absolute bottom-0 left-0 right-0 h-1 bg-black/10 dark:bg-white/10 overflow-hidden\">\n <div\n className={buildClassName(\n 'h-full transition-all duration-75 ease-linear',\n variant === 'filled' ? 'bg-white/70' : progressBarColorMap[type],\n )}\n style={{ width: `${Math.max(0, progress)}%` }}\n />\n </div>\n )}\n </div>\n </Transition>\n )\n}\n\nToast.displayName = 'Toast'\n"],"names":["_jsx","CheckCircle","AlertCircle","Info","AlertTriangle","_jsxs","XIcon"],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import { jsxs, jsx } from 'react/jsx-runtime';
|
|
|
2
2
|
import { createContext, useContext, useState, useRef, useCallback, useEffect, useMemo } from 'react';
|
|
3
3
|
import { Toast } from './Toast.js';
|
|
4
4
|
import { buildClassName } from '../../utils/build-classname.js';
|
|
5
|
+
import { useResponsiveValue } from '../../hooks/use-breakpoint.js';
|
|
5
6
|
|
|
6
7
|
const ToastContext = createContext(undefined);
|
|
7
8
|
let toastCounter = 0;
|
|
@@ -15,11 +16,15 @@ const placementClass = {
|
|
|
15
16
|
'top-right': 'top-20 right-6 items-end',
|
|
16
17
|
'top-left': 'top-20 left-6 items-start',
|
|
17
18
|
'top-center': 'top-20 left-1/2 -translate-x-1/2 items-center',
|
|
18
|
-
|
|
19
|
-
'bottom-
|
|
20
|
-
'bottom-
|
|
19
|
+
// Bottom placements clear the home indicator on notched phones (0 elsewhere).
|
|
20
|
+
'bottom-right': 'bottom-[calc(1.5rem+env(safe-area-inset-bottom,0px))] right-6 items-end',
|
|
21
|
+
'bottom-left': 'bottom-[calc(1.5rem+env(safe-area-inset-bottom,0px))] left-6 items-start',
|
|
22
|
+
'bottom-center': 'bottom-[calc(1.5rem+env(safe-area-inset-bottom,0px))] left-1/2 -translate-x-1/2 items-center',
|
|
21
23
|
};
|
|
22
|
-
const ToastProvider = ({ children, placement = 'top-right', maxToasts = 5, className, }) => {
|
|
24
|
+
const ToastProvider = ({ children, placement: placementProp = 'top-right', maxToasts = 5, offset, className, }) => {
|
|
25
|
+
const placement = useResponsiveValue(placementProp);
|
|
26
|
+
const isTop = placement.startsWith('top');
|
|
27
|
+
const edgeOffset = isTop ? offset === null || offset === void 0 ? void 0 : offset.top : offset === null || offset === void 0 ? void 0 : offset.bottom;
|
|
23
28
|
const [toasts, setToasts] = useState([]);
|
|
24
29
|
const [pausedIds, setPausedIds] = useState(new Set());
|
|
25
30
|
const metaRefs = useRef(new Map());
|
|
@@ -140,7 +145,7 @@ const ToastProvider = ({ children, placement = 'top-right', maxToasts = 5, class
|
|
|
140
145
|
dismiss: (id) => closeToast(id),
|
|
141
146
|
dismissAll: () => dismissAll(),
|
|
142
147
|
}), [showToast, closeToast, dismissAll]);
|
|
143
|
-
return (jsxs(ToastContext.Provider, { value: { showToast, closeToast, toast: toastHelpers }, children: [children, jsx("div", { className: buildClassName('fixed z-[9999] flex flex-col gap-3 pointer-events-none', placementClass[placement], className), children: toasts.map((toastItem) => (jsx("div", { className: "pointer-events-auto", onMouseEnter: () => handleMouseEnter(toastItem), onMouseLeave: () => handleMouseLeave(toastItem), children: jsx(Toast, { ...toastItem, isPaused: pausedIds.has(toastItem.id), isTop:
|
|
148
|
+
return (jsxs(ToastContext.Provider, { value: { showToast, closeToast, toast: toastHelpers }, children: [children, jsx("div", { className: buildClassName('fixed z-[9999] flex flex-col gap-3 pointer-events-none', placementClass[placement], className), style: edgeOffset ? (isTop ? { top: edgeOffset } : { bottom: edgeOffset }) : undefined, "data-testid": "toast-container", "data-placement": placement, children: toasts.map((toastItem) => (jsx("div", { className: "pointer-events-auto", onMouseEnter: () => handleMouseEnter(toastItem), onMouseLeave: () => handleMouseLeave(toastItem), children: jsx(Toast, { ...toastItem, isPaused: pausedIds.has(toastItem.id), isTop: isTop, onClose: () => closeToast(toastItem.id) }) }, toastItem.id))) })] }));
|
|
144
149
|
};
|
|
145
150
|
ToastProvider.displayName = 'ToastProvider';
|
|
146
151
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToastProvider.js","sources":["../../../../../src/components/Toast/ToastProvider.tsx"],"sourcesContent":["import React, {\n createContext,\n useContext,\n useEffect,\n useState,\n type ReactNode,\n useRef,\n useCallback,\n useMemo,\n} from 'react'\nimport { Toast } from './Toast'\nimport type {\n IToast,\n ToastContextType,\n ToastOptions,\n ToastPlacement,\n ToastProviderProps,\n} from './Toast.types'\nimport { buildClassName } from '../../utils/build-classname'\n\nconst ToastContext = createContext<ToastContextType | undefined>(undefined)\nlet toastCounter = 0\n\nexport const useToast = (): ToastContextType => {\n const context = useContext(ToastContext)\n if (!context) throw new Error('useToast must be used within ToastProvider')\n return context\n}\n\nconst placementClass: Record<ToastPlacement, string> = {\n 'top-right': 'top-20 right-6 items-end',\n 'top-left': 'top-20 left-6 items-start',\n 'top-center': 'top-20 left-1/2 -translate-x-1/2 items-center',\n\n 'bottom-right': 'bottom-6 right-6 items-end',\n 'bottom-left': 'bottom-6 left-6 items-start',\n 'bottom-center': 'bottom-6 left-1/2 -translate-x-1/2 items-center',\n}\n\ninterface ToastMeta {\n timerId: any\n startTime: number\n remainingTime: number\n}\n\nexport const ToastProvider: React.FC<ToastProviderProps> = ({\n children,\n placement = 'top-right',\n maxToasts = 5,\n className,\n}) => {\n const [toasts, setToasts] = useState<IToast[]>([])\n const [pausedIds, setPausedIds] = useState<Set<number>>(new Set())\n const metaRefs = useRef<Map<number, ToastMeta>>(new Map())\n\n const clearTimer = (id: number) => {\n const meta = metaRefs.current.get(id)\n if (meta?.timerId) {\n clearTimeout(meta.timerId)\n meta.timerId = null\n }\n }\n\n const closeToast = useCallback((id: number) => {\n clearTimer(id)\n metaRefs.current.delete(id)\n setPausedIds((prev) => {\n const next = new Set(prev)\n next.delete(id)\n return next\n })\n setToasts((prev) => prev.filter((t) => t.id !== id))\n }, [])\n\n const dismissAll = useCallback(() => {\n metaRefs.current.forEach((meta) => {\n if (meta.timerId) clearTimeout(meta.timerId)\n })\n metaRefs.current.clear()\n setPausedIds(new Set())\n setToasts([])\n }, [])\n\n const startAutoClose = useCallback(\n (toastId: number, delay: number) => {\n clearTimer(toastId)\n\n const timerId = setTimeout(() => {\n closeToast(toastId)\n }, delay)\n\n const meta = metaRefs.current.get(toastId)\n if (meta) {\n meta.timerId = timerId\n meta.startTime = Date.now()\n meta.remainingTime = delay\n } else {\n metaRefs.current.set(toastId, {\n timerId,\n startTime: Date.now(),\n remainingTime: delay,\n })\n }\n },\n [closeToast],\n )\n\n useEffect(() => {\n const refs = metaRefs.current\n return () =>\n refs.forEach((meta) => {\n if (meta.timerId) clearTimeout(meta.timerId)\n })\n }, [])\n\n const showToast = useCallback(\n (message: ReactNode, options?: ToastOptions): number => {\n const id = ++toastCounter\n\n const newToast: IToast = {\n id,\n title: options?.title,\n message,\n type: options?.type ?? 'info',\n variant: options?.variant ?? 'accent',\n duration: options?.duration ?? 4000,\n autoClose: options?.autoClose ?? true,\n pauseOnHover: options?.pauseOnHover ?? true,\n showProgressBar: options?.showProgressBar ?? options?.autoClose !== false,\n action: options?.action,\n icon: options?.icon,\n }\n\n setToasts((prev) => {\n const updated = [...prev, newToast]\n if (updated.length > maxToasts) updated.shift()\n return updated\n })\n\n if (newToast.autoClose) {\n startAutoClose(id, newToast.duration)\n }\n\n return id\n },\n [maxToasts, startAutoClose],\n )\n\n // Hover pauses timer and tracks exact remaining milliseconds\n const handleMouseEnter = (toast: IToast) => {\n if (!toast.pauseOnHover || !toast.autoClose) return\n\n const meta = metaRefs.current.get(toast.id)\n if (meta) {\n const elapsed = Date.now() - meta.startTime\n meta.remainingTime = Math.max(0, meta.remainingTime - elapsed)\n clearTimer(toast.id)\n setPausedIds((prev) => new Set(prev).add(toast.id))\n }\n }\n\n // Mouse leave resumes timer with exact remaining milliseconds\n const handleMouseLeave = (toast: IToast) => {\n if (!toast.pauseOnHover || !toast.autoClose) return\n\n setPausedIds((prev) => {\n const next = new Set(prev)\n next.delete(toast.id)\n return next\n })\n\n const meta = metaRefs.current.get(toast.id)\n if (meta && meta.remainingTime > 0) {\n startAutoClose(toast.id, meta.remainingTime)\n } else if (meta && meta.remainingTime <= 0) {\n closeToast(toast.id)\n }\n }\n\n const toastHelpers = useMemo(\n () => ({\n show: (message: ReactNode, options?: ToastOptions) => showToast(message, options),\n success: (message: ReactNode, options?: ToastOptions) =>\n showToast(message, { ...options, type: 'success' }),\n error: (message: ReactNode, options?: ToastOptions) =>\n showToast(message, { ...options, type: 'error' }),\n info: (message: ReactNode, options?: ToastOptions) =>\n showToast(message, { ...options, type: 'info' }),\n warning: (message: ReactNode, options?: ToastOptions) =>\n showToast(message, { ...options, type: 'warning' }),\n dismiss: (id: number) => closeToast(id),\n dismissAll: () => dismissAll(),\n }),\n [showToast, closeToast, dismissAll],\n )\n\n return (\n <ToastContext.Provider value={{ showToast, closeToast, toast: toastHelpers }}>\n {children}\n\n {/* Toast Container */}\n <div\n className={buildClassName(\n 'fixed z-[9999] flex flex-col gap-3 pointer-events-none',\n placementClass[placement],\n className,\n )}\n >\n {toasts.map((toastItem) => (\n <div\n key={toastItem.id}\n className=\"pointer-events-auto\"\n onMouseEnter={() => handleMouseEnter(toastItem)}\n onMouseLeave={() => handleMouseLeave(toastItem)}\n >\n <Toast\n {...toastItem}\n isPaused={pausedIds.has(toastItem.id)}\n isTop={placement.startsWith('top')}\n onClose={() => closeToast(toastItem.id)}\n />\n </div>\n ))}\n </div>\n </ToastContext.Provider>\n )\n}\n\nToastProvider.displayName = 'ToastProvider'\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ToastProvider.js","sources":["../../../../../src/components/Toast/ToastProvider.tsx"],"sourcesContent":["import React, {\n createContext,\n useContext,\n useEffect,\n useState,\n type ReactNode,\n useRef,\n useCallback,\n useMemo,\n} from 'react'\nimport { Toast } from './Toast'\nimport type {\n IToast,\n ToastContextType,\n ToastOptions,\n ToastPlacement,\n ToastProviderProps,\n} from './Toast.types'\nimport { buildClassName } from '../../utils/build-classname'\nimport { useResponsiveValue } from '../../hooks/use-breakpoint'\n\nconst ToastContext = createContext<ToastContextType | undefined>(undefined)\nlet toastCounter = 0\n\nexport const useToast = (): ToastContextType => {\n const context = useContext(ToastContext)\n if (!context) throw new Error('useToast must be used within ToastProvider')\n return context\n}\n\nconst placementClass: Record<ToastPlacement, string> = {\n 'top-right': 'top-20 right-6 items-end',\n 'top-left': 'top-20 left-6 items-start',\n 'top-center': 'top-20 left-1/2 -translate-x-1/2 items-center',\n\n // Bottom placements clear the home indicator on notched phones (0 elsewhere).\n 'bottom-right': 'bottom-[calc(1.5rem+env(safe-area-inset-bottom,0px))] right-6 items-end',\n 'bottom-left': 'bottom-[calc(1.5rem+env(safe-area-inset-bottom,0px))] left-6 items-start',\n 'bottom-center':\n 'bottom-[calc(1.5rem+env(safe-area-inset-bottom,0px))] left-1/2 -translate-x-1/2 items-center',\n}\n\ninterface ToastMeta {\n timerId: any\n startTime: number\n remainingTime: number\n}\n\nexport const ToastProvider: React.FC<ToastProviderProps> = ({\n children,\n placement: placementProp = 'top-right',\n maxToasts = 5,\n offset,\n className,\n}) => {\n const placement = useResponsiveValue(placementProp)\n const isTop = placement.startsWith('top')\n const edgeOffset = isTop ? offset?.top : offset?.bottom\n const [toasts, setToasts] = useState<IToast[]>([])\n const [pausedIds, setPausedIds] = useState<Set<number>>(new Set())\n const metaRefs = useRef<Map<number, ToastMeta>>(new Map())\n\n const clearTimer = (id: number) => {\n const meta = metaRefs.current.get(id)\n if (meta?.timerId) {\n clearTimeout(meta.timerId)\n meta.timerId = null\n }\n }\n\n const closeToast = useCallback((id: number) => {\n clearTimer(id)\n metaRefs.current.delete(id)\n setPausedIds((prev) => {\n const next = new Set(prev)\n next.delete(id)\n return next\n })\n setToasts((prev) => prev.filter((t) => t.id !== id))\n }, [])\n\n const dismissAll = useCallback(() => {\n metaRefs.current.forEach((meta) => {\n if (meta.timerId) clearTimeout(meta.timerId)\n })\n metaRefs.current.clear()\n setPausedIds(new Set())\n setToasts([])\n }, [])\n\n const startAutoClose = useCallback(\n (toastId: number, delay: number) => {\n clearTimer(toastId)\n\n const timerId = setTimeout(() => {\n closeToast(toastId)\n }, delay)\n\n const meta = metaRefs.current.get(toastId)\n if (meta) {\n meta.timerId = timerId\n meta.startTime = Date.now()\n meta.remainingTime = delay\n } else {\n metaRefs.current.set(toastId, {\n timerId,\n startTime: Date.now(),\n remainingTime: delay,\n })\n }\n },\n [closeToast],\n )\n\n useEffect(() => {\n const refs = metaRefs.current\n return () =>\n refs.forEach((meta) => {\n if (meta.timerId) clearTimeout(meta.timerId)\n })\n }, [])\n\n const showToast = useCallback(\n (message: ReactNode, options?: ToastOptions): number => {\n const id = ++toastCounter\n\n const newToast: IToast = {\n id,\n title: options?.title,\n message,\n type: options?.type ?? 'info',\n variant: options?.variant ?? 'accent',\n duration: options?.duration ?? 4000,\n autoClose: options?.autoClose ?? true,\n pauseOnHover: options?.pauseOnHover ?? true,\n showProgressBar: options?.showProgressBar ?? options?.autoClose !== false,\n action: options?.action,\n icon: options?.icon,\n }\n\n setToasts((prev) => {\n const updated = [...prev, newToast]\n if (updated.length > maxToasts) updated.shift()\n return updated\n })\n\n if (newToast.autoClose) {\n startAutoClose(id, newToast.duration)\n }\n\n return id\n },\n [maxToasts, startAutoClose],\n )\n\n // Hover pauses timer and tracks exact remaining milliseconds\n const handleMouseEnter = (toast: IToast) => {\n if (!toast.pauseOnHover || !toast.autoClose) return\n\n const meta = metaRefs.current.get(toast.id)\n if (meta) {\n const elapsed = Date.now() - meta.startTime\n meta.remainingTime = Math.max(0, meta.remainingTime - elapsed)\n clearTimer(toast.id)\n setPausedIds((prev) => new Set(prev).add(toast.id))\n }\n }\n\n // Mouse leave resumes timer with exact remaining milliseconds\n const handleMouseLeave = (toast: IToast) => {\n if (!toast.pauseOnHover || !toast.autoClose) return\n\n setPausedIds((prev) => {\n const next = new Set(prev)\n next.delete(toast.id)\n return next\n })\n\n const meta = metaRefs.current.get(toast.id)\n if (meta && meta.remainingTime > 0) {\n startAutoClose(toast.id, meta.remainingTime)\n } else if (meta && meta.remainingTime <= 0) {\n closeToast(toast.id)\n }\n }\n\n const toastHelpers = useMemo(\n () => ({\n show: (message: ReactNode, options?: ToastOptions) => showToast(message, options),\n success: (message: ReactNode, options?: ToastOptions) =>\n showToast(message, { ...options, type: 'success' }),\n error: (message: ReactNode, options?: ToastOptions) =>\n showToast(message, { ...options, type: 'error' }),\n info: (message: ReactNode, options?: ToastOptions) =>\n showToast(message, { ...options, type: 'info' }),\n warning: (message: ReactNode, options?: ToastOptions) =>\n showToast(message, { ...options, type: 'warning' }),\n dismiss: (id: number) => closeToast(id),\n dismissAll: () => dismissAll(),\n }),\n [showToast, closeToast, dismissAll],\n )\n\n return (\n <ToastContext.Provider value={{ showToast, closeToast, toast: toastHelpers }}>\n {children}\n\n {/* Toast Container */}\n <div\n className={buildClassName(\n 'fixed z-[9999] flex flex-col gap-3 pointer-events-none',\n placementClass[placement],\n className,\n )}\n style={edgeOffset ? (isTop ? { top: edgeOffset } : { bottom: edgeOffset }) : undefined}\n data-testid=\"toast-container\"\n data-placement={placement}\n >\n {toasts.map((toastItem) => (\n <div\n key={toastItem.id}\n className=\"pointer-events-auto\"\n onMouseEnter={() => handleMouseEnter(toastItem)}\n onMouseLeave={() => handleMouseLeave(toastItem)}\n >\n <Toast\n {...toastItem}\n isPaused={pausedIds.has(toastItem.id)}\n isTop={isTop}\n onClose={() => closeToast(toastItem.id)}\n />\n </div>\n ))}\n </div>\n </ToastContext.Provider>\n )\n}\n\nToastProvider.displayName = 'ToastProvider'\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
|