@dreamtree-org/twreact-ui 1.3.0 → 1.3.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/README.md +179 -10
- package/ai-skills/dreamtree-ui.md +71 -12
- package/dist/ai-schema.json +452 -17
- package/dist/components/core/Accordion.d.ts.map +1 -1
- package/dist/components/core/Button.d.ts.map +1 -1
- package/dist/components/core/Checkbox.d.ts.map +1 -1
- package/dist/components/core/ColorPicker.d.ts.map +1 -1
- package/dist/components/core/DatePicker.d.ts.map +1 -1
- package/dist/components/core/DateRangePicker.d.ts.map +1 -1
- package/dist/components/core/Form.d.ts.map +1 -1
- package/dist/components/core/Input.d.ts.map +1 -1
- package/dist/components/core/LocationPicker.d.ts.map +1 -1
- package/dist/components/core/Popover.d.ts +4 -0
- package/dist/components/core/Popover.d.ts.map +1 -0
- package/dist/components/core/PriceRangePicker.d.ts.map +1 -1
- package/dist/components/core/ProgressBar.d.ts.map +1 -1
- package/dist/components/core/Radio.d.ts.map +1 -1
- package/dist/components/core/Rate.d.ts.map +1 -1
- package/dist/components/core/Select.d.ts.map +1 -1
- package/dist/components/core/Skeleton.d.ts.map +1 -1
- package/dist/components/core/Slider.d.ts +4 -0
- package/dist/components/core/Slider.d.ts.map +1 -0
- package/dist/components/core/SpeechToText.d.ts.map +1 -1
- package/dist/components/core/Switch.d.ts.map +1 -1
- package/dist/components/core/Table/ActionMenu.d.ts.map +1 -1
- package/dist/components/core/Table/ColumnMenu.d.ts +2 -1
- package/dist/components/core/Table/ColumnMenu.d.ts.map +1 -1
- package/dist/components/core/Table/MobileCard.d.ts +2 -2
- package/dist/components/core/Table/MobileCard.d.ts.map +1 -1
- package/dist/components/core/Table/Table.d.ts.map +1 -1
- package/dist/components/core/Table/TableRow.d.ts +4 -2
- package/dist/components/core/Table/TableRow.d.ts.map +1 -1
- package/dist/components/core/Tabs.d.ts.map +1 -1
- package/dist/components/core/Textarea.d.ts +4 -0
- package/dist/components/core/Textarea.d.ts.map +1 -0
- package/dist/components/core/ThreeDotPopover.d.ts.map +1 -1
- package/dist/components/core/Tooltip.d.ts.map +1 -1
- package/dist/components/feedback/Dialog.d.ts.map +1 -1
- package/dist/components/feedback/Drawer.d.ts +4 -0
- package/dist/components/feedback/Drawer.d.ts.map +1 -0
- package/dist/components/feedback/Toast.d.ts +14 -5
- package/dist/components/feedback/Toast.d.ts.map +1 -1
- package/dist/components/feedback/Tour.d.ts +4 -0
- package/dist/components/feedback/Tour.d.ts.map +1 -0
- package/dist/components/feedback/TourSpotlight.d.ts +9 -0
- package/dist/components/feedback/TourSpotlight.d.ts.map +1 -0
- package/dist/components/navigation/Breadcrumbs.d.ts.map +1 -1
- package/dist/components/navigation/FootNav.d.ts.map +1 -1
- package/dist/components/navigation/Navbar.d.ts.map +1 -1
- package/dist/components/navigation/Sidebar.d.ts +8 -2
- package/dist/components/navigation/Sidebar.d.ts.map +1 -1
- package/dist/components/utility/Badge.d.ts.map +1 -1
- package/dist/components/utility/FileUpload.d.ts.map +1 -1
- package/dist/components/utility/Sortable.d.ts +4 -0
- package/dist/components/utility/Sortable.d.ts.map +1 -0
- package/dist/esm/_vendor/object-assign/index.js +99 -0
- package/dist/esm/_vendor/prop-types/_vendor/react-is/cjs/react-is.development.js +190 -0
- package/dist/esm/_vendor/prop-types/_vendor/react-is/cjs/react-is.production.min.js +26 -0
- package/dist/esm/_vendor/prop-types/_vendor/react-is/index.js +19 -0
- package/dist/esm/_vendor/prop-types/checkPropTypes.js +115 -0
- package/dist/esm/_vendor/prop-types/factoryWithThrowingShims.js +74 -0
- package/dist/esm/_vendor/prop-types/factoryWithTypeCheckers.js +625 -0
- package/dist/esm/_vendor/prop-types/index.js +30 -0
- package/dist/esm/_vendor/prop-types/lib/ReactPropTypesSecret.js +21 -0
- package/dist/esm/_vendor/prop-types/lib/has.js +11 -0
- package/dist/esm/_virtual/_commonjsHelpers.js +5 -0
- package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +329 -0
- package/dist/esm/_virtual/index.js +3 -0
- package/dist/esm/_virtual/index2.js +3 -0
- package/dist/esm/_virtual/react-is.development.js +3 -0
- package/dist/esm/_virtual/react-is.production.min.js +3 -0
- package/dist/esm/components/blocks/AppShell.js +205 -0
- package/dist/esm/components/blocks/ConfirmDialog.js +57 -0
- package/dist/esm/components/blocks/EmptyState.js +44 -0
- package/dist/esm/components/blocks/ErrorState.js +53 -0
- package/dist/esm/components/blocks/LoadingState.js +134 -0
- package/dist/esm/components/blocks/PageHeader.js +51 -0
- package/dist/esm/components/blocks/StatCard.js +79 -0
- package/dist/esm/components/blocks/StatusPill.js +55 -0
- package/dist/esm/components/core/Accordion.js +260 -0
- package/dist/esm/components/core/Button.js +59 -0
- package/dist/esm/components/core/Checkbox.js +188 -0
- package/dist/esm/components/core/ColorPicker.js +348 -0
- package/dist/esm/components/core/DatePicker.js +436 -0
- package/dist/esm/components/core/DateRangePicker.js +494 -0
- package/dist/esm/components/core/Form.js +522 -0
- package/dist/esm/components/core/Input.js +179 -0
- package/dist/esm/components/core/Loader.js +141 -0
- package/dist/esm/components/core/LocationPicker.js +161 -0
- package/dist/esm/components/core/Popover.js +171 -0
- package/dist/esm/components/core/PriceRangePicker.js +376 -0
- package/dist/esm/components/core/ProgressBar.js +152 -0
- package/dist/esm/components/core/Radio.js +156 -0
- package/dist/esm/components/core/Rate.js +197 -0
- package/dist/esm/components/core/RoundedTag.js +118 -0
- package/dist/esm/components/core/Select.js +857 -0
- package/dist/esm/components/core/Skeleton.js +100 -0
- package/dist/esm/components/core/Slider.js +134 -0
- package/dist/esm/components/core/SpeechToText.js +226 -0
- package/dist/esm/components/core/Switch.js +207 -0
- package/dist/esm/components/core/Table/ActionMenu.js +251 -0
- package/dist/esm/components/core/Table/ColumnMenu.js +55 -0
- package/dist/esm/components/core/Table/FieldInput.js +157 -0
- package/dist/esm/components/core/Table/MobileCard.js +187 -0
- package/dist/esm/components/core/Table/MobileFilters.js +72 -0
- package/dist/esm/components/core/Table/Pagination.js +157 -0
- package/dist/esm/components/core/Table/Table.js +1533 -0
- package/dist/esm/components/core/Table/TableRow.js +254 -0
- package/dist/esm/components/core/Table/constants.js +35 -0
- package/dist/esm/components/core/Table/helpers.js +124 -0
- package/dist/esm/components/core/Table/useClickOutside.js +26 -0
- package/dist/esm/components/core/Tabs.js +289 -0
- package/dist/esm/components/core/TextToSpeech.js +52 -0
- package/dist/esm/components/core/Textarea.js +125 -0
- package/dist/esm/components/core/ThreeDotPopover.js +160 -0
- package/dist/esm/components/core/Tooltip.js +372 -0
- package/dist/esm/components/feedback/Alert.js +96 -0
- package/dist/esm/components/feedback/Dialog.js +200 -0
- package/dist/esm/components/feedback/Drawer.js +171 -0
- package/dist/esm/components/feedback/Toast.js +362 -0
- package/dist/esm/components/feedback/Tour.js +214 -0
- package/dist/esm/components/feedback/TourSpotlight.js +71 -0
- package/dist/esm/components/navigation/Breadcrumbs.js +75 -0
- package/dist/esm/components/navigation/Dropdown.js +53 -0
- package/dist/esm/components/navigation/FootNav.js +51 -0
- package/dist/esm/components/navigation/Navbar.js +437 -0
- package/dist/esm/components/navigation/Sidebar.js +567 -0
- package/dist/esm/components/utility/Avatar.js +89 -0
- package/dist/esm/components/utility/Badge.js +47 -0
- package/dist/esm/components/utility/Card.js +85 -0
- package/dist/esm/components/utility/Carousel.js +97 -0
- package/dist/esm/components/utility/Condition.js +9 -0
- package/dist/esm/components/utility/FileUpload.js +177 -0
- package/dist/esm/components/utility/Pagination.js +111 -0
- package/dist/esm/components/utility/Sortable.js +190 -0
- package/dist/esm/components/utility/Stepper.js +101 -0
- package/dist/esm/hooks/useApi.js +169 -0
- package/dist/esm/hooks/useControllableState.js +32 -0
- package/dist/esm/hooks/useFocusTrap.js +85 -0
- package/dist/esm/hooks/useLatestRef.js +20 -0
- package/dist/esm/hooks/useMixins.js +100 -0
- package/dist/esm/hooks/useScrollLock.js +26 -0
- package/dist/esm/hooks/useSliderValues.js +135 -0
- package/dist/esm/hooks/useSortable.js +188 -0
- package/dist/esm/hooks/useTheme.js +53 -0
- package/dist/esm/hooks/useTourTarget.js +92 -0
- package/dist/esm/index.js +65 -0
- package/dist/esm/store/index.js +26 -0
- package/dist/esm/store/store.js +107 -0
- package/dist/esm/store/storeSlice.js +45 -0
- package/dist/esm/utils/cn.js +11 -0
- package/dist/esm/utils/emitter.js +169 -0
- package/dist/esm/utils/helpers.js +161 -0
- package/dist/esm/utils/position.js +134 -0
- package/dist/hooks/useApi.d.ts +2 -1
- package/dist/hooks/useApi.d.ts.map +1 -1
- package/dist/hooks/useControllableState.d.ts +11 -0
- package/dist/hooks/useControllableState.d.ts.map +1 -0
- package/dist/hooks/useFocusTrap.d.ts +15 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -0
- package/dist/hooks/useLatestRef.d.ts +8 -0
- package/dist/hooks/useLatestRef.d.ts.map +1 -0
- package/dist/hooks/useMixins.d.ts.map +1 -1
- package/dist/hooks/useScrollLock.d.ts +2 -0
- package/dist/hooks/useScrollLock.d.ts.map +1 -0
- package/dist/hooks/useSliderValues.d.ts +43 -0
- package/dist/hooks/useSliderValues.d.ts.map +1 -0
- package/dist/hooks/useSortable.d.ts +32 -0
- package/dist/hooks/useSortable.d.ts.map +1 -0
- package/dist/hooks/useTheme.d.ts.map +1 -1
- package/dist/hooks/useTourTarget.d.ts +15 -0
- package/dist/hooks/useTourTarget.d.ts.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.js +4800 -2212
- package/dist/index.js +4805 -2210
- package/dist/types/index.d.ts +193 -5
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/position.d.ts +30 -0
- package/dist/utils/position.d.ts.map +1 -0
- package/doc/README.md +7 -1
- package/mcp/catalog.snapshot.json +911 -212
- package/package.json +14 -2
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { objectWithoutProperties as _objectWithoutProperties, objectSpread2 as _objectSpread2 } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
4
|
+
import React, { useRef, useId } from 'react';
|
|
5
|
+
import { createPortal } from 'react-dom';
|
|
6
|
+
import { X } from 'lucide-react';
|
|
7
|
+
import { cn } from '../../utils/cn.js';
|
|
8
|
+
import { setRefs } from '../../utils/position.js';
|
|
9
|
+
import { useFocusTrap } from '../../hooks/useFocusTrap.js';
|
|
10
|
+
import { useScrollLock } from '../../hooks/useScrollLock.js';
|
|
11
|
+
|
|
12
|
+
var _excluded = ["isOpen", "onClose", "title", "description", "children", "placement", "size", "dismissible", "showCloseButton", "footer", "initialFocusRef", "className"],
|
|
13
|
+
_excluded2 = ["className"],
|
|
14
|
+
_excluded3 = ["className"],
|
|
15
|
+
_excluded4 = ["className"];
|
|
16
|
+
var PLACEMENT_CLASSES = {
|
|
17
|
+
right: "inset-y-0 right-0 h-full w-full border-l",
|
|
18
|
+
left: "inset-y-0 left-0 h-full w-full border-r",
|
|
19
|
+
top: "inset-x-0 top-0 w-full border-b",
|
|
20
|
+
bottom: "inset-x-0 bottom-0 w-full border-t"
|
|
21
|
+
};
|
|
22
|
+
var SIDE_SIZES = {
|
|
23
|
+
sm: "max-w-xs",
|
|
24
|
+
md: "max-w-md",
|
|
25
|
+
lg: "max-w-2xl",
|
|
26
|
+
xl: "max-w-4xl",
|
|
27
|
+
full: "max-w-full"
|
|
28
|
+
};
|
|
29
|
+
var EDGE_SIZES = {
|
|
30
|
+
sm: "max-h-[30vh]",
|
|
31
|
+
md: "max-h-[50vh]",
|
|
32
|
+
lg: "max-h-[75vh]",
|
|
33
|
+
xl: "max-h-[90vh]",
|
|
34
|
+
full: "h-full"
|
|
35
|
+
};
|
|
36
|
+
var CloseButton = function CloseButton(_ref) {
|
|
37
|
+
var onClose = _ref.onClose,
|
|
38
|
+
className = _ref.className;
|
|
39
|
+
return jsx("button", {
|
|
40
|
+
type: "button",
|
|
41
|
+
onClick: onClose,
|
|
42
|
+
"aria-label": "Close drawer",
|
|
43
|
+
className: cn("rounded-md p-1 text-gray-500 hover:bg-gray-100 hover:text-gray-700 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2", "dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-200 dark:focus:ring-offset-gray-900", className),
|
|
44
|
+
children: jsx(X, {
|
|
45
|
+
className: "h-5 w-5",
|
|
46
|
+
"aria-hidden": "true"
|
|
47
|
+
})
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
var Drawer = /*#__PURE__*/React.forwardRef(function (_ref2, _ref3) {
|
|
51
|
+
var isOpen = _ref2.isOpen,
|
|
52
|
+
onClose = _ref2.onClose,
|
|
53
|
+
title = _ref2.title,
|
|
54
|
+
description = _ref2.description,
|
|
55
|
+
children = _ref2.children,
|
|
56
|
+
_ref2$placement = _ref2.placement,
|
|
57
|
+
placement = _ref2$placement === void 0 ? "right" : _ref2$placement,
|
|
58
|
+
_ref2$size = _ref2.size,
|
|
59
|
+
size = _ref2$size === void 0 ? "md" : _ref2$size,
|
|
60
|
+
_ref2$dismissible = _ref2.dismissible,
|
|
61
|
+
dismissible = _ref2$dismissible === void 0 ? true : _ref2$dismissible,
|
|
62
|
+
_ref2$showCloseButton = _ref2.showCloseButton,
|
|
63
|
+
showCloseButton = _ref2$showCloseButton === void 0 ? true : _ref2$showCloseButton,
|
|
64
|
+
footer = _ref2.footer,
|
|
65
|
+
initialFocusRef = _ref2.initialFocusRef,
|
|
66
|
+
className = _ref2.className,
|
|
67
|
+
props = _objectWithoutProperties(_ref2, _excluded);
|
|
68
|
+
var panelRef = useRef(null);
|
|
69
|
+
var titleId = "drawer-title-".concat(useId());
|
|
70
|
+
var descriptionId = "drawer-description-".concat(useId());
|
|
71
|
+
var side = PLACEMENT_CLASSES[placement] ? placement : "right";
|
|
72
|
+
var isEdge = side === "top" || side === "bottom";
|
|
73
|
+
// Without title/description/footer the children are the panel content, so
|
|
74
|
+
// Drawer.Header / Drawer.Body / Drawer.Footer compose without double padding.
|
|
75
|
+
var composed = !title && !description && !footer;
|
|
76
|
+
useScrollLock(isOpen);
|
|
77
|
+
useFocusTrap(panelRef, {
|
|
78
|
+
active: isOpen,
|
|
79
|
+
initialFocusRef: initialFocusRef,
|
|
80
|
+
onEscape: function onEscape() {
|
|
81
|
+
if (dismissible) onClose === null || onClose === void 0 || onClose();
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
if (!isOpen || typeof document === "undefined") return null;
|
|
85
|
+
return /*#__PURE__*/createPortal(jsxs("div", {
|
|
86
|
+
className: "fixed inset-0 z-50",
|
|
87
|
+
children: [jsx("div", {
|
|
88
|
+
"aria-hidden": "true",
|
|
89
|
+
"data-testid": "drawer-backdrop",
|
|
90
|
+
className: "absolute inset-0 bg-black/50 animate-fade-in motion-reduce:animate-none",
|
|
91
|
+
onClick: function onClick() {
|
|
92
|
+
return dismissible && (onClose === null || onClose === void 0 ? void 0 : onClose());
|
|
93
|
+
}
|
|
94
|
+
}), jsx("div", _objectSpread2(_objectSpread2({
|
|
95
|
+
ref: function ref(node) {
|
|
96
|
+
return setRefs(node, panelRef, _ref3);
|
|
97
|
+
},
|
|
98
|
+
role: "dialog",
|
|
99
|
+
"aria-modal": "true",
|
|
100
|
+
"aria-labelledby": title ? titleId : undefined,
|
|
101
|
+
"aria-describedby": description ? descriptionId : undefined,
|
|
102
|
+
tabIndex: -1,
|
|
103
|
+
"data-placement": side,
|
|
104
|
+
className: cn("absolute flex flex-col border-gray-200 bg-white text-gray-900 shadow-xl focus:outline-none", "dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100", "animate-fade-in motion-reduce:animate-none", PLACEMENT_CLASSES[side], (isEdge ? EDGE_SIZES : SIDE_SIZES)[size] || (isEdge ? EDGE_SIZES.md : SIDE_SIZES.md), className)
|
|
105
|
+
}, props), {}, {
|
|
106
|
+
children: composed ? jsxs(Fragment, {
|
|
107
|
+
children: [showCloseButton && jsx(CloseButton, {
|
|
108
|
+
onClose: onClose,
|
|
109
|
+
className: "absolute right-3 top-3"
|
|
110
|
+
}), children]
|
|
111
|
+
}) : jsxs(Fragment, {
|
|
112
|
+
children: [jsxs("div", {
|
|
113
|
+
className: "flex items-start justify-between gap-4 border-b border-gray-200 px-6 py-4 dark:border-gray-700",
|
|
114
|
+
children: [jsxs("div", {
|
|
115
|
+
className: "min-w-0",
|
|
116
|
+
children: [title && jsx("h2", {
|
|
117
|
+
id: titleId,
|
|
118
|
+
className: "text-lg font-semibold",
|
|
119
|
+
children: title
|
|
120
|
+
}), description && jsx("p", {
|
|
121
|
+
id: descriptionId,
|
|
122
|
+
className: "mt-1 text-sm text-gray-500 dark:text-gray-400",
|
|
123
|
+
children: description
|
|
124
|
+
})]
|
|
125
|
+
}), showCloseButton && jsx(CloseButton, {
|
|
126
|
+
onClose: onClose
|
|
127
|
+
})]
|
|
128
|
+
}), jsx("div", {
|
|
129
|
+
className: "min-h-0 flex-1 overflow-y-auto px-6 py-4",
|
|
130
|
+
children: children
|
|
131
|
+
}), footer && jsx("div", {
|
|
132
|
+
className: "flex items-center justify-end gap-3 border-t border-gray-200 px-6 py-4 dark:border-gray-700",
|
|
133
|
+
children: footer
|
|
134
|
+
})]
|
|
135
|
+
})
|
|
136
|
+
}))]
|
|
137
|
+
}), document.body);
|
|
138
|
+
});
|
|
139
|
+
Drawer.displayName = "Drawer";
|
|
140
|
+
var DrawerHeader = /*#__PURE__*/React.forwardRef(function (_ref4, ref) {
|
|
141
|
+
var className = _ref4.className,
|
|
142
|
+
props = _objectWithoutProperties(_ref4, _excluded2);
|
|
143
|
+
return jsx("div", _objectSpread2({
|
|
144
|
+
ref: ref,
|
|
145
|
+
className: cn("border-b border-gray-200 px-6 py-4 dark:border-gray-700", className)
|
|
146
|
+
}, props));
|
|
147
|
+
});
|
|
148
|
+
var DrawerBody = /*#__PURE__*/React.forwardRef(function (_ref5, ref) {
|
|
149
|
+
var className = _ref5.className,
|
|
150
|
+
props = _objectWithoutProperties(_ref5, _excluded3);
|
|
151
|
+
return jsx("div", _objectSpread2({
|
|
152
|
+
ref: ref,
|
|
153
|
+
className: cn("min-h-0 flex-1 overflow-y-auto px-6 py-4", className)
|
|
154
|
+
}, props));
|
|
155
|
+
});
|
|
156
|
+
var DrawerFooter = /*#__PURE__*/React.forwardRef(function (_ref6, ref) {
|
|
157
|
+
var className = _ref6.className,
|
|
158
|
+
props = _objectWithoutProperties(_ref6, _excluded4);
|
|
159
|
+
return jsx("div", _objectSpread2({
|
|
160
|
+
ref: ref,
|
|
161
|
+
className: cn("flex items-center justify-end gap-3 border-t border-gray-200 px-6 py-4 dark:border-gray-700", className)
|
|
162
|
+
}, props));
|
|
163
|
+
});
|
|
164
|
+
DrawerHeader.displayName = "Drawer.Header";
|
|
165
|
+
DrawerBody.displayName = "Drawer.Body";
|
|
166
|
+
DrawerFooter.displayName = "Drawer.Footer";
|
|
167
|
+
Drawer.Header = DrawerHeader;
|
|
168
|
+
Drawer.Body = DrawerBody;
|
|
169
|
+
Drawer.Footer = DrawerFooter;
|
|
170
|
+
|
|
171
|
+
export { Drawer as default };
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2, toConsumableArray as _toConsumableArray, typeof as _typeof } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
3
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
4
|
+
import { forwardRef, useState, useRef, useCallback, useEffect, useContext, createContext, useMemo } from 'react';
|
|
5
|
+
import { createPortal } from 'react-dom';
|
|
6
|
+
import { cn } from '../../utils/cn.js';
|
|
7
|
+
import { Bell, Info, AlertTriangle, XCircle, CheckCircle2, X } from 'lucide-react';
|
|
8
|
+
|
|
9
|
+
var _excluded = ["id", "title", "message", "description", "type", "duration", "onClose", "position", "statusIcon", "actions", "color", "footerNote", "showFooterNote", "portal", "className"];
|
|
10
|
+
var STATUS_CONFIG = {
|
|
11
|
+
success: {
|
|
12
|
+
icon: CheckCircle2,
|
|
13
|
+
iconClass: 'text-emerald-500 dark:text-emerald-400',
|
|
14
|
+
progressClass: 'bg-emerald-500 dark:bg-emerald-400'
|
|
15
|
+
},
|
|
16
|
+
error: {
|
|
17
|
+
icon: XCircle,
|
|
18
|
+
iconClass: 'text-rose-500 dark:text-rose-400',
|
|
19
|
+
progressClass: 'bg-rose-500 dark:bg-rose-400'
|
|
20
|
+
},
|
|
21
|
+
warning: {
|
|
22
|
+
icon: AlertTriangle,
|
|
23
|
+
iconClass: 'text-amber-500 dark:text-amber-400',
|
|
24
|
+
progressClass: 'bg-amber-500 dark:bg-amber-400'
|
|
25
|
+
},
|
|
26
|
+
info: {
|
|
27
|
+
icon: Info,
|
|
28
|
+
iconClass: 'text-sky-500 dark:text-sky-400',
|
|
29
|
+
progressClass: 'bg-sky-500 dark:bg-sky-400'
|
|
30
|
+
},
|
|
31
|
+
"default": {
|
|
32
|
+
icon: Bell,
|
|
33
|
+
iconClass: 'text-primary-500 dark:text-primary-400',
|
|
34
|
+
progressClass: 'bg-primary-500 dark:bg-primary-400'
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
var POSITION_CLASSES = {
|
|
38
|
+
'top-right': 'top-4 right-4 items-end',
|
|
39
|
+
'top-left': 'top-4 left-4 items-start',
|
|
40
|
+
'bottom-right': 'bottom-4 right-4 items-end',
|
|
41
|
+
'bottom-left': 'bottom-4 left-4 items-start',
|
|
42
|
+
'top-center': 'top-4 left-1/2 transform -translate-x-1/2 items-center',
|
|
43
|
+
'bottom-center': 'bottom-4 left-1/2 transform -translate-x-1/2 items-center'
|
|
44
|
+
};
|
|
45
|
+
var STANDALONE_POSITION_CLASSES = {
|
|
46
|
+
'top-right': 'top-4 right-4',
|
|
47
|
+
'top-left': 'top-4 left-4',
|
|
48
|
+
'bottom-right': 'bottom-4 right-4',
|
|
49
|
+
'bottom-left': 'bottom-4 left-4',
|
|
50
|
+
'top-center': 'top-4 left-1/2 transform -translate-x-1/2',
|
|
51
|
+
'bottom-center': 'bottom-4 left-1/2 transform -translate-x-1/2'
|
|
52
|
+
};
|
|
53
|
+
var Toast = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
54
|
+
var id = _ref.id,
|
|
55
|
+
title = _ref.title,
|
|
56
|
+
message = _ref.message,
|
|
57
|
+
description = _ref.description,
|
|
58
|
+
_ref$type = _ref.type,
|
|
59
|
+
type = _ref$type === void 0 ? 'info' : _ref$type,
|
|
60
|
+
_ref$duration = _ref.duration,
|
|
61
|
+
duration = _ref$duration === void 0 ? 5000 : _ref$duration,
|
|
62
|
+
onClose = _ref.onClose,
|
|
63
|
+
_ref$position = _ref.position,
|
|
64
|
+
position = _ref$position === void 0 ? 'top-right' : _ref$position,
|
|
65
|
+
statusIcon = _ref.statusIcon,
|
|
66
|
+
_ref$actions = _ref.actions,
|
|
67
|
+
actions = _ref$actions === void 0 ? [] : _ref$actions,
|
|
68
|
+
color = _ref.color,
|
|
69
|
+
footerNote = _ref.footerNote,
|
|
70
|
+
_ref$showFooterNote = _ref.showFooterNote,
|
|
71
|
+
showFooterNote = _ref$showFooterNote === void 0 ? false : _ref$showFooterNote,
|
|
72
|
+
_ref$portal = _ref.portal,
|
|
73
|
+
portal = _ref$portal === void 0 ? true : _ref$portal,
|
|
74
|
+
_ref$className = _ref.className,
|
|
75
|
+
className = _ref$className === void 0 ? '' : _ref$className,
|
|
76
|
+
props = _objectWithoutProperties(_ref, _excluded);
|
|
77
|
+
var _useState = useState(true),
|
|
78
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
79
|
+
isVisible = _useState2[0],
|
|
80
|
+
setIsVisible = _useState2[1];
|
|
81
|
+
var _useState3 = useState(false),
|
|
82
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
83
|
+
isLeaving = _useState4[0],
|
|
84
|
+
setIsLeaving = _useState4[1];
|
|
85
|
+
var _useState5 = useState(false),
|
|
86
|
+
_useState6 = _slicedToArray(_useState5, 2),
|
|
87
|
+
isPaused = _useState6[0],
|
|
88
|
+
setIsPaused = _useState6[1];
|
|
89
|
+
var progressBarRef = useRef(null);
|
|
90
|
+
var timerTextRef = useRef(null);
|
|
91
|
+
var startTimeRef = useRef(null);
|
|
92
|
+
var remainingRef = useRef(duration);
|
|
93
|
+
var timerRef = useRef(null);
|
|
94
|
+
var animFrameRef = useRef(null);
|
|
95
|
+
var handleClose = useCallback(function () {
|
|
96
|
+
if (isLeaving) return;
|
|
97
|
+
setIsLeaving(true);
|
|
98
|
+
setTimeout(function () {
|
|
99
|
+
setIsVisible(false);
|
|
100
|
+
onClose === null || onClose === void 0 || onClose(id);
|
|
101
|
+
}, 300);
|
|
102
|
+
}, [id, onClose, isLeaving]);
|
|
103
|
+
var handleStopTimer = useCallback(function (e) {
|
|
104
|
+
e === null || e === void 0 || e.stopPropagation();
|
|
105
|
+
setIsPaused(true);
|
|
106
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
107
|
+
if (animFrameRef.current) cancelAnimationFrame(animFrameRef.current);
|
|
108
|
+
}, []);
|
|
109
|
+
// Direct DOM-based progress updates to prevent 60 FPS React re-renders and glitches
|
|
110
|
+
useEffect(function () {
|
|
111
|
+
if (duration <= 0) return;
|
|
112
|
+
if (isPaused) {
|
|
113
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
114
|
+
if (animFrameRef.current) cancelAnimationFrame(animFrameRef.current);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
startTimeRef.current = Date.now();
|
|
118
|
+
timerRef.current = setTimeout(function () {
|
|
119
|
+
handleClose();
|
|
120
|
+
}, remainingRef.current);
|
|
121
|
+
var _updateProgress = function updateProgress() {
|
|
122
|
+
var elapsed = startTimeRef.current ? Date.now() - startTimeRef.current : 0;
|
|
123
|
+
var currentRemaining = Math.max(0, remainingRef.current - elapsed);
|
|
124
|
+
var pct = currentRemaining / duration * 100;
|
|
125
|
+
if (progressBarRef.current) {
|
|
126
|
+
progressBarRef.current.style.width = "".concat(pct, "%");
|
|
127
|
+
}
|
|
128
|
+
if (timerTextRef.current) {
|
|
129
|
+
var secs = Math.ceil(currentRemaining / 1000);
|
|
130
|
+
timerTextRef.current.textContent = "This message will close in ".concat(secs, " seconds. ");
|
|
131
|
+
}
|
|
132
|
+
if (currentRemaining > 0 && !isPaused) {
|
|
133
|
+
animFrameRef.current = requestAnimationFrame(_updateProgress);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
animFrameRef.current = requestAnimationFrame(_updateProgress);
|
|
137
|
+
return function () {
|
|
138
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
139
|
+
if (animFrameRef.current) cancelAnimationFrame(animFrameRef.current);
|
|
140
|
+
if (!isPaused && startTimeRef.current) {
|
|
141
|
+
var elapsed = Date.now() - startTimeRef.current;
|
|
142
|
+
remainingRef.current = Math.max(0, remainingRef.current - elapsed);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}, [duration, isPaused, handleClose]);
|
|
146
|
+
if (!isVisible) return null;
|
|
147
|
+
var statusStyle = STATUS_CONFIG[type] || STATUS_CONFIG.info || STATUS_CONFIG["default"];
|
|
148
|
+
var StatusIconComponent = statusStyle.icon;
|
|
149
|
+
var bodyText = description || message;
|
|
150
|
+
var toastContent = jsxs("div", _objectSpread2(_objectSpread2({
|
|
151
|
+
ref: ref,
|
|
152
|
+
onMouseEnter: function onMouseEnter() {
|
|
153
|
+
return setIsPaused(true);
|
|
154
|
+
},
|
|
155
|
+
onMouseLeave: function onMouseLeave() {
|
|
156
|
+
return setIsPaused(false);
|
|
157
|
+
},
|
|
158
|
+
className: cn('relative overflow-hidden rounded-xl border border-slate-200/90 bg-white/95 shadow-xl backdrop-blur-md transition-all duration-300', 'dark:border-slate-800/80 dark:bg-[#18181b] dark:text-slate-100 dark:shadow-2xl', 'max-w-md w-full', isLeaving ? 'opacity-0 scale-95 translate-y-1' : 'animate-slide-up opacity-100 scale-100', portal ? ['fixed z-50', STANDALONE_POSITION_CLASSES[position] || STANDALONE_POSITION_CLASSES['top-right']] : '', className)
|
|
159
|
+
}, props), {}, {
|
|
160
|
+
children: [jsx("div", {
|
|
161
|
+
className: "p-4",
|
|
162
|
+
children: jsxs("div", {
|
|
163
|
+
className: "flex items-start gap-3 justify-between",
|
|
164
|
+
children: [jsx("span", {
|
|
165
|
+
className: "flex-shrink-0 mt-0.5",
|
|
166
|
+
children: statusIcon ? statusIcon : jsx(StatusIconComponent, {
|
|
167
|
+
className: cn('h-5 w-5', statusStyle.iconClass)
|
|
168
|
+
})
|
|
169
|
+
}), jsxs("div", {
|
|
170
|
+
className: "flex-1 min-w-0 pr-2",
|
|
171
|
+
children: [title && jsx("h4", {
|
|
172
|
+
className: "text-sm font-semibold text-slate-900 dark:text-slate-100 leading-snug",
|
|
173
|
+
children: title
|
|
174
|
+
}), bodyText && jsx("p", {
|
|
175
|
+
className: "mt-1 text-xs text-slate-600 dark:text-slate-400 leading-relaxed whitespace-pre-line",
|
|
176
|
+
children: bodyText
|
|
177
|
+
}), actions && actions.length > 0 && jsx("div", {
|
|
178
|
+
className: "mt-3 flex items-center gap-2 flex-wrap",
|
|
179
|
+
children: actions.map(function (actItem, idx) {
|
|
180
|
+
return jsx("button", {
|
|
181
|
+
type: "button",
|
|
182
|
+
onClick: function onClick(e) {
|
|
183
|
+
var _actItem$onClick;
|
|
184
|
+
(_actItem$onClick = actItem.onClick) === null || _actItem$onClick === void 0 || _actItem$onClick.call(actItem, e);
|
|
185
|
+
if (actItem.dismiss !== false) {
|
|
186
|
+
handleClose();
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
className: cn('px-3 py-1.5 text-xs font-medium rounded-lg transition-colors border shadow-xs', actItem.variant === 'primary' ? 'bg-primary-600 hover:bg-primary-700 text-white border-primary-600' : 'bg-slate-100 dark:bg-zinc-800/80 text-slate-700 dark:text-zinc-200 border-slate-200 dark:border-zinc-700 hover:bg-slate-200 dark:hover:bg-zinc-700', actItem.className),
|
|
190
|
+
children: actItem.label
|
|
191
|
+
}, actItem.id || actItem.label || "act-".concat(idx));
|
|
192
|
+
})
|
|
193
|
+
})]
|
|
194
|
+
}), jsx("button", {
|
|
195
|
+
type: "button",
|
|
196
|
+
"aria-label": "Close notification",
|
|
197
|
+
className: "flex-shrink-0 rounded-lg p-1 text-slate-400 hover:text-slate-600 dark:hover:text-slate-200 hover:bg-slate-100 dark:hover:bg-zinc-800/70 transition-colors outline-none focus:ring-2 focus:ring-primary-500",
|
|
198
|
+
onClick: handleClose,
|
|
199
|
+
children: jsx(X, {
|
|
200
|
+
className: "h-4 w-4"
|
|
201
|
+
})
|
|
202
|
+
})]
|
|
203
|
+
})
|
|
204
|
+
}), (showFooterNote || footerNote) && duration > 0 && jsx("div", {
|
|
205
|
+
className: "px-4 py-2 bg-slate-50 dark:bg-zinc-950/40 border-t border-slate-100 dark:border-zinc-800/50 text-[11px] text-slate-500 dark:text-zinc-400 flex items-center justify-between",
|
|
206
|
+
children: jsx("span", {
|
|
207
|
+
children: footerNote ? footerNote : jsxs(Fragment, {
|
|
208
|
+
children: [jsxs("span", {
|
|
209
|
+
ref: timerTextRef,
|
|
210
|
+
children: ["This message will close in ", Math.ceil(duration / 1000), " seconds.", ' ']
|
|
211
|
+
}), jsx("button", {
|
|
212
|
+
type: "button",
|
|
213
|
+
onClick: handleStopTimer,
|
|
214
|
+
className: "font-medium text-slate-700 dark:text-zinc-200 hover:underline inline",
|
|
215
|
+
children: "Click to stop."
|
|
216
|
+
})]
|
|
217
|
+
})
|
|
218
|
+
})
|
|
219
|
+
}), duration > 0 && jsx("div", {
|
|
220
|
+
className: "absolute bottom-0 left-0 right-0 h-0.5 bg-slate-100 dark:bg-zinc-800/80 overflow-hidden rounded-b-xl",
|
|
221
|
+
children: jsx("div", {
|
|
222
|
+
ref: progressBarRef,
|
|
223
|
+
className: cn('h-full transition-all ease-linear', color ? '' : statusStyle.progressClass),
|
|
224
|
+
style: {
|
|
225
|
+
width: '100%',
|
|
226
|
+
backgroundColor: color || undefined
|
|
227
|
+
}
|
|
228
|
+
})
|
|
229
|
+
})]
|
|
230
|
+
}));
|
|
231
|
+
if (portal) {
|
|
232
|
+
return /*#__PURE__*/createPortal(toastContent, document.body);
|
|
233
|
+
}
|
|
234
|
+
return toastContent;
|
|
235
|
+
});
|
|
236
|
+
Toast.displayName = 'Toast';
|
|
237
|
+
// Shared queue for <ToastProvider>. `null` outside a provider, where useToast
|
|
238
|
+
// falls back to its own component-local queue (the pre-provider behavior).
|
|
239
|
+
var ToastContext = /*#__PURE__*/createContext(null);
|
|
240
|
+
var ToastStack = function ToastStack(_ref2) {
|
|
241
|
+
var _ref2$toasts = _ref2.toasts,
|
|
242
|
+
toasts = _ref2$toasts === void 0 ? [] : _ref2$toasts,
|
|
243
|
+
_ref2$position = _ref2.position,
|
|
244
|
+
position = _ref2$position === void 0 ? 'top-right' : _ref2$position,
|
|
245
|
+
onRemove = _ref2.onRemove,
|
|
246
|
+
_ref2$className = _ref2.className,
|
|
247
|
+
className = _ref2$className === void 0 ? '' : _ref2$className;
|
|
248
|
+
if (!toasts || toasts.length === 0) {
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
var posClass = POSITION_CLASSES[position] || POSITION_CLASSES['top-right'];
|
|
252
|
+
return /*#__PURE__*/createPortal(jsx("div", {
|
|
253
|
+
className: cn('fixed z-50 flex flex-col gap-3 max-h-[calc(100vh-2rem)] overflow-y-auto overflow-x-hidden p-2 pointer-events-none', '[scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden', posClass, className),
|
|
254
|
+
children: toasts.map(function (t) {
|
|
255
|
+
return jsx("div", {
|
|
256
|
+
className: "pointer-events-auto w-full max-w-md",
|
|
257
|
+
children: jsx(Toast, _objectSpread2(_objectSpread2({}, t), {}, {
|
|
258
|
+
portal: false,
|
|
259
|
+
position: position,
|
|
260
|
+
onClose: onRemove
|
|
261
|
+
}))
|
|
262
|
+
}, t.id);
|
|
263
|
+
})
|
|
264
|
+
}), document.body);
|
|
265
|
+
};
|
|
266
|
+
// Toast Container Component for vertical stacking & scrollable overflow without visible scrollbars
|
|
267
|
+
var ToastContainer = function ToastContainer(props) {
|
|
268
|
+
var shared = useContext(ToastContext);
|
|
269
|
+
// Under a <ToastProvider> the provider already renders the shared queue, so a
|
|
270
|
+
// legacy `<ToastContainer toasts={useToast().toasts} />` would render every
|
|
271
|
+
// toast twice. Skip it when it is handed the provider's own queue.
|
|
272
|
+
if (shared && props.toasts === shared.toasts) return null;
|
|
273
|
+
return jsx(ToastStack, _objectSpread2({}, props));
|
|
274
|
+
};
|
|
275
|
+
var useToastQueue = function useToastQueue() {
|
|
276
|
+
var _useState7 = useState([]),
|
|
277
|
+
_useState8 = _slicedToArray(_useState7, 2),
|
|
278
|
+
toasts = _useState8[0],
|
|
279
|
+
setToasts = _useState8[1];
|
|
280
|
+
var addToast = useCallback(function (toastOptions) {
|
|
281
|
+
var id = toastOptions.id || "".concat(Date.now(), "-").concat(Math.random().toString(36).slice(2, 7));
|
|
282
|
+
var newToast = _objectSpread2(_objectSpread2({}, toastOptions), {}, {
|
|
283
|
+
id: id
|
|
284
|
+
});
|
|
285
|
+
setToasts(function (prev) {
|
|
286
|
+
return [].concat(_toConsumableArray(prev), [newToast]);
|
|
287
|
+
});
|
|
288
|
+
return id;
|
|
289
|
+
}, []);
|
|
290
|
+
var removeToast = useCallback(function (id) {
|
|
291
|
+
setToasts(function (prev) {
|
|
292
|
+
return prev.filter(function (t) {
|
|
293
|
+
return t.id !== id;
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
}, []);
|
|
297
|
+
var clearToasts = useCallback(function () {
|
|
298
|
+
setToasts([]);
|
|
299
|
+
}, []);
|
|
300
|
+
// Build the callable `toast` together with its typed shorthands in one
|
|
301
|
+
// memo, so the stable function is never mutated after creation.
|
|
302
|
+
var toast = useMemo(function () {
|
|
303
|
+
var withType = function withType(type) {
|
|
304
|
+
return function (title, message, options) {
|
|
305
|
+
return addToast(_objectSpread2({
|
|
306
|
+
title: title,
|
|
307
|
+
message: message,
|
|
308
|
+
type: type
|
|
309
|
+
}, _typeof(options) === 'object' ? options : {}));
|
|
310
|
+
};
|
|
311
|
+
};
|
|
312
|
+
return Object.assign(function (options) {
|
|
313
|
+
return addToast(typeof options === 'string' ? {
|
|
314
|
+
message: options
|
|
315
|
+
} : options);
|
|
316
|
+
}, {
|
|
317
|
+
success: withType('success'),
|
|
318
|
+
error: withType('error'),
|
|
319
|
+
warning: withType('warning'),
|
|
320
|
+
info: withType('info'),
|
|
321
|
+
"default": withType('default')
|
|
322
|
+
});
|
|
323
|
+
}, [addToast]);
|
|
324
|
+
return useMemo(function () {
|
|
325
|
+
return {
|
|
326
|
+
toast: toast,
|
|
327
|
+
toasts: toasts,
|
|
328
|
+
removeToast: removeToast,
|
|
329
|
+
clearToasts: clearToasts,
|
|
330
|
+
addToast: addToast
|
|
331
|
+
};
|
|
332
|
+
}, [toast, toasts, removeToast, clearToasts, addToast]);
|
|
333
|
+
};
|
|
334
|
+
// App-level provider: every useToast() below it shares ONE queue, rendered by
|
|
335
|
+
// the provider's own container — no per-screen <ToastContainer> needed.
|
|
336
|
+
var ToastProvider = function ToastProvider(_ref3) {
|
|
337
|
+
var children = _ref3.children,
|
|
338
|
+
_ref3$position = _ref3.position,
|
|
339
|
+
position = _ref3$position === void 0 ? 'top-right' : _ref3$position,
|
|
340
|
+
_ref3$className = _ref3.className,
|
|
341
|
+
className = _ref3$className === void 0 ? '' : _ref3$className;
|
|
342
|
+
var queue = useToastQueue();
|
|
343
|
+
return jsxs(ToastContext.Provider, {
|
|
344
|
+
value: queue,
|
|
345
|
+
children: [children, jsx(ToastStack, {
|
|
346
|
+
toasts: queue.toasts,
|
|
347
|
+
position: position,
|
|
348
|
+
onRemove: queue.removeToast,
|
|
349
|
+
className: className
|
|
350
|
+
})]
|
|
351
|
+
});
|
|
352
|
+
};
|
|
353
|
+
ToastProvider.displayName = 'ToastProvider';
|
|
354
|
+
// Toast Hook. Inside a <ToastProvider> it returns the shared queue; outside one
|
|
355
|
+
// it keeps a component-local queue (render it with <ToastContainer>).
|
|
356
|
+
var useToast = function useToast() {
|
|
357
|
+
var shared = useContext(ToastContext);
|
|
358
|
+
var local = useToastQueue();
|
|
359
|
+
return shared !== null && shared !== void 0 ? shared : local;
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
export { Toast, ToastContainer, ToastProvider, Toast as default, useToast };
|