@sehgaltech/psui 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.
package/dist/index.cjs ADDED
@@ -0,0 +1,391 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var clsx = require('clsx');
5
+ var tailwindMerge = require('tailwind-merge');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+ var LucideIcons = require('lucide-react');
8
+
9
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
+
11
+ function _interopNamespace(e) {
12
+ if (e && e.__esModule) return e;
13
+ var n = Object.create(null);
14
+ if (e) {
15
+ Object.keys(e).forEach(function (k) {
16
+ if (k !== 'default') {
17
+ var d = Object.getOwnPropertyDescriptor(e, k);
18
+ Object.defineProperty(n, k, d.get ? d : {
19
+ enumerable: true,
20
+ get: function () { return e[k]; }
21
+ });
22
+ }
23
+ });
24
+ }
25
+ n.default = e;
26
+ return Object.freeze(n);
27
+ }
28
+
29
+ var React__default = /*#__PURE__*/_interopDefault(React);
30
+ var LucideIcons__namespace = /*#__PURE__*/_interopNamespace(LucideIcons);
31
+
32
+ // src/components/Button/Button.tsx
33
+ function cn(...inputs) {
34
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
35
+ }
36
+ var sizeClasses = {
37
+ sm: "px-3 py-1.5 text-sm",
38
+ md: "px-4 py-2 text-base",
39
+ lg: "px-6 py-3 text-lg"
40
+ };
41
+ var variantClasses = {
42
+ solid: {
43
+ primary: "bg-primary text-primary-content hover:opacity-90",
44
+ secondary: "bg-secondary text-secondary-content hover:opacity-90",
45
+ success: "bg-success text-success-content hover:opacity-90",
46
+ danger: "bg-error text-error-content hover:opacity-90",
47
+ warning: "bg-warning text-warning-content hover:opacity-90",
48
+ info: "bg-info text-info-content hover:opacity-90",
49
+ ghost: "bg-base-200 text-base-content hover:bg-base-300"
50
+ },
51
+ outlined: {
52
+ primary: "border border-primary text-primary bg-transparent hover:bg-primary/10",
53
+ secondary: "border border-secondary text-secondary bg-transparent hover:bg-secondary/10",
54
+ success: "border border-success text-success bg-transparent hover:bg-success/10",
55
+ danger: "border border-error text-error bg-transparent hover:bg-error/10",
56
+ warning: "border border-warning text-warning bg-transparent hover:bg-warning/10",
57
+ info: "border border-info text-info bg-transparent hover:bg-info/10",
58
+ ghost: "border border-base-200 text-base-content bg-transparent hover:bg-base-200/10"
59
+ },
60
+ dashed: {
61
+ primary: "border border-dashed border-primary text-primary bg-transparent hover:bg-primary/10",
62
+ secondary: "border border-dashed border-secondary text-secondary bg-transparent hover:bg-secondary/10",
63
+ success: "border border-dashed border-success text-success bg-transparent hover:bg-success/10",
64
+ danger: "border border-dashed border-error text-error bg-transparent hover:bg-error/10",
65
+ warning: "border border-dashed border-warning text-warning bg-transparent hover:bg-warning/10",
66
+ info: "border border-dashed border-info text-info bg-transparent hover:bg-info/10",
67
+ ghost: "border border-dashed border-base-200 text-base-content bg-transparent hover:bg-base-200/10"
68
+ },
69
+ text: {
70
+ primary: "text-primary bg-transparent hover:bg-primary/10",
71
+ secondary: "text-secondary bg-transparent hover:bg-secondary/10",
72
+ success: "text-success bg-transparent hover:bg-success/10",
73
+ danger: "text-error bg-transparent hover:bg-error/10",
74
+ warning: "text-warning bg-transparent hover:bg-warning/10",
75
+ info: "text-info bg-transparent hover:bg-info/10",
76
+ ghost: "text-base-content bg-transparent hover:bg-base-200/10"
77
+ },
78
+ link: {
79
+ primary: "text-primary underline bg-transparent hover:text-primary/80",
80
+ secondary: "text-secondary underline bg-transparent hover:text-secondary/80",
81
+ success: "text-success underline bg-transparent hover:text-success/80",
82
+ danger: "text-error underline bg-transparent hover:text-error/80",
83
+ warning: "text-warning underline bg-transparent hover:text-warning/80",
84
+ info: "text-info underline bg-transparent hover:text-info/80",
85
+ ghost: "text-base-content underline bg-transparent hover:text-base-content/80"
86
+ }
87
+ };
88
+ var getButtonClasses = (variant, type) => {
89
+ return variantClasses[variant][type] || variantClasses.solid.primary;
90
+ };
91
+ var SuccessIcon = () => /* @__PURE__ */ jsxRuntime.jsx(
92
+ "svg",
93
+ {
94
+ className: "h-4 w-4",
95
+ xmlns: "http://www.w3.org/2000/svg",
96
+ fill: "none",
97
+ viewBox: "0 0 24 24",
98
+ "aria-hidden": "true",
99
+ children: /* @__PURE__ */ jsxRuntime.jsx(
100
+ "path",
101
+ {
102
+ stroke: "currentColor",
103
+ strokeLinecap: "round",
104
+ strokeLinejoin: "round",
105
+ strokeWidth: "2.5",
106
+ d: "M5 12.5l4.5 4.5L19 7.5"
107
+ }
108
+ )
109
+ }
110
+ );
111
+ var Button = React.forwardRef(
112
+ ({
113
+ variant = "solid",
114
+ type = "primary",
115
+ size = "md",
116
+ fullWidth = false,
117
+ loading = false,
118
+ loadingText,
119
+ success = false,
120
+ successText,
121
+ successIcon,
122
+ successDuration = 1500,
123
+ disabled = false,
124
+ startIcon,
125
+ endIcon,
126
+ color,
127
+ className = "",
128
+ children,
129
+ ...props
130
+ }, ref) => {
131
+ const [isShowingSuccess, setIsShowingSuccess] = React.useState(false);
132
+ React.useEffect(() => {
133
+ if (!success || loading) {
134
+ return;
135
+ }
136
+ setIsShowingSuccess(true);
137
+ const timer = window.setTimeout(() => {
138
+ setIsShowingSuccess(false);
139
+ }, successDuration);
140
+ return () => window.clearTimeout(timer);
141
+ }, [success, loading, successDuration]);
142
+ const baseClasses = "inline-flex items-center justify-center font-medium rounded-[var(--radius-selector)] transition-all duration-200 focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed active:scale-95 gap-2";
143
+ const variantClass = getButtonClasses(variant, type);
144
+ const sizeClass = sizeClasses[size];
145
+ const widthClass = fullWidth ? "w-full" : "";
146
+ const loadingClass = loading ? "cursor-wait" : "";
147
+ const combinedClasses = cn(
148
+ baseClasses,
149
+ variantClass,
150
+ sizeClass,
151
+ widthClass,
152
+ loadingClass,
153
+ className
154
+ );
155
+ const customStyle = { ...props.style };
156
+ if (color) {
157
+ if (variant === "solid") {
158
+ customStyle.backgroundColor = color;
159
+ customStyle.borderColor = color;
160
+ } else if (variant === "outlined" || variant === "dashed") {
161
+ customStyle.borderColor = color;
162
+ customStyle.color = color;
163
+ } else if (variant === "text" || variant === "link") {
164
+ customStyle.color = color;
165
+ }
166
+ }
167
+ const content = loading ? loadingText ?? children : isShowingSuccess ? successText ?? children : children;
168
+ return /* @__PURE__ */ jsxRuntime.jsxs(
169
+ "button",
170
+ {
171
+ ref,
172
+ type: "button",
173
+ className: combinedClasses,
174
+ style: customStyle,
175
+ disabled: disabled || loading,
176
+ "aria-busy": loading || void 0,
177
+ ...props,
178
+ children: [
179
+ loading && /* @__PURE__ */ jsxRuntime.jsxs(
180
+ "svg",
181
+ {
182
+ className: "animate-spin -ml-1 h-4 w-4",
183
+ xmlns: "http://www.w3.org/2000/svg",
184
+ fill: "none",
185
+ viewBox: "0 0 24 24",
186
+ "aria-hidden": "true",
187
+ children: [
188
+ /* @__PURE__ */ jsxRuntime.jsx(
189
+ "circle",
190
+ {
191
+ className: "opacity-25",
192
+ cx: "12",
193
+ cy: "12",
194
+ r: "10",
195
+ stroke: "currentColor",
196
+ strokeWidth: "4"
197
+ }
198
+ ),
199
+ /* @__PURE__ */ jsxRuntime.jsx(
200
+ "path",
201
+ {
202
+ className: "opacity-75",
203
+ fill: "currentColor",
204
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
205
+ }
206
+ )
207
+ ]
208
+ }
209
+ ),
210
+ !loading && isShowingSuccess && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex shrink-0", children: successIcon ?? /* @__PURE__ */ jsxRuntime.jsx(SuccessIcon, {}) }),
211
+ !loading && !isShowingSuccess && startIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex shrink-0", children: startIcon }),
212
+ content,
213
+ !loading && !isShowingSuccess && endIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex shrink-0", children: endIcon })
214
+ ]
215
+ }
216
+ );
217
+ }
218
+ );
219
+ Button.displayName = "Button";
220
+ var SplitButton = React.forwardRef(
221
+ ({
222
+ label,
223
+ onClick,
224
+ items,
225
+ menuLabel = "More actions",
226
+ align = "right",
227
+ variant = "solid",
228
+ type = "primary",
229
+ size = "md",
230
+ color,
231
+ disabled = false,
232
+ loading = false,
233
+ className,
234
+ menuClassName,
235
+ ...buttonProps
236
+ }, ref) => {
237
+ const [open, setOpen] = React.useState(false);
238
+ const rootRef = React.useRef(null);
239
+ const menuId = React.useId();
240
+ React.useEffect(() => {
241
+ const handleEscape = (event) => {
242
+ if (event.key === "Escape") {
243
+ setOpen(false);
244
+ }
245
+ };
246
+ document.addEventListener("keydown", handleEscape);
247
+ return () => {
248
+ document.removeEventListener("keydown", handleEscape);
249
+ };
250
+ }, []);
251
+ const handleItemSelect = (item) => {
252
+ if (item.disabled) {
253
+ return;
254
+ }
255
+ item.onClick?.();
256
+ setOpen(false);
257
+ };
258
+ const hasItems = items.length > 0;
259
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rootRef, className: cn("relative inline-flex", className), children: [
260
+ /* @__PURE__ */ jsxRuntime.jsx(
261
+ Button,
262
+ {
263
+ ref,
264
+ variant,
265
+ type,
266
+ size,
267
+ color,
268
+ disabled,
269
+ loading,
270
+ onClick,
271
+ className: cn("rounded-r-none", variant !== "link" && "border-r-0"),
272
+ ...buttonProps,
273
+ children: label
274
+ }
275
+ ),
276
+ /* @__PURE__ */ jsxRuntime.jsx(
277
+ Button,
278
+ {
279
+ variant,
280
+ type,
281
+ size,
282
+ color,
283
+ disabled: disabled || loading || !hasItems,
284
+ "aria-label": menuLabel,
285
+ "aria-haspopup": "menu",
286
+ "aria-expanded": open,
287
+ "aria-controls": menuId,
288
+ onClick: () => setOpen((prev) => !prev),
289
+ className: cn("rounded-l-none px-3", variant !== "link" && "border-l"),
290
+ children: /* @__PURE__ */ jsxRuntime.jsx(
291
+ "svg",
292
+ {
293
+ xmlns: "http://www.w3.org/2000/svg",
294
+ viewBox: "0 0 20 20",
295
+ fill: "currentColor",
296
+ className: cn("h-4 w-4 transition-transform duration-150", open && "rotate-180"),
297
+ "aria-hidden": "true",
298
+ children: /* @__PURE__ */ jsxRuntime.jsx(
299
+ "path",
300
+ {
301
+ fillRule: "evenodd",
302
+ d: "M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z",
303
+ clipRule: "evenodd"
304
+ }
305
+ )
306
+ }
307
+ )
308
+ }
309
+ ),
310
+ open && hasItems && /* @__PURE__ */ jsxRuntime.jsx(
311
+ "div",
312
+ {
313
+ id: menuId,
314
+ role: "menu",
315
+ className: cn(
316
+ "absolute z-20 top-full mt-2 min-w-44 overflow-hidden rounded-lg border border-base-300 bg-base-100 p-1 shadow-lg",
317
+ align === "right" ? "right-0" : "left-0",
318
+ menuClassName
319
+ ),
320
+ children: items.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
321
+ "button",
322
+ {
323
+ type: "button",
324
+ role: "menuitem",
325
+ disabled: item.disabled,
326
+ onClick: () => handleItemSelect(item),
327
+ className: cn(
328
+ "w-full rounded-md px-3 py-2 text-left text-sm transition-colors",
329
+ item.disabled ? "cursor-not-allowed opacity-50" : item.destructive ? "text-error hover:bg-error/10" : "text-base-content hover:bg-base-200"
330
+ ),
331
+ children: item.label
332
+ },
333
+ item.key ?? `split-item-${index}`
334
+ ))
335
+ }
336
+ )
337
+ ] });
338
+ }
339
+ );
340
+ SplitButton.displayName = "SplitButton";
341
+ var sizeMap = {
342
+ xs: 12,
343
+ sm: 16,
344
+ md: 24,
345
+ lg: 32,
346
+ xl: 48,
347
+ "2xl": 64
348
+ };
349
+ var colorMap = {
350
+ primary: "text-primary",
351
+ secondary: "text-secondary",
352
+ accent: "text-accent",
353
+ neutral: "text-neutral",
354
+ info: "text-info",
355
+ success: "text-success",
356
+ warning: "text-warning",
357
+ error: "text-error",
358
+ current: "text-current"
359
+ };
360
+ var Icon = React__default.default.forwardRef(
361
+ ({ icon: ExplicitIcon, name, size = "md", color = "current", className, ...props }, ref) => {
362
+ const sizeValue = sizeMap[size];
363
+ const isThemeColor = color && Object.keys(colorMap).includes(color);
364
+ const colorClass = isThemeColor ? colorMap[color] : "";
365
+ const customColor = !isThemeColor ? color : void 0;
366
+ const IconComponent = ExplicitIcon || (name ? LucideIcons__namespace[name] : null);
367
+ if (!IconComponent) {
368
+ console.warn(`Icon: No icon provided. Pass either 'icon' component or 'name' string.`);
369
+ return null;
370
+ }
371
+ return /* @__PURE__ */ jsxRuntime.jsx(
372
+ IconComponent,
373
+ {
374
+ ref,
375
+ width: sizeValue,
376
+ height: sizeValue,
377
+ size: sizeValue,
378
+ color: customColor,
379
+ style: { color: customColor, ...props.style },
380
+ className: `${colorClass} ${className || ""}`,
381
+ ...props
382
+ }
383
+ );
384
+ }
385
+ );
386
+ Icon.displayName = "Icon";
387
+
388
+ exports.Button = Button;
389
+ exports.Icon = Icon;
390
+ //# sourceMappingURL=index.cjs.map
391
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/cn.ts","../src/components/Button/Button.tsx","../src/components/Icon/Icon.tsx"],"names":["twMerge","clsx","jsx","forwardRef","useState","useEffect","jsxs","useRef","useId","React","LucideIcons"],"mappings":"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","file":"index.cjs","sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import { forwardRef, useEffect, useId, useRef, useState } from 'react';\nimport type { ComponentProps } from '../../types';\nimport { cn } from '../../utils/cn';\n\nexport type ButtonVariant = 'solid' | 'outlined' | 'dashed' | 'text' | 'link';\nexport type ButtonType = 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'ghost';\n\nexport interface ButtonProps extends Omit<ComponentProps<'button'>, 'type'> {\n /**\n * The visual style variant of the button\n * @default 'solid'\n */\n variant?: ButtonVariant;\n /**\n * The type theme of the button\n * @default 'primary'\n */\n type?: ButtonType;\n /**\n * Custom hex, rgb, or css color string that overrides the type colors\n */\n color?: string;\n /**\n * The size of the button\n * @default 'md'\n */\n size?: 'sm' | 'md' | 'lg';\n /**\n * Whether the button should take full width of its container\n * @default false\n */\n fullWidth?: boolean;\n /**\n * Whether the button is in a loading state\n * @default false\n */\n loading?: boolean;\n /**\n * Optional text shown while loading.\n */\n loadingText?: React.ReactNode;\n /**\n * Whether the button should show temporary success feedback.\n */\n success?: boolean;\n /**\n * Optional text shown in success state.\n */\n successText?: React.ReactNode;\n /**\n * Optional icon shown in success state.\n */\n successIcon?: React.ReactNode;\n /**\n * Duration in milliseconds before success state resets.\n * @default 1500\n */\n successDuration?: number;\n /**\n * Element to place before the children.\n */\n startIcon?: React.ReactNode;\n /**\n * Element to place after the children.\n */\n endIcon?: React.ReactNode;\n}\n\nexport interface SplitButtonItem {\n /**\n * Stable key for rendering list items\n */\n key?: string;\n /**\n * Rendered menu item label\n */\n label: React.ReactNode;\n /**\n * Item click handler\n */\n onClick?: () => void;\n /**\n * Whether the item is disabled\n */\n disabled?: boolean;\n /**\n * Marks a destructive menu item with error color\n */\n destructive?: boolean;\n}\n\nexport interface SplitButtonProps extends Omit<ButtonProps, 'children' | 'onClick' | 'fullWidth'> {\n /**\n * Main action label/content\n */\n label: React.ReactNode;\n /**\n * Main action handler\n */\n onClick?: React.MouseEventHandler<HTMLButtonElement>;\n /**\n * Dropdown menu items\n */\n items: SplitButtonItem[];\n /**\n * Accessible label for toggle button\n * @default 'More actions'\n */\n menuLabel?: string;\n /**\n * Menu alignment relative to trigger\n * @default 'right'\n */\n align?: 'left' | 'right';\n /**\n * Optional wrapper classes for split group container\n */\n className?: string;\n /**\n * Optional menu panel classes\n */\n menuClassName?: string;\n}\n\nconst sizeClasses = {\n sm: 'px-3 py-1.5 text-sm',\n md: 'px-4 py-2 text-base',\n lg: 'px-6 py-3 text-lg',\n};\n\nconst variantClasses: Record<ButtonVariant, Record<ButtonType, string>> = {\n solid: {\n primary: 'bg-primary text-primary-content hover:opacity-90',\n secondary: 'bg-secondary text-secondary-content hover:opacity-90',\n success: 'bg-success text-success-content hover:opacity-90',\n danger: 'bg-error text-error-content hover:opacity-90',\n warning: 'bg-warning text-warning-content hover:opacity-90',\n info: 'bg-info text-info-content hover:opacity-90',\n ghost: 'bg-base-200 text-base-content hover:bg-base-300',\n },\n outlined: {\n primary: 'border border-primary text-primary bg-transparent hover:bg-primary/10',\n secondary: 'border border-secondary text-secondary bg-transparent hover:bg-secondary/10',\n success: 'border border-success text-success bg-transparent hover:bg-success/10',\n danger: 'border border-error text-error bg-transparent hover:bg-error/10',\n warning: 'border border-warning text-warning bg-transparent hover:bg-warning/10',\n info: 'border border-info text-info bg-transparent hover:bg-info/10',\n ghost: 'border border-base-200 text-base-content bg-transparent hover:bg-base-200/10',\n },\n dashed: {\n primary: 'border border-dashed border-primary text-primary bg-transparent hover:bg-primary/10',\n secondary: 'border border-dashed border-secondary text-secondary bg-transparent hover:bg-secondary/10',\n success: 'border border-dashed border-success text-success bg-transparent hover:bg-success/10',\n danger: 'border border-dashed border-error text-error bg-transparent hover:bg-error/10',\n warning: 'border border-dashed border-warning text-warning bg-transparent hover:bg-warning/10',\n info: 'border border-dashed border-info text-info bg-transparent hover:bg-info/10',\n ghost: 'border border-dashed border-base-200 text-base-content bg-transparent hover:bg-base-200/10',\n },\n text: {\n primary: 'text-primary bg-transparent hover:bg-primary/10',\n secondary: 'text-secondary bg-transparent hover:bg-secondary/10',\n success: 'text-success bg-transparent hover:bg-success/10',\n danger: 'text-error bg-transparent hover:bg-error/10',\n warning: 'text-warning bg-transparent hover:bg-warning/10',\n info: 'text-info bg-transparent hover:bg-info/10',\n ghost: 'text-base-content bg-transparent hover:bg-base-200/10',\n },\n link: {\n primary: 'text-primary underline bg-transparent hover:text-primary/80',\n secondary: 'text-secondary underline bg-transparent hover:text-secondary/80',\n success: 'text-success underline bg-transparent hover:text-success/80',\n danger: 'text-error underline bg-transparent hover:text-error/80',\n warning: 'text-warning underline bg-transparent hover:text-warning/80',\n info: 'text-info underline bg-transparent hover:text-info/80',\n ghost: 'text-base-content underline bg-transparent hover:text-base-content/80',\n },\n};\n\nconst getButtonClasses = (variant: ButtonVariant, type: ButtonType) => {\n return variantClasses[variant][type] || variantClasses.solid.primary;\n};\n\nconst SuccessIcon = () => (\n <svg\n className=\"h-4 w-4\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <path\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2.5\"\n d=\"M5 12.5l4.5 4.5L19 7.5\"\n />\n </svg>\n);\n\n/**\n * Primary UI component for user interaction\n *\n * Supports all standard HTML button attributes including `style` and `className`.\n * - Use `type` and `variant` for standard theming.\n * - Use `className` with Tailwind classes for one-off overrides (merged intelligently).\n * - Use `style` for inline dynamic styles.\n */\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n variant = 'solid',\n type = 'primary',\n size = 'md',\n fullWidth = false,\n loading = false,\n loadingText,\n success = false,\n successText,\n successIcon,\n successDuration = 1500,\n disabled = false,\n startIcon,\n endIcon,\n color,\n className = '',\n children,\n ...props\n },\n ref\n ) => {\n const [isShowingSuccess, setIsShowingSuccess] = useState(false);\n\n useEffect(() => {\n if (!success || loading) {\n return;\n }\n\n setIsShowingSuccess(true);\n const timer = window.setTimeout(() => {\n setIsShowingSuccess(false);\n }, successDuration);\n\n return () => window.clearTimeout(timer);\n }, [success, loading, successDuration]);\n\n const baseClasses = 'inline-flex items-center justify-center font-medium rounded-[var(--radius-selector)] transition-all duration-200 focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed active:scale-95 gap-2';\n const variantClass = getButtonClasses(variant, type);\n const sizeClass = sizeClasses[size];\n const widthClass = fullWidth ? 'w-full' : '';\n const loadingClass = loading ? 'cursor-wait' : '';\n\n const combinedClasses = cn(\n baseClasses,\n variantClass,\n sizeClass,\n widthClass,\n loadingClass,\n className\n );\n\n const customStyle: React.CSSProperties = { ...props.style };\n if (color) {\n if (variant === 'solid') {\n customStyle.backgroundColor = color;\n customStyle.borderColor = color;\n } else if (variant === 'outlined' || variant === 'dashed') {\n customStyle.borderColor = color;\n customStyle.color = color;\n } else if (variant === 'text' || variant === 'link') {\n customStyle.color = color;\n }\n }\n\n const content = loading\n ? loadingText ?? children\n : isShowingSuccess\n ? successText ?? children\n : children;\n\n return (\n <button\n ref={ref}\n type=\"button\"\n className={combinedClasses}\n style={customStyle}\n disabled={disabled || loading}\n aria-busy={loading || undefined}\n {...props}\n >\n {loading && (\n <svg\n className=\"animate-spin -ml-1 h-4 w-4\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n )}\n {!loading && isShowingSuccess && <span className=\"inline-flex shrink-0\">{successIcon ?? <SuccessIcon />}</span>}\n {!loading && !isShowingSuccess && startIcon && <span className=\"inline-flex shrink-0\">{startIcon}</span>}\n {content}\n {!loading && !isShowingSuccess && endIcon && <span className=\"inline-flex shrink-0\">{endIcon}</span>}\n </button>\n );\n }\n);\n\nButton.displayName = 'Button';\n\nexport const SplitButton = forwardRef<HTMLButtonElement, SplitButtonProps>(\n (\n {\n label,\n onClick,\n items,\n menuLabel = 'More actions',\n align = 'right',\n variant = 'solid',\n type = 'primary',\n size = 'md',\n color,\n disabled = false,\n loading = false,\n className,\n menuClassName,\n ...buttonProps\n },\n ref\n ) => {\n const [open, setOpen] = useState(false);\n const rootRef = useRef<HTMLDivElement>(null);\n const menuId = useId();\n\n useEffect(() => {\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n setOpen(false);\n }\n };\n\n document.addEventListener('keydown', handleEscape);\n\n return () => {\n document.removeEventListener('keydown', handleEscape);\n };\n }, []);\n\n const handleItemSelect = (item: SplitButtonItem) => {\n if (item.disabled) {\n return;\n }\n\n item.onClick?.();\n setOpen(false);\n };\n\n const hasItems = items.length > 0;\n\n return (\n <div ref={rootRef} className={cn('relative inline-flex', className)}>\n <Button\n ref={ref}\n variant={variant}\n type={type}\n size={size}\n color={color}\n disabled={disabled}\n loading={loading}\n onClick={onClick}\n className={cn('rounded-r-none', variant !== 'link' && 'border-r-0')}\n {...buttonProps}\n >\n {label}\n </Button>\n\n <Button\n variant={variant}\n type={type}\n size={size}\n color={color}\n disabled={disabled || loading || !hasItems}\n aria-label={menuLabel}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-controls={menuId}\n onClick={() => setOpen((prev) => !prev)}\n className={cn('rounded-l-none px-3', variant !== 'link' && 'border-l')}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n className={cn('h-4 w-4 transition-transform duration-150', open && 'rotate-180')}\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </Button>\n\n {open && hasItems && (\n <div\n id={menuId}\n role=\"menu\"\n className={cn(\n 'absolute z-20 top-full mt-2 min-w-44 overflow-hidden rounded-lg border border-base-300 bg-base-100 p-1 shadow-lg',\n align === 'right' ? 'right-0' : 'left-0',\n menuClassName\n )}\n >\n {items.map((item, index) => (\n <button\n key={item.key ?? `split-item-${index}`}\n type=\"button\"\n role=\"menuitem\"\n disabled={item.disabled}\n onClick={() => handleItemSelect(item)}\n className={cn(\n 'w-full rounded-md px-3 py-2 text-left text-sm transition-colors',\n item.disabled\n ? 'cursor-not-allowed opacity-50'\n : item.destructive\n ? 'text-error hover:bg-error/10'\n : 'text-base-content hover:bg-base-200'\n )}\n >\n {item.label}\n </button>\n ))}\n </div>\n )}\n </div>\n );\n }\n);\n\nSplitButton.displayName = 'SplitButton';\n","import * as LucideIcons from 'lucide-react';\nimport React from 'react';\n\nexport type IconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n\nexport type IconColor =\n | 'primary'\n | 'secondary'\n | 'accent'\n | 'neutral'\n | 'info'\n | 'success'\n | 'warning'\n | 'error'\n | 'current';\n\nexport type IconName = keyof typeof LucideIcons;\n\nexport interface IconProps extends Omit<React.SVGProps<SVGSVGElement>, 'color'> {\n /** The icon component to render (e.g., from Phosphor, Heroicons, Radix, etc.) */\n icon?: React.ElementType;\n /** The name of the Lucide icon to render (backward compatibility) */\n name?: IconName;\n /** Size of the icon */\n size?: IconSize;\n /** Color of the icon. Can be a theme color (e.g., 'primary') or any valid CSS color string. */\n color?: IconColor | string;\n}\n\nconst sizeMap: Record<IconSize, number> = {\n xs: 12,\n sm: 16,\n md: 24,\n lg: 32,\n xl: 48,\n '2xl': 64,\n};\n\nconst colorMap: Record<IconColor, string> = {\n primary: 'text-primary',\n secondary: 'text-secondary',\n accent: 'text-accent',\n neutral: 'text-neutral',\n info: 'text-info',\n success: 'text-success',\n warning: 'text-warning',\n error: 'text-error',\n current: 'text-current',\n};\n\nexport const Icon = React.forwardRef<SVGSVGElement, IconProps>(\n ({ icon: ExplicitIcon, name, size = 'md', color = 'current', className, ...props }, ref) => {\n const sizeValue = sizeMap[size];\n\n const isThemeColor = color && Object.keys(colorMap).includes(color as string);\n const colorClass = isThemeColor ? colorMap[color as IconColor] : '';\n const customColor = !isThemeColor ? color : undefined;\n\n // Resolve the component to render: explicitly passed icon takes precedence over named lucide icon.\n const IconComponent = ExplicitIcon || (name ? (LucideIcons[name] as React.ElementType) : null);\n\n if (!IconComponent) {\n console.warn(`Icon: No icon provided. Pass either 'icon' component or 'name' string.`);\n return null;\n }\n\n // We pass standard SVG width/height and color styles. \n // This makes it compatible with almost ALL external icon libraries out of the box\n // because components generally forward standard SVG props to their root <svg>.\n return (\n <IconComponent\n ref={ref}\n width={sizeValue}\n height={sizeValue}\n // Fallback for libraries like Lucide or Phosphor that use a custom `size` prop\n size={sizeValue}\n // Fallback for libraries like Lucide or Phosphor that use a custom `color` prop\n color={customColor}\n style={{ color: customColor, ...props.style }}\n className={`${colorClass} ${className || ''}`}\n {...props}\n />\n );\n }\n);\n\nIcon.displayName = 'Icon';\n"]}
@@ -0,0 +1,97 @@
1
+ import * as react from 'react';
2
+ import react__default, { ElementType, ComponentPropsWithoutRef } from 'react';
3
+ import * as LucideIcons from 'lucide-react';
4
+
5
+ type ComponentProps<T extends ElementType> = ComponentPropsWithoutRef<T>;
6
+ type ComponentVariants<T extends Record<string, string>> = {
7
+ [K in keyof T]?: T[K];
8
+ };
9
+
10
+ type ButtonVariant = 'solid' | 'outlined' | 'dashed' | 'text' | 'link';
11
+ type ButtonType = 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'ghost';
12
+ interface ButtonProps extends Omit<ComponentProps<'button'>, 'type'> {
13
+ /**
14
+ * The visual style variant of the button
15
+ * @default 'solid'
16
+ */
17
+ variant?: ButtonVariant;
18
+ /**
19
+ * The type theme of the button
20
+ * @default 'primary'
21
+ */
22
+ type?: ButtonType;
23
+ /**
24
+ * Custom hex, rgb, or css color string that overrides the type colors
25
+ */
26
+ color?: string;
27
+ /**
28
+ * The size of the button
29
+ * @default 'md'
30
+ */
31
+ size?: 'sm' | 'md' | 'lg';
32
+ /**
33
+ * Whether the button should take full width of its container
34
+ * @default false
35
+ */
36
+ fullWidth?: boolean;
37
+ /**
38
+ * Whether the button is in a loading state
39
+ * @default false
40
+ */
41
+ loading?: boolean;
42
+ /**
43
+ * Optional text shown while loading.
44
+ */
45
+ loadingText?: React.ReactNode;
46
+ /**
47
+ * Whether the button should show temporary success feedback.
48
+ */
49
+ success?: boolean;
50
+ /**
51
+ * Optional text shown in success state.
52
+ */
53
+ successText?: React.ReactNode;
54
+ /**
55
+ * Optional icon shown in success state.
56
+ */
57
+ successIcon?: React.ReactNode;
58
+ /**
59
+ * Duration in milliseconds before success state resets.
60
+ * @default 1500
61
+ */
62
+ successDuration?: number;
63
+ /**
64
+ * Element to place before the children.
65
+ */
66
+ startIcon?: React.ReactNode;
67
+ /**
68
+ * Element to place after the children.
69
+ */
70
+ endIcon?: React.ReactNode;
71
+ }
72
+ /**
73
+ * Primary UI component for user interaction
74
+ *
75
+ * Supports all standard HTML button attributes including `style` and `className`.
76
+ * - Use `type` and `variant` for standard theming.
77
+ * - Use `className` with Tailwind classes for one-off overrides (merged intelligently).
78
+ * - Use `style` for inline dynamic styles.
79
+ */
80
+ declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLButtonElement>>;
81
+
82
+ type IconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
83
+ type IconColor = 'primary' | 'secondary' | 'accent' | 'neutral' | 'info' | 'success' | 'warning' | 'error' | 'current';
84
+ type IconName = keyof typeof LucideIcons;
85
+ interface IconProps extends Omit<react__default.SVGProps<SVGSVGElement>, 'color'> {
86
+ /** The icon component to render (e.g., from Phosphor, Heroicons, Radix, etc.) */
87
+ icon?: react__default.ElementType;
88
+ /** The name of the Lucide icon to render (backward compatibility) */
89
+ name?: IconName;
90
+ /** Size of the icon */
91
+ size?: IconSize;
92
+ /** Color of the icon. Can be a theme color (e.g., 'primary') or any valid CSS color string. */
93
+ color?: IconColor | string;
94
+ }
95
+ declare const Icon: react__default.ForwardRefExoticComponent<Omit<IconProps, "ref"> & react__default.RefAttributes<SVGSVGElement>>;
96
+
97
+ export { Button, type ButtonProps, type ComponentProps, type ComponentVariants, Icon, type IconProps };
@@ -0,0 +1,97 @@
1
+ import * as react from 'react';
2
+ import react__default, { ElementType, ComponentPropsWithoutRef } from 'react';
3
+ import * as LucideIcons from 'lucide-react';
4
+
5
+ type ComponentProps<T extends ElementType> = ComponentPropsWithoutRef<T>;
6
+ type ComponentVariants<T extends Record<string, string>> = {
7
+ [K in keyof T]?: T[K];
8
+ };
9
+
10
+ type ButtonVariant = 'solid' | 'outlined' | 'dashed' | 'text' | 'link';
11
+ type ButtonType = 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'ghost';
12
+ interface ButtonProps extends Omit<ComponentProps<'button'>, 'type'> {
13
+ /**
14
+ * The visual style variant of the button
15
+ * @default 'solid'
16
+ */
17
+ variant?: ButtonVariant;
18
+ /**
19
+ * The type theme of the button
20
+ * @default 'primary'
21
+ */
22
+ type?: ButtonType;
23
+ /**
24
+ * Custom hex, rgb, or css color string that overrides the type colors
25
+ */
26
+ color?: string;
27
+ /**
28
+ * The size of the button
29
+ * @default 'md'
30
+ */
31
+ size?: 'sm' | 'md' | 'lg';
32
+ /**
33
+ * Whether the button should take full width of its container
34
+ * @default false
35
+ */
36
+ fullWidth?: boolean;
37
+ /**
38
+ * Whether the button is in a loading state
39
+ * @default false
40
+ */
41
+ loading?: boolean;
42
+ /**
43
+ * Optional text shown while loading.
44
+ */
45
+ loadingText?: React.ReactNode;
46
+ /**
47
+ * Whether the button should show temporary success feedback.
48
+ */
49
+ success?: boolean;
50
+ /**
51
+ * Optional text shown in success state.
52
+ */
53
+ successText?: React.ReactNode;
54
+ /**
55
+ * Optional icon shown in success state.
56
+ */
57
+ successIcon?: React.ReactNode;
58
+ /**
59
+ * Duration in milliseconds before success state resets.
60
+ * @default 1500
61
+ */
62
+ successDuration?: number;
63
+ /**
64
+ * Element to place before the children.
65
+ */
66
+ startIcon?: React.ReactNode;
67
+ /**
68
+ * Element to place after the children.
69
+ */
70
+ endIcon?: React.ReactNode;
71
+ }
72
+ /**
73
+ * Primary UI component for user interaction
74
+ *
75
+ * Supports all standard HTML button attributes including `style` and `className`.
76
+ * - Use `type` and `variant` for standard theming.
77
+ * - Use `className` with Tailwind classes for one-off overrides (merged intelligently).
78
+ * - Use `style` for inline dynamic styles.
79
+ */
80
+ declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLButtonElement>>;
81
+
82
+ type IconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
83
+ type IconColor = 'primary' | 'secondary' | 'accent' | 'neutral' | 'info' | 'success' | 'warning' | 'error' | 'current';
84
+ type IconName = keyof typeof LucideIcons;
85
+ interface IconProps extends Omit<react__default.SVGProps<SVGSVGElement>, 'color'> {
86
+ /** The icon component to render (e.g., from Phosphor, Heroicons, Radix, etc.) */
87
+ icon?: react__default.ElementType;
88
+ /** The name of the Lucide icon to render (backward compatibility) */
89
+ name?: IconName;
90
+ /** Size of the icon */
91
+ size?: IconSize;
92
+ /** Color of the icon. Can be a theme color (e.g., 'primary') or any valid CSS color string. */
93
+ color?: IconColor | string;
94
+ }
95
+ declare const Icon: react__default.ForwardRefExoticComponent<Omit<IconProps, "ref"> & react__default.RefAttributes<SVGSVGElement>>;
96
+
97
+ export { Button, type ButtonProps, type ComponentProps, type ComponentVariants, Icon, type IconProps };