uiplex 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +207 -0
  3. package/dist/Box/Box.d.ts +52 -0
  4. package/dist/Box/Box.d.ts.map +1 -0
  5. package/dist/Box/index.d.ts +3 -0
  6. package/dist/Box/index.d.ts.map +1 -0
  7. package/dist/Button/Button.d.ts +17 -0
  8. package/dist/Button/Button.d.ts.map +1 -0
  9. package/dist/Button/index.d.ts +3 -0
  10. package/dist/Button/index.d.ts.map +1 -0
  11. package/dist/CircularProgress/CircularProgress.d.ts +23 -0
  12. package/dist/CircularProgress/CircularProgress.d.ts.map +1 -0
  13. package/dist/CircularProgress/index.d.ts +3 -0
  14. package/dist/CircularProgress/index.d.ts.map +1 -0
  15. package/dist/Flex/Flex.d.ts +57 -0
  16. package/dist/Flex/Flex.d.ts.map +1 -0
  17. package/dist/Flex/index.d.ts +3 -0
  18. package/dist/Flex/index.d.ts.map +1 -0
  19. package/dist/FormControl/FormControl.d.ts +20 -0
  20. package/dist/FormControl/FormControl.d.ts.map +1 -0
  21. package/dist/FormControl/FormErrorMessage.d.ts +8 -0
  22. package/dist/FormControl/FormErrorMessage.d.ts.map +1 -0
  23. package/dist/FormControl/FormLabel.d.ts +9 -0
  24. package/dist/FormControl/FormLabel.d.ts.map +1 -0
  25. package/dist/FormControl/index.d.ts +7 -0
  26. package/dist/FormControl/index.d.ts.map +1 -0
  27. package/dist/Grid/Grid.d.ts +42 -0
  28. package/dist/Grid/Grid.d.ts.map +1 -0
  29. package/dist/Grid/index.d.ts +3 -0
  30. package/dist/Grid/index.d.ts.map +1 -0
  31. package/dist/IconButton/IconButton.d.ts +15 -0
  32. package/dist/IconButton/IconButton.d.ts.map +1 -0
  33. package/dist/IconButton/index.d.ts +3 -0
  34. package/dist/IconButton/index.d.ts.map +1 -0
  35. package/dist/Input/Input.d.ts +13 -0
  36. package/dist/Input/Input.d.ts.map +1 -0
  37. package/dist/Input/index.d.ts +3 -0
  38. package/dist/Input/index.d.ts.map +1 -0
  39. package/dist/Link/Link.d.ts +13 -0
  40. package/dist/Link/Link.d.ts.map +1 -0
  41. package/dist/Link/index.d.ts +3 -0
  42. package/dist/Link/index.d.ts.map +1 -0
  43. package/dist/Loader/Loader.d.ts +12 -0
  44. package/dist/Loader/Loader.d.ts.map +1 -0
  45. package/dist/Loader/index.d.ts +3 -0
  46. package/dist/Loader/index.d.ts.map +1 -0
  47. package/dist/Modal/Modal.d.ts +45 -0
  48. package/dist/Modal/Modal.d.ts.map +1 -0
  49. package/dist/Modal/index.d.ts +3 -0
  50. package/dist/Modal/index.d.ts.map +1 -0
  51. package/dist/Popover/Popover.d.ts +43 -0
  52. package/dist/Popover/Popover.d.ts.map +1 -0
  53. package/dist/Popover/index.d.ts +3 -0
  54. package/dist/Popover/index.d.ts.map +1 -0
  55. package/dist/Radio/Radio.d.ts +34 -0
  56. package/dist/Radio/Radio.d.ts.map +1 -0
  57. package/dist/Radio/index.d.ts +3 -0
  58. package/dist/Radio/index.d.ts.map +1 -0
  59. package/dist/Text/Text.d.ts +17 -0
  60. package/dist/Text/Text.d.ts.map +1 -0
  61. package/dist/Text/index.d.ts +3 -0
  62. package/dist/Text/index.d.ts.map +1 -0
  63. package/dist/Textarea/Textarea.d.ts +14 -0
  64. package/dist/Textarea/Textarea.d.ts.map +1 -0
  65. package/dist/Textarea/index.d.ts +3 -0
  66. package/dist/Textarea/index.d.ts.map +1 -0
  67. package/dist/Theme/ThemeProvider.d.ts +15 -0
  68. package/dist/Theme/ThemeProvider.d.ts.map +1 -0
  69. package/dist/Theme/ThemeScript.d.ts +31 -0
  70. package/dist/Theme/ThemeScript.d.ts.map +1 -0
  71. package/dist/Theme/ThemeToggle.d.ts +10 -0
  72. package/dist/Theme/ThemeToggle.d.ts.map +1 -0
  73. package/dist/Theme/index.d.ts +5 -0
  74. package/dist/Theme/index.d.ts.map +1 -0
  75. package/dist/Toast/Toast.d.ts +26 -0
  76. package/dist/Toast/Toast.d.ts.map +1 -0
  77. package/dist/Toast/ToastContainerGlobal.d.ts +3 -0
  78. package/dist/Toast/ToastContainerGlobal.d.ts.map +1 -0
  79. package/dist/Toast/ToastProvider.d.ts +11 -0
  80. package/dist/Toast/ToastProvider.d.ts.map +1 -0
  81. package/dist/Toast/ToastStatic.d.ts +18 -0
  82. package/dist/Toast/ToastStatic.d.ts.map +1 -0
  83. package/dist/Toast/index.d.ts +6 -0
  84. package/dist/Toast/index.d.ts.map +1 -0
  85. package/dist/Toast/toastManager.d.ts +28 -0
  86. package/dist/Toast/toastManager.d.ts.map +1 -0
  87. package/dist/Toast/useToast.d.ts +17 -0
  88. package/dist/Toast/useToast.d.ts.map +1 -0
  89. package/dist/Tooltip/Tooltip.d.ts +14 -0
  90. package/dist/Tooltip/Tooltip.d.ts.map +1 -0
  91. package/dist/Tooltip/index.d.ts +3 -0
  92. package/dist/Tooltip/index.d.ts.map +1 -0
  93. package/dist/hooks/index.d.ts +5 -0
  94. package/dist/hooks/index.d.ts.map +1 -0
  95. package/dist/hooks/useDisclosure.d.ts +8 -0
  96. package/dist/hooks/useDisclosure.d.ts.map +1 -0
  97. package/dist/hooks/useOutsideClick.d.ts +8 -0
  98. package/dist/hooks/useOutsideClick.d.ts.map +1 -0
  99. package/dist/index.cjs +1097 -0
  100. package/dist/index.css +2339 -0
  101. package/dist/index.d.ts +59 -0
  102. package/dist/index.d.ts.map +1 -0
  103. package/dist/index.js +1056 -0
  104. package/package.json +72 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,1097 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var React = require('react');
5
+
6
+ const Button = ({ children, variant = "primary", size = "md", colorScheme = "", disabled = false, loading = false, leftIcon, rightIcon, onClick, className = "", style, ...props }) => {
7
+ const buttonClasses = [
8
+ "ui-button",
9
+ `ui-button--${variant}`,
10
+ `ui-button--${size}`,
11
+ `ui-button--${colorScheme}`,
12
+ loading && "ui-button--loading",
13
+ className,
14
+ ]
15
+ .filter(Boolean)
16
+ .join(" ");
17
+ const isDisabled = disabled || loading;
18
+ return (jsxRuntime.jsxs("button", { className: buttonClasses, disabled: isDisabled, onClick: onClick, style: style, ...props, children: [loading && (jsxRuntime.jsx("svg", { className: "ui-button__spinner", viewBox: "0 0 24 24", children: jsxRuntime.jsxs("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4", fill: "none", strokeDasharray: "31.416", strokeDashoffset: "31.416", children: [jsxRuntime.jsx("animate", { attributeName: "stroke-dasharray", dur: "2s", values: "0 31.416;15.708 15.708;0 31.416", repeatCount: "indefinite" }), jsxRuntime.jsx("animate", { attributeName: "stroke-dashoffset", dur: "2s", values: "0;-15.708;-31.416", repeatCount: "indefinite" })] }) })), !loading && leftIcon && (jsxRuntime.jsx("span", { className: "ui-button__left-icon", children: leftIcon })), jsxRuntime.jsx("span", { className: "ui-button__content", children: children }), !loading && rightIcon && (jsxRuntime.jsx("span", { className: "ui-button__right-icon", children: rightIcon }))] }));
19
+ };
20
+
21
+ const Loader = ({ width, height, isCentered = false, className = "", size = "md", variant = "spinner", }) => {
22
+ const loaderClasses = [
23
+ "ui-loader",
24
+ `ui-loader--${size}`,
25
+ `ui-loader--${variant}`,
26
+ isCentered && "ui-loader--centered",
27
+ className,
28
+ ]
29
+ .filter(Boolean)
30
+ .join(" ");
31
+ const getSize = () => {
32
+ if (width && height)
33
+ return { width, height };
34
+ const sizeMap = {
35
+ xs: { width: 16, height: 16 },
36
+ sm: { width: 24, height: 24 },
37
+ md: { width: 32, height: 32 },
38
+ lg: { width: 44, height: 44 },
39
+ };
40
+ return sizeMap[size];
41
+ };
42
+ const { width: finalWidth, height: finalHeight } = getSize();
43
+ const renderLoader = () => {
44
+ switch (variant) {
45
+ case "dots":
46
+ return (jsxRuntime.jsxs("div", { className: "ui-loader__dots", children: [jsxRuntime.jsx("div", { className: "ui-loader__dot" }), jsxRuntime.jsx("div", { className: "ui-loader__dot" }), jsxRuntime.jsx("div", { className: "ui-loader__dot" })] }));
47
+ case "pulse":
48
+ return (jsxRuntime.jsx("div", { className: "ui-loader__pulse", style: { width: finalWidth, height: finalHeight } }));
49
+ case "spinner":
50
+ default:
51
+ return (jsxRuntime.jsx("svg", { className: "ui-loader__spinner", width: finalWidth, height: finalHeight, viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsxRuntime.jsxs("circle", { cx: "12", cy: "12", r: "10", stroke: "#fbbf24", strokeWidth: "3", fill: "none", strokeDasharray: "31.416", strokeDashoffset: "31.416", children: [jsxRuntime.jsx("animate", { attributeName: "stroke-dasharray", dur: "1s", values: "0 31.416;15.708 15.708;0 31.416", repeatCount: "indefinite" }), jsxRuntime.jsx("animate", { attributeName: "stroke-dashoffset", dur: "1s", values: "0;-15.708;-31.416", repeatCount: "indefinite" })] }) }));
52
+ }
53
+ };
54
+ return jsxRuntime.jsx("div", { className: loaderClasses, children: renderLoader() });
55
+ };
56
+
57
+ const Radio = ({ id, name, value, checked = false, disabled = false, label, description, size = "md", colorScheme = "blue", onChange, className = "", }) => {
58
+ const radioId = id || `${name}-${value}`;
59
+ const radioClasses = [
60
+ "ui-radio",
61
+ `ui-radio--${size}`,
62
+ `ui-radio--${colorScheme}`,
63
+ disabled && "ui-radio--disabled",
64
+ className,
65
+ ]
66
+ .filter(Boolean)
67
+ .join(" ");
68
+ const handleChange = (event) => {
69
+ if (!disabled && onChange) {
70
+ onChange(event.target.value);
71
+ }
72
+ };
73
+ return (jsxRuntime.jsxs("label", { className: radioClasses, children: [jsxRuntime.jsx("input", { type: "radio", id: radioId, name: name, value: value, checked: checked, disabled: disabled, onChange: handleChange, className: "ui-radio__input" }), jsxRuntime.jsx("span", { className: "ui-radio__checkmark" }), (label || description) && (jsxRuntime.jsxs("div", { className: "ui-radio__content", children: [label && jsxRuntime.jsx("span", { className: "ui-radio__label", children: label }), description && (jsxRuntime.jsx("span", { className: "ui-radio__description", children: description }))] }))] }));
74
+ };
75
+ const RadioGroup = ({ name, value, options, disabled = false, size = "md", colorScheme = "blue", onChange, className = "", orientation = "vertical", }) => {
76
+ const groupClasses = [
77
+ "ui-radio-group",
78
+ `ui-radio-group--${orientation}`,
79
+ className,
80
+ ]
81
+ .filter(Boolean)
82
+ .join(" ");
83
+ return (jsxRuntime.jsx("div", { className: groupClasses, children: options.map((option, index) => (jsxRuntime.jsx(Radio, { name: name, value: option.value, checked: value === option.value, disabled: disabled || option.disabled, label: option.label, description: option.description, size: size, colorScheme: colorScheme, onChange: onChange }, `${name}-${option.value}-${index}`))) }));
84
+ };
85
+
86
+ const Text = ({ as = "p", size = "md", weight = "regular", color = "primary", align = "left", className = "", children, style, ...props }) => {
87
+ const Component = as;
88
+ const classes = [
89
+ "ui-text",
90
+ `ui-text--${size}`,
91
+ `ui-text--${weight}`,
92
+ `ui-text--${color}`,
93
+ `ui-text--align-${align}`,
94
+ className,
95
+ ]
96
+ .filter(Boolean)
97
+ .join(" ");
98
+ return (jsxRuntime.jsx(Component, { className: classes, style: style, ...props, children: children }));
99
+ };
100
+
101
+ const ModalOverlay = ({ onClick, className = "", }) => {
102
+ return (jsxRuntime.jsx("div", { className: `ui-modal-overlay ${className}`, onClick: onClick, "aria-hidden": "true" }));
103
+ };
104
+ const ModalContent = ({ children, className = "", size = "md", isCentered = true, }) => {
105
+ const contentClasses = [
106
+ "ui-modal-content",
107
+ `ui-modal-content--${size}`,
108
+ isCentered && "ui-modal-content--centered",
109
+ className,
110
+ ]
111
+ .filter(Boolean)
112
+ .join(" ");
113
+ return jsxRuntime.jsx("div", { className: contentClasses, children: children });
114
+ };
115
+ const ModalHeader = ({ children, className = "", }) => {
116
+ return jsxRuntime.jsx("div", { className: `ui-modal-header ${className}`, children: children });
117
+ };
118
+ const ModalBody = ({ children, className = "", }) => {
119
+ return jsxRuntime.jsx("div", { className: `ui-modal-body ${className}`, children: children });
120
+ };
121
+ const ModalFooter = ({ children, className = "", }) => {
122
+ return jsxRuntime.jsx("div", { className: `ui-modal-footer ${className}`, children: children });
123
+ };
124
+ const ModalCloseButton = ({ onClose, className = "", }) => {
125
+ return (jsxRuntime.jsx("button", { className: `ui-modal-close-button ${className}`, onClick: onClose, "aria-label": "Close modal", children: jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsxRuntime.jsx("path", { d: "M12 4L4 12M4 4L12 12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
126
+ };
127
+ const Modal = ({ isOpen, onClose, children, size = "md", closeOnOverlayClick = true, closeOnEsc = true, isCentered = true, }) => {
128
+ const modalRef = React.useRef(null);
129
+ React.useEffect(() => {
130
+ if (!isOpen)
131
+ return;
132
+ const handleEsc = (e) => {
133
+ if (closeOnEsc && e.key === "Escape") {
134
+ onClose();
135
+ }
136
+ };
137
+ document.addEventListener("keydown", handleEsc);
138
+ document.body.style.overflow = "hidden";
139
+ return () => {
140
+ document.removeEventListener("keydown", handleEsc);
141
+ document.body.style.overflow = "";
142
+ };
143
+ }, [isOpen, closeOnEsc, onClose]);
144
+ if (!isOpen)
145
+ return null;
146
+ const handleOverlayClick = (e) => {
147
+ if (closeOnOverlayClick && e.target === e.currentTarget) {
148
+ onClose();
149
+ }
150
+ };
151
+ return (jsxRuntime.jsxs("div", { className: "ui-modal", ref: modalRef, children: [jsxRuntime.jsx(ModalOverlay, { onClick: handleOverlayClick }), jsxRuntime.jsx(ModalContent, { size: size, isCentered: isCentered, children: children })] }));
152
+ };
153
+
154
+ const normalizeValue$2 = (value) => {
155
+ if (value === undefined)
156
+ return undefined;
157
+ if (typeof value === "number")
158
+ return `${value}px`;
159
+ return value;
160
+ };
161
+ const Box = ({ children, as = "div", className = "", position, top, right, bottom, left, zIndex, display, width, height, minWidth, maxWidth, minHeight, maxHeight, padding, paddingTop, paddingRight, paddingBottom, paddingLeft, margin, marginTop, marginRight, marginBottom, marginLeft, overflow, overflowX, overflowY, color, backgroundColor, bg, opacity, border, borderWidth, borderStyle, borderColor, borderRadius, boxShadow, shadow, fontSize, fontWeight, lineHeight, textAlign, textDecoration, style, ...props }) => {
162
+ const Component = as;
163
+ const boxClasses = ["ui-box", className].filter(Boolean).join(" ");
164
+ const computedStyle = {
165
+ ...(position && { position }),
166
+ ...(top !== undefined && { top: normalizeValue$2(top) }),
167
+ ...(right !== undefined && { right: normalizeValue$2(right) }),
168
+ ...(bottom !== undefined && { bottom: normalizeValue$2(bottom) }),
169
+ ...(left !== undefined && { left: normalizeValue$2(left) }),
170
+ ...(zIndex !== undefined && { zIndex }),
171
+ ...(display && { display }),
172
+ ...(width !== undefined && { width: normalizeValue$2(width) }),
173
+ ...(height !== undefined && { height: normalizeValue$2(height) }),
174
+ ...(minWidth !== undefined && { minWidth: normalizeValue$2(minWidth) }),
175
+ ...(maxWidth !== undefined && { maxWidth: normalizeValue$2(maxWidth) }),
176
+ ...(minHeight !== undefined && { minHeight: normalizeValue$2(minHeight) }),
177
+ ...(maxHeight !== undefined && { maxHeight: normalizeValue$2(maxHeight) }),
178
+ ...(padding !== undefined && { padding: normalizeValue$2(padding) }),
179
+ ...(paddingTop !== undefined && { paddingTop: normalizeValue$2(paddingTop) }),
180
+ ...(paddingRight !== undefined && { paddingRight: normalizeValue$2(paddingRight) }),
181
+ ...(paddingBottom !== undefined && { paddingBottom: normalizeValue$2(paddingBottom) }),
182
+ ...(paddingLeft !== undefined && { paddingLeft: normalizeValue$2(paddingLeft) }),
183
+ ...(margin !== undefined && { margin: normalizeValue$2(margin) }),
184
+ ...(marginTop !== undefined && { marginTop: normalizeValue$2(marginTop) }),
185
+ ...(marginRight !== undefined && { marginRight: normalizeValue$2(marginRight) }),
186
+ ...(marginBottom !== undefined && { marginBottom: normalizeValue$2(marginBottom) }),
187
+ ...(marginLeft !== undefined && { marginLeft: normalizeValue$2(marginLeft) }),
188
+ ...(overflow && { overflow }),
189
+ ...(overflowX && { overflowX }),
190
+ ...(overflowY && { overflowY }),
191
+ ...(color && { color }),
192
+ ...(backgroundColor && { backgroundColor }),
193
+ ...(bg && { backgroundColor: bg }),
194
+ ...(opacity !== undefined && { opacity }),
195
+ ...(border && { border }),
196
+ ...(borderWidth !== undefined && { borderWidth: normalizeValue$2(borderWidth) }),
197
+ ...(borderStyle && { borderStyle }),
198
+ ...(borderColor && { borderColor }),
199
+ ...(borderRadius !== undefined && { borderRadius: normalizeValue$2(borderRadius) }),
200
+ ...(boxShadow && { boxShadow }),
201
+ ...(shadow && { boxShadow: shadow }),
202
+ ...(fontSize !== undefined && { fontSize: normalizeValue$2(fontSize) }),
203
+ ...(fontWeight !== undefined && { fontWeight }),
204
+ ...(lineHeight !== undefined && { lineHeight: normalizeValue$2(lineHeight) }),
205
+ ...(textAlign && { textAlign }),
206
+ ...(textDecoration && { textDecoration }),
207
+ ...style,
208
+ };
209
+ return (jsxRuntime.jsx(Component, { className: boxClasses, style: computedStyle, ...props, children: children }));
210
+ };
211
+
212
+ const normalizeValue$1 = (value) => {
213
+ if (value === undefined)
214
+ return undefined;
215
+ if (typeof value === "number")
216
+ return `${value}px`;
217
+ return value;
218
+ };
219
+ const mapAlignToFlex = (align) => {
220
+ if (!align)
221
+ return undefined;
222
+ const map = {
223
+ start: "flex-start",
224
+ end: "flex-end",
225
+ center: "center",
226
+ stretch: "stretch",
227
+ baseline: "baseline",
228
+ };
229
+ return map[align];
230
+ };
231
+ const mapJustifyToFlex = (justify) => {
232
+ if (!justify)
233
+ return undefined;
234
+ const map = {
235
+ start: "flex-start",
236
+ end: "flex-end",
237
+ center: "center",
238
+ between: "space-between",
239
+ around: "space-around",
240
+ evenly: "space-evenly",
241
+ };
242
+ return map[justify];
243
+ };
244
+ const Flex = ({ children, direction = "row", align, alignItems, justify, justifyContent, wrap = "nowrap", gap, className = "", position, top, right, bottom, left, zIndex, width, height, minWidth, maxWidth, minHeight, maxHeight, padding, paddingTop, paddingRight, paddingBottom, paddingLeft, margin, marginTop, marginRight, marginBottom, marginLeft, overflow, overflowX, overflowY, color, backgroundColor, bg, opacity, border, borderWidth, borderStyle, borderColor, borderRadius, boxShadow, shadow, fontSize, fontWeight, lineHeight, textAlign, textDecoration, style, ...props }) => {
245
+ const flexClasses = [
246
+ "ui-flex",
247
+ `ui-flex--${direction}`,
248
+ align && `ui-flex--align-${align}`,
249
+ justify && `ui-flex--justify-${justify}`,
250
+ `ui-flex--wrap-${wrap}`,
251
+ className,
252
+ ]
253
+ .filter(Boolean)
254
+ .join(" ");
255
+ const flexStyle = {
256
+ ...(position && { position }),
257
+ ...(top !== undefined && { top: normalizeValue$1(top) }),
258
+ ...(right !== undefined && { right: normalizeValue$1(right) }),
259
+ ...(bottom !== undefined && { bottom: normalizeValue$1(bottom) }),
260
+ ...(left !== undefined && { left: normalizeValue$1(left) }),
261
+ ...(zIndex !== undefined && { zIndex }),
262
+ ...(width !== undefined && { width: normalizeValue$1(width) }),
263
+ ...(height !== undefined && { height: normalizeValue$1(height) }),
264
+ ...(minWidth !== undefined && { minWidth: normalizeValue$1(minWidth) }),
265
+ ...(maxWidth !== undefined && { maxWidth: normalizeValue$1(maxWidth) }),
266
+ ...(minHeight !== undefined && { minHeight: normalizeValue$1(minHeight) }),
267
+ ...(maxHeight !== undefined && { maxHeight: normalizeValue$1(maxHeight) }),
268
+ ...(padding !== undefined && { padding: normalizeValue$1(padding) }),
269
+ ...(paddingTop !== undefined && { paddingTop: normalizeValue$1(paddingTop) }),
270
+ ...(paddingRight !== undefined && {
271
+ paddingRight: normalizeValue$1(paddingRight),
272
+ }),
273
+ ...(paddingBottom !== undefined && {
274
+ paddingBottom: normalizeValue$1(paddingBottom),
275
+ }),
276
+ ...(paddingLeft !== undefined && {
277
+ paddingLeft: normalizeValue$1(paddingLeft),
278
+ }),
279
+ ...(margin !== undefined && { margin: normalizeValue$1(margin) }),
280
+ ...(marginTop !== undefined && { marginTop: normalizeValue$1(marginTop) }),
281
+ ...(marginRight !== undefined && {
282
+ marginRight: normalizeValue$1(marginRight),
283
+ }),
284
+ ...(marginBottom !== undefined && {
285
+ marginBottom: normalizeValue$1(marginBottom),
286
+ }),
287
+ ...(marginLeft !== undefined && { marginLeft: normalizeValue$1(marginLeft) }),
288
+ ...(overflow && { overflow }),
289
+ ...(overflowX && { overflowX }),
290
+ ...(overflowY && { overflowY }),
291
+ ...(color && { color }),
292
+ ...(backgroundColor && { backgroundColor }),
293
+ ...(bg && { backgroundColor: bg }),
294
+ ...(opacity !== undefined && { opacity }),
295
+ ...(border && { border }),
296
+ ...(borderWidth !== undefined && {
297
+ borderWidth: normalizeValue$1(borderWidth),
298
+ }),
299
+ ...(borderStyle && { borderStyle }),
300
+ ...(borderColor && { borderColor }),
301
+ ...(borderRadius !== undefined && {
302
+ borderRadius: normalizeValue$1(borderRadius),
303
+ }),
304
+ ...(boxShadow && { boxShadow }),
305
+ ...(shadow && { boxShadow: shadow }),
306
+ ...(fontSize !== undefined && { fontSize: normalizeValue$1(fontSize) }),
307
+ ...(fontWeight !== undefined && { fontWeight }),
308
+ ...(lineHeight !== undefined && { lineHeight: normalizeValue$1(lineHeight) }),
309
+ ...(textAlign && { textAlign }),
310
+ ...(textDecoration && { textDecoration }),
311
+ // Flexbox specific
312
+ ...(alignItems && { alignItems }),
313
+ ...(align && !alignItems && { alignItems: mapAlignToFlex(align) }),
314
+ ...(justifyContent && { justifyContent }),
315
+ ...(justify &&
316
+ !justifyContent && { justifyContent: mapJustifyToFlex(justify) }),
317
+ ...(gap !== undefined && {
318
+ gap: typeof gap === "number" ? `${gap}px` : gap,
319
+ }),
320
+ ...style,
321
+ };
322
+ return (jsxRuntime.jsx("div", { className: flexClasses, style: flexStyle, ...props, children: children }));
323
+ };
324
+
325
+ const FormControlContext = React.createContext({});
326
+ const useFormControlContext = () => React.useContext(FormControlContext);
327
+ const FormControl = ({ children, isInvalid = false, isRequired = false, isDisabled = false, id, className = "", }) => {
328
+ const contextValue = {
329
+ isInvalid,
330
+ isRequired,
331
+ isDisabled,
332
+ id,
333
+ };
334
+ return (jsxRuntime.jsx(FormControlContext.Provider, { value: contextValue, children: jsxRuntime.jsx("div", { className: `ui-form-control ${className}`, children: children }) }));
335
+ };
336
+
337
+ const FormLabel = ({ children, htmlFor, className = "", style, }) => {
338
+ const { isRequired, id } = useFormControlContext();
339
+ const labelId = id ? `${id}-label` : undefined;
340
+ const labelFor = htmlFor || id;
341
+ return (jsxRuntime.jsxs("label", { htmlFor: labelFor, id: labelId, className: `ui-form-label ${className}`, style: style, children: [children, isRequired && jsxRuntime.jsx("span", { className: "ui-form-label__required", children: "*" })] }));
342
+ };
343
+
344
+ const FormErrorMessage = ({ children, className = "", style, }) => {
345
+ const { isInvalid, id } = useFormControlContext();
346
+ const errorId = id ? `${id}-error` : undefined;
347
+ if (!isInvalid)
348
+ return null;
349
+ return (jsxRuntime.jsx("div", { id: errorId, className: `ui-form-error-message ${className}`, role: "alert", style: style, children: children }));
350
+ };
351
+
352
+ const Input = ({ size = "md", variant = "outline", isInvalid, isDisabled, isReadOnly, className = "", style, id, ...props }) => {
353
+ const formControl = useFormControlContext();
354
+ const invalid = isInvalid ?? formControl.isInvalid ?? false;
355
+ const disabled = isDisabled ?? formControl.isDisabled ?? false;
356
+ const inputId = id || formControl.id;
357
+ const inputClasses = [
358
+ "ui-input",
359
+ `ui-input--${size}`,
360
+ `ui-input--${variant}`,
361
+ invalid && "ui-input--invalid",
362
+ disabled && "ui-input--disabled",
363
+ isReadOnly && "ui-input--readonly",
364
+ className,
365
+ ]
366
+ .filter(Boolean)
367
+ .join(" ");
368
+ return (jsxRuntime.jsx("input", { id: inputId, className: inputClasses, disabled: disabled, readOnly: isReadOnly, "aria-invalid": invalid, "aria-describedby": invalid && formControl.id ? `${formControl.id}-error` : undefined, style: style, ...props }));
369
+ };
370
+
371
+ const Textarea = ({ size = "md", variant = "outline", isInvalid, isDisabled, isReadOnly, resize = "vertical", className = "", style, id, ...props }) => {
372
+ const formControl = useFormControlContext();
373
+ const invalid = isInvalid ?? formControl.isInvalid ?? false;
374
+ const disabled = isDisabled ?? formControl.isDisabled ?? false;
375
+ const textareaId = id || formControl.id;
376
+ const textareaClasses = [
377
+ "ui-textarea",
378
+ `ui-textarea--${size}`,
379
+ `ui-textarea--${variant}`,
380
+ `ui-textarea--resize-${resize}`,
381
+ invalid && "ui-textarea--invalid",
382
+ disabled && "ui-textarea--disabled",
383
+ isReadOnly && "ui-textarea--readonly",
384
+ className,
385
+ ]
386
+ .filter(Boolean)
387
+ .join(" ");
388
+ return (jsxRuntime.jsx("textarea", { id: textareaId, className: textareaClasses, disabled: disabled, readOnly: isReadOnly, "aria-invalid": invalid, "aria-describedby": invalid && formControl.id ? `${formControl.id}-error` : undefined, style: style, ...props }));
389
+ };
390
+
391
+ const normalizeValue = (value) => {
392
+ if (value === undefined)
393
+ return undefined;
394
+ if (typeof value === "number")
395
+ return `${value}px`;
396
+ return value;
397
+ };
398
+ const Grid = ({ children, templateColumns, templateRows, gap, columnGap, rowGap, autoFlow, autoColumns, autoRows, className = "", position, top, right, bottom, left, zIndex, width, height, minWidth, maxWidth, minHeight, maxHeight, padding, paddingTop, paddingRight, paddingBottom, paddingLeft, margin, marginTop, marginRight, marginBottom, marginLeft, backgroundColor, bg, borderRadius, style, ...props }) => {
399
+ const gridClasses = ["ui-grid", className].filter(Boolean).join(" ");
400
+ const gridStyle = {
401
+ ...(position && { position }),
402
+ ...(top !== undefined && { top: normalizeValue(top) }),
403
+ ...(right !== undefined && { right: normalizeValue(right) }),
404
+ ...(bottom !== undefined && { bottom: normalizeValue(bottom) }),
405
+ ...(left !== undefined && { left: normalizeValue(left) }),
406
+ ...(zIndex !== undefined && { zIndex }),
407
+ ...(width !== undefined && { width: normalizeValue(width) }),
408
+ ...(height !== undefined && { height: normalizeValue(height) }),
409
+ ...(minWidth !== undefined && { minWidth: normalizeValue(minWidth) }),
410
+ ...(maxWidth !== undefined && { maxWidth: normalizeValue(maxWidth) }),
411
+ ...(minHeight !== undefined && { minHeight: normalizeValue(minHeight) }),
412
+ ...(maxHeight !== undefined && { maxHeight: normalizeValue(maxHeight) }),
413
+ ...(padding !== undefined && { padding: normalizeValue(padding) }),
414
+ ...(paddingTop !== undefined && { paddingTop: normalizeValue(paddingTop) }),
415
+ ...(paddingRight !== undefined && {
416
+ paddingRight: normalizeValue(paddingRight),
417
+ }),
418
+ ...(paddingBottom !== undefined && {
419
+ paddingBottom: normalizeValue(paddingBottom),
420
+ }),
421
+ ...(paddingLeft !== undefined && {
422
+ paddingLeft: normalizeValue(paddingLeft),
423
+ }),
424
+ ...(margin !== undefined && { margin: normalizeValue(margin) }),
425
+ ...(marginTop !== undefined && { marginTop: normalizeValue(marginTop) }),
426
+ ...(marginRight !== undefined && { marginRight: normalizeValue(marginRight) }),
427
+ ...(marginBottom !== undefined && {
428
+ marginBottom: normalizeValue(marginBottom),
429
+ }),
430
+ ...(marginLeft !== undefined && { marginLeft: normalizeValue(marginLeft) }),
431
+ ...(backgroundColor && { backgroundColor }),
432
+ ...(bg && { backgroundColor: bg }),
433
+ ...(borderRadius !== undefined && {
434
+ borderRadius: normalizeValue(borderRadius),
435
+ }),
436
+ // Grid specific
437
+ ...(templateColumns && { gridTemplateColumns: templateColumns }),
438
+ ...(templateRows && { gridTemplateRows: templateRows }),
439
+ ...(gap !== undefined && {
440
+ gap: typeof gap === "number" ? `${gap}px` : gap,
441
+ }),
442
+ ...(columnGap !== undefined && {
443
+ columnGap: typeof columnGap === "number" ? `${columnGap}px` : columnGap,
444
+ }),
445
+ ...(rowGap !== undefined && {
446
+ rowGap: typeof rowGap === "number" ? `${rowGap}px` : rowGap,
447
+ }),
448
+ ...(autoFlow && { gridAutoFlow: autoFlow }),
449
+ ...(autoColumns && { gridAutoColumns: autoColumns }),
450
+ ...(autoRows && { gridAutoRows: autoRows }),
451
+ ...style,
452
+ };
453
+ return (jsxRuntime.jsx("div", { className: gridClasses, style: gridStyle, ...props, children: children }));
454
+ };
455
+
456
+ const Link = ({ children, href, isExternal = false, variant = "link", color = "primary", className = "", style, ...props }) => {
457
+ const linkClasses = [
458
+ "ui-link",
459
+ `ui-link--${variant}`,
460
+ `ui-link--${color}`,
461
+ className,
462
+ ]
463
+ .filter(Boolean)
464
+ .join(" ");
465
+ return (jsxRuntime.jsx("a", { href: href, className: linkClasses, target: isExternal ? "_blank" : undefined, rel: isExternal ? "noopener noreferrer" : undefined, style: style, ...props, children: children }));
466
+ };
467
+
468
+ const IconButton = ({ icon, size = "md", variant = "ghost", colorScheme, isRound = false, isDisabled = false, className = "", style, ...props }) => {
469
+ const iconButtonClasses = [
470
+ "ui-icon-button",
471
+ `ui-icon-button--${size}`,
472
+ `ui-icon-button--${variant}`,
473
+ colorScheme && `ui-icon-button--${colorScheme}`,
474
+ isRound && "ui-icon-button--round",
475
+ isDisabled && "ui-icon-button--disabled",
476
+ className,
477
+ ]
478
+ .filter(Boolean)
479
+ .join(" ");
480
+ return (jsxRuntime.jsx("button", { className: iconButtonClasses, disabled: isDisabled, style: style, ...props, children: icon }));
481
+ };
482
+
483
+ const CircularProgress = ({ value = 0, min = 0, max = 100, size = 48, thickness = 4, color = "var(--accent-primary, #bb00ed)", trackColor = "var(--bg-secondary, #f3f4f6)", isIndeterminate = false, className = "", style, children, }) => {
484
+ const normalizedSize = typeof size === "number" ? `${size}px` : size;
485
+ const radius = (parseFloat(normalizedSize) - thickness) / 2;
486
+ const circumference = 2 * Math.PI * radius;
487
+ const normalizedValue = Math.min(Math.max((value - min) / (max - min), 0), 1);
488
+ const strokeDasharray = isIndeterminate ? undefined : circumference;
489
+ const strokeDashoffset = isIndeterminate
490
+ ? undefined
491
+ : circumference * (1 - normalizedValue);
492
+ return (jsxRuntime.jsxs("div", { className: `ui-circular-progress ${className}`, style: { width: normalizedSize, height: normalizedSize, ...style }, role: "progressbar", "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": isIndeterminate ? undefined : value, children: [jsxRuntime.jsxs("svg", { className: "ui-circular-progress__svg", width: normalizedSize, height: normalizedSize, viewBox: `0 0 ${parseFloat(normalizedSize)} ${parseFloat(normalizedSize)}`, children: [jsxRuntime.jsx("circle", { className: "ui-circular-progress__track", cx: parseFloat(normalizedSize) / 2, cy: parseFloat(normalizedSize) / 2, r: radius, fill: "none", stroke: trackColor, strokeWidth: thickness }), jsxRuntime.jsx("circle", { className: `ui-circular-progress__indicator ${isIndeterminate
493
+ ? "ui-circular-progress__indicator--indeterminate"
494
+ : ""}`, cx: parseFloat(normalizedSize) / 2, cy: parseFloat(normalizedSize) / 2, r: radius, fill: "none", stroke: color, strokeWidth: thickness, strokeDasharray: strokeDasharray, strokeDashoffset: strokeDashoffset, strokeLinecap: "round", transform: `rotate(-90 ${parseFloat(normalizedSize) / 2} ${parseFloat(normalizedSize) / 2})` })] }), children && (jsxRuntime.jsx("div", { className: "ui-circular-progress__label", children: children }))] }));
495
+ };
496
+ const CircularProgressLabel = ({ children, className = "", style, }) => {
497
+ return (jsxRuntime.jsx("div", { className: `ui-circular-progress-label ${className}`, style: style, children: children }));
498
+ };
499
+
500
+ const useOutsideClick = ({ handler, refs, enabled = true, }) => {
501
+ React.useEffect(() => {
502
+ if (!enabled)
503
+ return;
504
+ const handleClickOutside = (event) => {
505
+ const target = event.target;
506
+ const isOutside = refs.every((ref) => {
507
+ return ref.current && !ref.current.contains(target);
508
+ });
509
+ if (isOutside) {
510
+ handler(event);
511
+ }
512
+ };
513
+ document.addEventListener("mousedown", handleClickOutside);
514
+ document.addEventListener("touchstart", handleClickOutside);
515
+ return () => {
516
+ document.removeEventListener("mousedown", handleClickOutside);
517
+ document.removeEventListener("touchstart", handleClickOutside);
518
+ };
519
+ }, [handler, refs, enabled]);
520
+ };
521
+
522
+ const Tooltip = ({ children, label, placement = "top", isOpen: controlledIsOpen, defaultIsOpen = false, closeOnClick = false, className = "", style, }) => {
523
+ const [internalIsOpen, setInternalIsOpen] = React.useState(defaultIsOpen);
524
+ const tooltipRef = React.useRef(null);
525
+ const triggerRef = React.useRef(null);
526
+ const isControlled = controlledIsOpen !== undefined;
527
+ const isOpen = isControlled ? controlledIsOpen : internalIsOpen;
528
+ useOutsideClick({
529
+ handler: () => {
530
+ if (!isControlled) {
531
+ setInternalIsOpen(false);
532
+ }
533
+ },
534
+ refs: [tooltipRef],
535
+ enabled: isOpen && !isControlled,
536
+ });
537
+ const handleMouseEnter = () => {
538
+ if (!isControlled) {
539
+ setInternalIsOpen(true);
540
+ }
541
+ };
542
+ const handleMouseLeave = () => {
543
+ if (!isControlled && !closeOnClick) {
544
+ setInternalIsOpen(false);
545
+ }
546
+ };
547
+ const handleClick = () => {
548
+ if (closeOnClick && !isControlled) {
549
+ setInternalIsOpen((prev) => !prev);
550
+ }
551
+ };
552
+ const clonedChild = React.cloneElement(children, {
553
+ ref: triggerRef,
554
+ onMouseEnter: handleMouseEnter,
555
+ onMouseLeave: handleMouseLeave,
556
+ onClick: handleClick,
557
+ });
558
+ return (jsxRuntime.jsxs("div", { className: `ui-tooltip-wrapper ${className}`, style: style, children: [clonedChild, isOpen && (jsxRuntime.jsx("div", { ref: tooltipRef, className: `ui-tooltip ui-tooltip--${placement}`, role: "tooltip", children: label }))] }));
559
+ };
560
+
561
+ const PopoverContent = ({ children, className = "", }) => {
562
+ return jsxRuntime.jsx("div", { className: `ui-popover__content ${className}`, children: children });
563
+ };
564
+ const PopoverHeader = ({ children, className = "", }) => {
565
+ return jsxRuntime.jsx("div", { className: `ui-popover__header ${className}`, children: children });
566
+ };
567
+ const PopoverBody = ({ children, className = "", }) => {
568
+ return jsxRuntime.jsx("div", { className: `ui-popover__body ${className}`, children: children });
569
+ };
570
+ const PopoverFooter = ({ children, className = "", }) => {
571
+ return jsxRuntime.jsx("div", { className: `ui-popover__footer ${className}`, children: children });
572
+ };
573
+ const PopoverCloseButton = ({ onClose, className = "", }) => {
574
+ return (jsxRuntime.jsx("button", { className: `ui-popover__close ${className}`, onClick: onClose, "aria-label": "Close popover", children: jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsxRuntime.jsx("path", { d: "M13 1L1 13M1 1L13 13", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
575
+ };
576
+ const Popover = ({ children, content, placement = "bottom", isOpen: controlledIsOpen, defaultIsOpen = false, onOpenChange, trigger = "click", closeOnBlur = true, showArrow = true, className = "", style, }) => {
577
+ const [internalIsOpen, setInternalIsOpen] = React.useState(defaultIsOpen);
578
+ const popoverRef = React.useRef(null);
579
+ const triggerRef = React.useRef(null);
580
+ const isControlled = controlledIsOpen !== undefined;
581
+ const isOpen = isControlled ? controlledIsOpen : internalIsOpen;
582
+ const handleOpenChange = React.useCallback((open) => {
583
+ if (!isControlled) {
584
+ setInternalIsOpen(open);
585
+ }
586
+ onOpenChange?.(open);
587
+ }, [isControlled, onOpenChange]);
588
+ // Handle outside click
589
+ React.useEffect(() => {
590
+ if (!isOpen || !closeOnBlur)
591
+ return;
592
+ const handleClickOutside = (event) => {
593
+ const target = event.target;
594
+ // Check if refs are available
595
+ if (!popoverRef.current || !triggerRef.current) {
596
+ return;
597
+ }
598
+ // Check if click is inside popover or trigger
599
+ const clickedInsidePopover = popoverRef.current.contains(target);
600
+ const clickedInsideTrigger = triggerRef.current.contains(target);
601
+ // Close if clicked outside both
602
+ if (!clickedInsidePopover && !clickedInsideTrigger) {
603
+ handleOpenChange(false);
604
+ }
605
+ };
606
+ // Use click event in bubble phase (not capture) so button clicks fire first
607
+ document.addEventListener("click", handleClickOutside, false);
608
+ document.addEventListener("touchend", handleClickOutside, false);
609
+ return () => {
610
+ document.removeEventListener("click", handleClickOutside, false);
611
+ document.removeEventListener("touchend", handleClickOutside, false);
612
+ };
613
+ }, [isOpen, closeOnBlur, handleOpenChange]);
614
+ // Handle click
615
+ const handleClick = () => {
616
+ if (trigger === "click") {
617
+ handleOpenChange(!isOpen);
618
+ }
619
+ };
620
+ // Handle hover
621
+ const handleMouseEnter = () => {
622
+ if (trigger === "hover") {
623
+ handleOpenChange(true);
624
+ }
625
+ };
626
+ const handleMouseLeave = () => {
627
+ if (trigger === "hover") {
628
+ handleOpenChange(false);
629
+ }
630
+ };
631
+ // Clone trigger element
632
+ const triggerElement = React.cloneElement(children, {
633
+ ref: (node) => {
634
+ triggerRef.current = node;
635
+ const originalRef = children.ref;
636
+ if (typeof originalRef === "function") {
637
+ originalRef(node);
638
+ }
639
+ else if (originalRef) {
640
+ try {
641
+ originalRef.current = node;
642
+ }
643
+ catch {
644
+ // Ignore read-only refs
645
+ }
646
+ }
647
+ },
648
+ onClick: trigger === "click" ? handleClick : undefined,
649
+ onMouseEnter: trigger === "hover" ? handleMouseEnter : undefined,
650
+ onMouseLeave: trigger === "hover" ? handleMouseLeave : undefined,
651
+ });
652
+ return (jsxRuntime.jsxs("div", { className: `ui-popover-wrapper ${className}`, style: style, children: [triggerElement, isOpen && (jsxRuntime.jsx("div", { ref: popoverRef, className: `ui-popover ui-popover--${placement} ${showArrow ? "ui-popover--with-arrow" : ""}`, role: "dialog", "aria-modal": "false", onClick: (e) => {
653
+ // Stop propagation to prevent outside click handler from firing
654
+ e.stopPropagation();
655
+ }, onMouseDown: (e) => {
656
+ // Stop propagation to prevent outside click handler from firing
657
+ e.stopPropagation();
658
+ }, children: content }))] }));
659
+ };
660
+
661
+ const Toast = ({ id, title, description, variant = "info", duration = 5000, isClosable = true, onClose, className = "", style, }) => {
662
+ const [isVisible, setIsVisible] = React.useState(false);
663
+ const [isExiting, setIsExiting] = React.useState(false);
664
+ React.useEffect(() => {
665
+ // Trigger entrance animation
666
+ setTimeout(() => setIsVisible(true), 10);
667
+ // Auto-close after duration
668
+ if (duration > 0) {
669
+ const timer = setTimeout(() => {
670
+ handleClose();
671
+ }, duration);
672
+ return () => clearTimeout(timer);
673
+ }
674
+ }, [duration]);
675
+ const handleClose = () => {
676
+ setIsExiting(true);
677
+ setTimeout(() => {
678
+ onClose?.(id);
679
+ }, 300); // Match CSS transition duration
680
+ };
681
+ const toastClasses = [
682
+ "ui-toast",
683
+ `ui-toast--${variant}`,
684
+ isVisible && !isExiting ? "ui-toast--visible" : "",
685
+ isExiting ? "ui-toast--exiting" : "",
686
+ className,
687
+ ]
688
+ .filter(Boolean)
689
+ .join(" ");
690
+ return (jsxRuntime.jsxs("div", { className: toastClasses, style: style, children: [jsxRuntime.jsxs("div", { className: "ui-toast__content", children: [title && jsxRuntime.jsx("div", { className: "ui-toast__title", children: title }), description && (jsxRuntime.jsx("div", { className: "ui-toast__description", children: description }))] }), isClosable && (jsxRuntime.jsx("button", { className: "ui-toast__close", onClick: handleClose, "aria-label": "Close toast", children: "\u00D7" }))] }));
691
+ };
692
+ const ToastContainer = ({ toasts, position = "top-right", onClose, className = "", style, }) => {
693
+ const containerClasses = [
694
+ "ui-toast-container",
695
+ `ui-toast-container--${position}`,
696
+ className,
697
+ ]
698
+ .filter(Boolean)
699
+ .join(" ");
700
+ return (jsxRuntime.jsx("div", { className: containerClasses, style: style, children: toasts.map((toast) => (jsxRuntime.jsx(Toast, { ...toast, onClose: onClose }, toast.id))) }));
701
+ };
702
+
703
+ class ToastManager {
704
+ constructor() {
705
+ this.toasts = [];
706
+ this.listeners = new Set();
707
+ this.defaultPosition = "top-center";
708
+ }
709
+ subscribe(listener) {
710
+ this.listeners.add(listener);
711
+ return () => {
712
+ this.listeners.delete(listener);
713
+ };
714
+ }
715
+ notify() {
716
+ this.listeners.forEach((listener) => listener([...this.toasts]));
717
+ }
718
+ getToasts() {
719
+ return [...this.toasts];
720
+ }
721
+ addToast(message, variant, options = {}) {
722
+ const id = `toast-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
723
+ // Support both 'duration' and 'hideAfter' options
724
+ const duration = options.hideAfter !== undefined
725
+ ? options.hideAfter
726
+ : options.duration ?? 5000;
727
+ // If title is provided, use it; otherwise use message as title
728
+ // If title is provided, use description from options; otherwise no description
729
+ const title = options.title || message;
730
+ const description = options.title ? options.description : undefined;
731
+ const toast = {
732
+ id,
733
+ title,
734
+ description,
735
+ variant,
736
+ duration,
737
+ isClosable: options.isClosable ?? true,
738
+ position: options.position || this.defaultPosition,
739
+ };
740
+ this.toasts.push(toast);
741
+ this.notify();
742
+ return id;
743
+ }
744
+ success(message, options) {
745
+ return this.addToast(message, "success", options);
746
+ }
747
+ error(message, options) {
748
+ return this.addToast(message, "error", options);
749
+ }
750
+ warning(message, options) {
751
+ return this.addToast(message, "warning", options);
752
+ }
753
+ info(message, options) {
754
+ return this.addToast(message, "info", options);
755
+ }
756
+ close(id) {
757
+ this.toasts = this.toasts.filter((toast) => toast.id !== id);
758
+ this.notify();
759
+ }
760
+ closeAll() {
761
+ this.toasts = [];
762
+ this.notify();
763
+ }
764
+ }
765
+ const toastManager = new ToastManager();
766
+
767
+ const ToastStatic = {
768
+ success: (messageOrOptions, options) => {
769
+ if (typeof messageOrOptions === "string") {
770
+ return toastManager.success(messageOrOptions, options);
771
+ }
772
+ else {
773
+ return toastManager.success("", messageOrOptions);
774
+ }
775
+ },
776
+ error: (messageOrOptions, options) => {
777
+ if (typeof messageOrOptions === "string") {
778
+ return toastManager.error(messageOrOptions, options);
779
+ }
780
+ else {
781
+ return toastManager.error("", messageOrOptions);
782
+ }
783
+ },
784
+ warning: (messageOrOptions, options) => {
785
+ if (typeof messageOrOptions === "string") {
786
+ return toastManager.warning(messageOrOptions, options);
787
+ }
788
+ else {
789
+ return toastManager.warning("", messageOrOptions);
790
+ }
791
+ },
792
+ info: (messageOrOptions, options) => {
793
+ if (typeof messageOrOptions === "string") {
794
+ return toastManager.info(messageOrOptions, options);
795
+ }
796
+ else {
797
+ return toastManager.info("", messageOrOptions);
798
+ }
799
+ },
800
+ close: (id) => {
801
+ toastManager.close(id);
802
+ },
803
+ closeAll: () => {
804
+ toastManager.closeAll();
805
+ },
806
+ };
807
+
808
+ const ToastContainerGlobal = () => {
809
+ const [toasts, setToasts] = React.useState([]);
810
+ React.useEffect(() => {
811
+ const unsubscribe = toastManager.subscribe((newToasts) => {
812
+ setToasts(newToasts);
813
+ });
814
+ // Set initial toasts
815
+ setToasts(toastManager.getToasts());
816
+ return unsubscribe;
817
+ }, []);
818
+ const handleClose = (id) => {
819
+ toastManager.close(id);
820
+ };
821
+ // Group toasts by position
822
+ const toastsByPosition = React.useMemo(() => {
823
+ const grouped = {
824
+ "top-left": [],
825
+ "top-right": [],
826
+ "top-center": [],
827
+ "bottom-left": [],
828
+ "bottom-right": [],
829
+ "bottom-center": [],
830
+ };
831
+ toasts.forEach((toast) => {
832
+ const position = toast.position || "top-right";
833
+ if (grouped[position]) {
834
+ grouped[position].push(toast);
835
+ }
836
+ });
837
+ return grouped;
838
+ }, [toasts]);
839
+ // Get all positions that have toasts
840
+ const positionsWithToasts = React.useMemo(() => {
841
+ return Object.keys(toastsByPosition).filter((position) => toastsByPosition[position].length > 0);
842
+ }, [toastsByPosition]);
843
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: positionsWithToasts.map((position) => (jsxRuntime.jsx(ToastContainer, { toasts: toastsByPosition[position], position: position, onClose: handleClose }, position))) }));
844
+ };
845
+
846
+ const useDisclosure = (defaultIsOpen = false) => {
847
+ const [isOpen, setIsOpen] = React.useState(defaultIsOpen);
848
+ const onOpen = React.useCallback(() => {
849
+ setIsOpen(true);
850
+ }, []);
851
+ const onClose = React.useCallback(() => {
852
+ setIsOpen(false);
853
+ }, []);
854
+ const onToggle = React.useCallback(() => {
855
+ setIsOpen((prev) => !prev);
856
+ }, []);
857
+ return {
858
+ isOpen,
859
+ onOpen,
860
+ onClose,
861
+ onToggle,
862
+ };
863
+ };
864
+
865
+ const ThemeContext = React.createContext(undefined);
866
+ const useTheme = () => {
867
+ const context = React.useContext(ThemeContext);
868
+ if (context === undefined) {
869
+ throw new Error("useTheme must be used within a ThemeProvider");
870
+ }
871
+ return context;
872
+ };
873
+ const ThemeProvider = ({ children, defaultTheme = "system", storageKey = "uilab-theme" }) => {
874
+ const [theme, setTheme] = React.useState(defaultTheme);
875
+ const [resolvedTheme, setResolvedTheme] = React.useState("light");
876
+ // Get system preference
877
+ const getSystemTheme = () => {
878
+ if (typeof window !== "undefined") {
879
+ return window.matchMedia("(prefers-color-scheme: dark)").matches
880
+ ? "dark"
881
+ : "light";
882
+ }
883
+ return "light";
884
+ };
885
+ // Apply theme to document
886
+ const applyTheme = (newTheme) => {
887
+ const root = document.documentElement;
888
+ const resolved = newTheme === "system" ? getSystemTheme() : newTheme;
889
+ root.classList.remove("light", "dark");
890
+ root.classList.add(resolved);
891
+ root.setAttribute("data-theme", resolved);
892
+ setResolvedTheme(resolved);
893
+ };
894
+ // Initialize theme from localStorage or use default
895
+ React.useEffect(() => {
896
+ const savedTheme = localStorage.getItem(storageKey);
897
+ if (savedTheme && ["light", "dark", "system"].includes(savedTheme)) {
898
+ setTheme(savedTheme);
899
+ }
900
+ else {
901
+ setTheme(defaultTheme);
902
+ }
903
+ }, [defaultTheme, storageKey]);
904
+ // Apply theme when theme state changes
905
+ React.useEffect(() => {
906
+ applyTheme(theme);
907
+ localStorage.setItem(storageKey, theme);
908
+ }, [theme, storageKey]);
909
+ // Listen for system theme changes
910
+ React.useEffect(() => {
911
+ if (theme === "system") {
912
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
913
+ const handleChange = () => applyTheme("system");
914
+ mediaQuery.addEventListener("change", handleChange);
915
+ return () => mediaQuery.removeEventListener("change", handleChange);
916
+ }
917
+ }, [theme]);
918
+ const value = {
919
+ theme,
920
+ setTheme,
921
+ resolvedTheme,
922
+ };
923
+ return (jsxRuntime.jsx(ThemeContext.Provider, { value: value, children: children }));
924
+ };
925
+
926
+ const ThemeToggle = ({ className = "", showLabel = true, variant = "dropdown", size = "md", }) => {
927
+ const { theme, setTheme, resolvedTheme } = useTheme();
928
+ const [isOpen, setIsOpen] = React.useState(false);
929
+ const dropdownRef = React.useRef(null);
930
+ // Close dropdown when clicking outside
931
+ React.useEffect(() => {
932
+ const handleClickOutside = (event) => {
933
+ if (dropdownRef.current &&
934
+ !dropdownRef.current.contains(event.target)) {
935
+ setIsOpen(false);
936
+ }
937
+ };
938
+ document.addEventListener("mousedown", handleClickOutside);
939
+ return () => document.removeEventListener("mousedown", handleClickOutside);
940
+ }, []);
941
+ const getThemeIcon = () => {
942
+ if (theme === "system") {
943
+ return "🖥️";
944
+ }
945
+ return theme === "dark" ? "🌙" : "☀️";
946
+ };
947
+ const getThemeLabel = () => {
948
+ switch (theme) {
949
+ case "light":
950
+ return "Light";
951
+ case "dark":
952
+ return "Dark";
953
+ case "system":
954
+ return "System";
955
+ default:
956
+ return "System";
957
+ }
958
+ };
959
+ const handleThemeChange = (newTheme) => {
960
+ setTheme(newTheme);
961
+ setIsOpen(false);
962
+ };
963
+ const handleToggle = () => {
964
+ if (variant === "button") {
965
+ // Cycle through themes: light -> dark -> system -> light
966
+ const themes = [
967
+ "light",
968
+ "dark",
969
+ "system",
970
+ ];
971
+ const currentIndex = themes.indexOf(theme);
972
+ const nextIndex = (currentIndex + 1) % themes.length;
973
+ setTheme(themes[nextIndex]);
974
+ }
975
+ else {
976
+ setIsOpen(!isOpen);
977
+ }
978
+ };
979
+ const sizeClasses = {
980
+ sm: "text-sm px-2 py-1",
981
+ md: "text-base px-3 py-2",
982
+ lg: "text-lg px-4 py-3",
983
+ };
984
+ const baseClasses = `inline-flex items-center gap-2 rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700 ${sizeClasses[size]} ${className}`;
985
+ if (variant === "button") {
986
+ return (jsxRuntime.jsxs("button", { onClick: handleToggle, className: baseClasses, title: `Current theme: ${getThemeLabel()}`, children: [jsxRuntime.jsx("span", { children: getThemeIcon() }), showLabel && jsxRuntime.jsx("span", { children: getThemeLabel() })] }));
987
+ }
988
+ return (jsxRuntime.jsxs("div", { className: "relative", ref: dropdownRef, children: [jsxRuntime.jsxs("button", { onClick: handleToggle, className: baseClasses, title: `Theme: ${getThemeLabel()}`, children: [jsxRuntime.jsx("span", { children: getThemeIcon() }), showLabel && jsxRuntime.jsx("span", { children: getThemeLabel() }), jsxRuntime.jsx("span", { className: "ml-1", children: "\u25BC" })] }), isOpen && (jsxRuntime.jsxs("div", { className: "absolute right-0 mt-2 w-48 rounded-md bg-white py-1 shadow-lg ring-1 ring-black ring-opacity-5 dark:bg-gray-800 dark:ring-gray-700", children: [jsxRuntime.jsx("button", { className: `block w-full px-4 py-2 text-left text-sm hover:bg-gray-100 dark:hover:bg-gray-700 ${theme === "light" ? "bg-gray-100 dark:bg-gray-700" : ""}`, onClick: () => handleThemeChange("light"), children: "\u2600\uFE0F Light" }), jsxRuntime.jsx("button", { className: `block w-full px-4 py-2 text-left text-sm hover:bg-gray-100 dark:hover:bg-gray-700 ${theme === "dark" ? "bg-gray-100 dark:bg-gray-700" : ""}`, onClick: () => handleThemeChange("dark"), children: "\uD83C\uDF19 Dark" }), jsxRuntime.jsxs("button", { className: `block w-full px-4 py-2 text-left text-sm hover:bg-gray-100 dark:hover:bg-gray-700 ${theme === "system" ? "bg-gray-100 dark:bg-gray-700" : ""}`, onClick: () => handleThemeChange("system"), children: ["\uD83D\uDDA5\uFE0F System", theme === "system" && (jsxRuntime.jsxs("span", { className: "ml-2 text-xs text-gray-500", children: ["(", resolvedTheme === "dark" ? "Dark" : "Light", ")"] }))] })] }))] }));
989
+ };
990
+
991
+ /**
992
+ * ThemeScript - Blocking script to prevent flash of light content in dark mode
993
+ *
994
+ * Add this component to your Next.js layout.tsx file before the ThemeProvider.
995
+ * Make sure to add `suppressHydrationWarning` to both `<html>` and `<body>` tags
996
+ * to prevent hydration mismatches.
997
+ *
998
+ * @example
999
+ * ```tsx
1000
+ * import { ThemeScript, ThemeProvider } from 'uiplex';
1001
+ *
1002
+ * export default function RootLayout({ children }) {
1003
+ * return (
1004
+ * <html suppressHydrationWarning>
1005
+ * <body suppressHydrationWarning>
1006
+ * <ThemeScript />
1007
+ * <ThemeProvider>
1008
+ * {children}
1009
+ * </ThemeProvider>
1010
+ * </body>
1011
+ * </html>
1012
+ * );
1013
+ * }
1014
+ * ```
1015
+ */
1016
+ const ThemeScript = ({ storageKey = "uiplex-theme", defaultTheme = "system" }) => {
1017
+ return (jsxRuntime.jsx("script", { dangerouslySetInnerHTML: {
1018
+ __html: `
1019
+ (function() {
1020
+ try {
1021
+ // Disable transitions immediately to prevent flash
1022
+ var noTransitionStyle = document.createElement('style');
1023
+ noTransitionStyle.textContent = '* { transition: none !important; }';
1024
+ document.head.appendChild(noTransitionStyle);
1025
+
1026
+ var theme = localStorage.getItem('${storageKey}') || '${defaultTheme}';
1027
+ var resolvedTheme = theme;
1028
+
1029
+ if (theme === 'system') {
1030
+ resolvedTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
1031
+ }
1032
+
1033
+ document.documentElement.classList.remove('light', 'dark');
1034
+ document.documentElement.classList.add(resolvedTheme);
1035
+ document.documentElement.setAttribute('data-theme', resolvedTheme);
1036
+
1037
+ // Set initial background color to prevent flash - use !important
1038
+ if (resolvedTheme === 'dark') {
1039
+ var darkStyle = document.createElement('style');
1040
+ darkStyle.textContent = 'html, body { background-color: #111827 !important; color: #f9fafb !important; }';
1041
+ document.head.appendChild(darkStyle);
1042
+ }
1043
+
1044
+ // Re-enable transitions after a short delay
1045
+ setTimeout(function() {
1046
+ noTransitionStyle.remove();
1047
+ }, 100);
1048
+ } catch (e) {
1049
+ document.documentElement.classList.add('light');
1050
+ document.documentElement.setAttribute('data-theme', 'light');
1051
+ }
1052
+ })();
1053
+ `,
1054
+ } }));
1055
+ };
1056
+
1057
+ exports.Box = Box;
1058
+ exports.Button = Button;
1059
+ exports.CircularProgress = CircularProgress;
1060
+ exports.CircularProgressLabel = CircularProgressLabel;
1061
+ exports.Flex = Flex;
1062
+ exports.FormControl = FormControl;
1063
+ exports.FormErrorMessage = FormErrorMessage;
1064
+ exports.FormLabel = FormLabel;
1065
+ exports.Grid = Grid;
1066
+ exports.IconButton = IconButton;
1067
+ exports.Input = Input;
1068
+ exports.Link = Link;
1069
+ exports.Loader = Loader;
1070
+ exports.Modal = Modal;
1071
+ exports.ModalBody = ModalBody;
1072
+ exports.ModalCloseButton = ModalCloseButton;
1073
+ exports.ModalContent = ModalContent;
1074
+ exports.ModalFooter = ModalFooter;
1075
+ exports.ModalHeader = ModalHeader;
1076
+ exports.ModalOverlay = ModalOverlay;
1077
+ exports.Popover = Popover;
1078
+ exports.PopoverBody = PopoverBody;
1079
+ exports.PopoverCloseButton = PopoverCloseButton;
1080
+ exports.PopoverContent = PopoverContent;
1081
+ exports.PopoverFooter = PopoverFooter;
1082
+ exports.PopoverHeader = PopoverHeader;
1083
+ exports.Radio = Radio;
1084
+ exports.RadioGroup = RadioGroup;
1085
+ exports.Text = Text;
1086
+ exports.Textarea = Textarea;
1087
+ exports.ThemeProvider = ThemeProvider;
1088
+ exports.ThemeScript = ThemeScript;
1089
+ exports.ThemeToggle = ThemeToggle;
1090
+ exports.Toast = ToastStatic;
1091
+ exports.ToastComponent = Toast;
1092
+ exports.ToastContainer = ToastContainer;
1093
+ exports.ToastContainerGlobal = ToastContainerGlobal;
1094
+ exports.Tooltip = Tooltip;
1095
+ exports.useDisclosure = useDisclosure;
1096
+ exports.useOutsideClick = useOutsideClick;
1097
+ exports.useTheme = useTheme;