@aereamart/design-system 0.2.0 → 0.3.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/Accordion.d.ts +10 -0
- package/dist/Accordion.js +12 -0
- package/dist/AlertBanner.d.ts +9 -0
- package/dist/AlertBanner.js +21 -0
- package/dist/AppBar.d.ts +7 -0
- package/dist/AppBar.js +5 -0
- package/dist/Avatar.d.ts +6 -0
- package/dist/Avatar.js +20 -0
- package/dist/Badge.js +4 -4
- package/dist/BottomSheet.d.ts +8 -0
- package/dist/BottomSheet.js +24 -0
- package/dist/Breadcrumb.d.ts +8 -0
- package/dist/Breadcrumb.js +9 -0
- package/dist/Button.js +3 -3
- package/dist/Card.d.ts +7 -0
- package/dist/Card.js +6 -0
- package/dist/Checkbox.d.ts +5 -0
- package/dist/Checkbox.js +5 -0
- package/dist/Chip.d.ts +7 -0
- package/dist/Chip.js +15 -0
- package/dist/DataTable.d.ts +15 -0
- package/dist/DataTable.js +7 -0
- package/dist/DatePicker.d.ts +5 -0
- package/dist/DatePicker.js +11 -0
- package/dist/Divider.d.ts +5 -0
- package/dist/Divider.js +11 -0
- package/dist/Drawer.d.ts +10 -0
- package/dist/Drawer.js +24 -0
- package/dist/EmptyState.d.ts +7 -0
- package/dist/EmptyState.js +6 -0
- package/dist/Input.js +3 -3
- package/dist/Link.d.ts +4 -0
- package/dist/Link.js +6 -0
- package/dist/Menu.d.ts +14 -0
- package/dist/Menu.js +29 -0
- package/dist/Modal.js +1 -1
- package/dist/NavigationBar.d.ts +14 -0
- package/dist/NavigationBar.js +22 -0
- package/dist/Pagination.d.ts +7 -0
- package/dist/Pagination.js +24 -0
- package/dist/Popover.d.ts +7 -0
- package/dist/Popover.js +9 -0
- package/dist/Progress.d.ts +8 -0
- package/dist/Progress.js +15 -0
- package/dist/Radio.d.ts +15 -0
- package/dist/Radio.js +8 -0
- package/dist/SegmentedControl.d.ts +13 -0
- package/dist/SegmentedControl.js +18 -0
- package/dist/Select.js +3 -3
- package/dist/Sidebar.d.ts +16 -0
- package/dist/Sidebar.js +19 -0
- package/dist/Slider.d.ts +5 -0
- package/dist/Slider.js +5 -0
- package/dist/Snackbar.d.ts +12 -0
- package/dist/Snackbar.js +20 -0
- package/dist/Switch.d.ts +4 -0
- package/dist/Switch.js +5 -0
- package/dist/Tabs.d.ts +14 -0
- package/dist/Tabs.js +24 -0
- package/dist/Tag.d.ts +6 -0
- package/dist/Tag.js +11 -0
- package/dist/Textarea.js +3 -3
- package/dist/Tooltip.d.ts +7 -0
- package/dist/Tooltip.js +5 -0
- package/dist/TreeView.d.ts +12 -0
- package/dist/TreeView.js +34 -0
- package/dist/index.d.ts +32 -2
- package/dist/index.js +32 -2
- package/package.json +1 -1
- package/src/Accordion.tsx +58 -0
- package/src/AlertBanner.tsx +62 -0
- package/src/AppBar.tsx +29 -0
- package/src/Avatar.tsx +42 -0
- package/src/Badge.tsx +4 -4
- package/src/BottomSheet.tsx +60 -0
- package/src/Breadcrumb.tsx +48 -0
- package/src/Button.tsx +3 -3
- package/src/Card.tsx +39 -0
- package/src/Checkbox.tsx +31 -0
- package/src/Chip.tsx +44 -0
- package/src/DataTable.tsx +64 -0
- package/src/DatePicker.tsx +44 -0
- package/src/Divider.tsx +33 -0
- package/src/Drawer.tsx +71 -0
- package/src/EmptyState.tsx +37 -0
- package/src/Input.tsx +4 -4
- package/src/Link.tsx +22 -0
- package/src/Menu.tsx +73 -0
- package/src/Modal.tsx +3 -3
- package/src/NavigationBar.tsx +68 -0
- package/src/Pagination.tsx +69 -0
- package/src/Popover.tsx +34 -0
- package/src/Progress.tsx +53 -0
- package/src/Radio.tsx +49 -0
- package/src/SegmentedControl.tsx +63 -0
- package/src/Select.tsx +4 -4
- package/src/Sidebar.tsx +73 -0
- package/src/Slider.tsx +33 -0
- package/src/Snackbar.tsx +72 -0
- package/src/Switch.tsx +40 -0
- package/src/Tabs.tsx +77 -0
- package/src/Tag.tsx +29 -0
- package/src/Textarea.tsx +4 -4
- package/src/Tooltip.tsx +25 -0
- package/src/TreeView.tsx +105 -0
- package/src/index.ts +38 -8
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface AccordionItem {
|
|
2
|
+
title: string;
|
|
3
|
+
content: React.ReactNode;
|
|
4
|
+
}
|
|
5
|
+
export interface AccordionProps {
|
|
6
|
+
items: AccordionItem[];
|
|
7
|
+
defaultOpen?: number | null;
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function Accordion({ items, defaultOpen, className }: AccordionProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { ChevronDown } from 'lucide-react';
|
|
4
|
+
import { cn } from './cn';
|
|
5
|
+
export function Accordion({ items, defaultOpen = null, className }) {
|
|
6
|
+
const [open, setOpen] = useState(defaultOpen);
|
|
7
|
+
return (_jsx("div", { className: cn('divide-y divide-slate-200 overflow-hidden rounded-xl border border-slate-200 bg-white', className), children: items.map((item, i) => {
|
|
8
|
+
const isOpen = open === i;
|
|
9
|
+
const uid = `accordion-${i}`;
|
|
10
|
+
return (_jsxs("div", { children: [_jsxs("button", { type: "button", "aria-expanded": isOpen, "aria-controls": `${uid}-panel`, onClick: () => setOpen(isOpen ? null : i), className: "flex w-full items-center justify-between gap-4 px-5 py-4 text-left text-sm font-semibold text-slate-900 transition-colors hover:bg-slate-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-lime-500/40", children: [item.title, _jsx(ChevronDown, { "aria-hidden": "true", className: cn('h-4 w-4 shrink-0 text-slate-400 transition-transform', isOpen && 'rotate-180') })] }), isOpen && (_jsx("div", { id: `${uid}-panel`, role: "region", className: "border-t border-slate-100 px-5 py-4 text-sm leading-relaxed text-slate-600", children: item.content }))] }, uid));
|
|
11
|
+
}) }));
|
|
12
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type AlertTone = 'info' | 'primary' | 'accent' | 'danger' | 'neutral';
|
|
2
|
+
export interface AlertBannerProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
tone?: AlertTone;
|
|
4
|
+
title?: string;
|
|
5
|
+
dismissible?: boolean;
|
|
6
|
+
onDismiss?: () => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function AlertBanner({ tone, title, dismissible, onDismiss, className, children, ...props }: AlertBannerProps): import("react").JSX.Element | null;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Info, AlertTriangle, CheckCircle2, XCircle, X } from 'lucide-react';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { cn } from './cn';
|
|
5
|
+
const toneRecord = {
|
|
6
|
+
info: { wrap: 'border-sky-300 bg-sky-50 text-sky-900', icon: _jsx(Info, { className: "h-4 w-4" }), label: 'Info' },
|
|
7
|
+
primary: { wrap: 'border-lime-300 bg-lime-50 text-lime-900', icon: _jsx(CheckCircle2, { className: "h-4 w-4" }), label: 'Success' },
|
|
8
|
+
accent: { wrap: 'border-purple-300 bg-purple-50 text-purple-900', icon: _jsx(AlertTriangle, { className: "h-4 w-4" }), label: 'Warning' },
|
|
9
|
+
danger: { wrap: 'border-red-300 bg-red-50 text-red-900', icon: _jsx(XCircle, { className: "h-4 w-4" }), label: 'Error' },
|
|
10
|
+
neutral: { wrap: 'border-slate-300 bg-slate-50 text-slate-800', icon: _jsx(Info, { className: "h-4 w-4" }), label: 'Notice' },
|
|
11
|
+
};
|
|
12
|
+
export function AlertBanner({ tone = 'primary', title, dismissible = false, onDismiss, className, children, ...props }) {
|
|
13
|
+
const [hidden, setHidden] = useState(false);
|
|
14
|
+
if (hidden)
|
|
15
|
+
return null;
|
|
16
|
+
const t = toneRecord[tone];
|
|
17
|
+
return (_jsxs("div", { role: "alert", className: cn('flex items-start gap-3 rounded-lg border px-4 py-3 text-sm', t.wrap, className), ...props, children: [_jsx("span", { className: "mt-0.5 shrink-0", "aria-label": t.label, children: t.icon }), _jsxs("div", { className: "min-w-0 flex-1", children: [title && _jsx("p", { className: "font-bold", children: title }), _jsx("div", { className: cn(title && 'mt-0.5 text-sm opacity-90'), children: children })] }), dismissible && (_jsx("button", { type: "button", "aria-label": "Dismiss", onClick: () => {
|
|
18
|
+
setHidden(true);
|
|
19
|
+
onDismiss?.();
|
|
20
|
+
}, className: "-mr-1 -mt-1 shrink-0 rounded-full p-1 hover:bg-black/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-current", children: _jsx(X, { "aria-hidden": "true", className: "h-4 w-4" }) }))] }));
|
|
21
|
+
}
|
package/dist/AppBar.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface AppBarProps extends React.HTMLAttributes<HTMLElement> {
|
|
2
|
+
title: string;
|
|
3
|
+
subtitle?: string;
|
|
4
|
+
leading?: React.ReactNode;
|
|
5
|
+
actions?: React.ReactNode;
|
|
6
|
+
}
|
|
7
|
+
export declare function AppBar({ title, subtitle, leading, actions, className, ...props }: AppBarProps): import("react").JSX.Element;
|
package/dist/AppBar.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from './cn';
|
|
3
|
+
export function AppBar({ title, subtitle, leading, actions, className, ...props }) {
|
|
4
|
+
return (_jsxs("header", { className: cn('flex items-center justify-between gap-4 border-b border-slate-200 bg-white px-6 py-4', className), ...props, children: [_jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [leading, _jsxs("div", { className: "min-w-0", children: [_jsx("h1", { className: "truncate text-lg font-bold text-slate-900", children: title }), subtitle && _jsx("p", { className: "truncate text-sm text-slate-500", children: subtitle })] })] }), actions && _jsx("div", { className: "flex shrink-0 items-center gap-2", children: actions })] }));
|
|
5
|
+
}
|
package/dist/Avatar.d.ts
ADDED
package/dist/Avatar.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from './cn';
|
|
3
|
+
const sizeClasses = {
|
|
4
|
+
sm: 'h-8 w-8 text-xs',
|
|
5
|
+
md: 'h-10 w-10 text-sm',
|
|
6
|
+
lg: 'h-14 w-14 text-lg',
|
|
7
|
+
};
|
|
8
|
+
function initials(name) {
|
|
9
|
+
if (!name)
|
|
10
|
+
return '?';
|
|
11
|
+
return name
|
|
12
|
+
.split(/\s+/)
|
|
13
|
+
.filter(Boolean)
|
|
14
|
+
.slice(0, 2)
|
|
15
|
+
.map(w => w[0]?.toUpperCase() ?? '')
|
|
16
|
+
.join('') || '?';
|
|
17
|
+
}
|
|
18
|
+
export function Avatar({ src, name, size = 'md', className, ...props }) {
|
|
19
|
+
return (_jsx("div", { className: cn('inline-flex shrink-0 select-none items-center justify-center overflow-hidden rounded-full bg-lime-100 font-semibold text-lime-800', sizeClasses[size], className), ...props, children: src ? (_jsx("img", { src: src, alt: name ?? '', className: "h-full w-full object-cover" })) : (_jsx("span", { "aria-hidden": "true", children: initials(name) })) }));
|
|
20
|
+
}
|
package/dist/Badge.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from './cn';
|
|
3
3
|
const variantClasses = {
|
|
4
|
-
danger: 'bg-red-
|
|
5
|
-
primary: 'bg-
|
|
6
|
-
accent: 'bg-
|
|
7
|
-
neutral: 'bg-
|
|
4
|
+
danger: 'bg-red-100 text-red-800',
|
|
5
|
+
primary: 'bg-lime-100 text-lime-800',
|
|
6
|
+
accent: 'bg-purple-100 text-purple-900',
|
|
7
|
+
neutral: 'bg-slate-200 text-slate-700',
|
|
8
8
|
};
|
|
9
9
|
export function Badge({ variant = 'danger', className, ...props }) {
|
|
10
10
|
return (_jsx("span", { className: cn('inline-flex items-center justify-center rounded-full text-[10px] font-bold leading-none', variantClasses[variant], className), ...props }));
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface BottomSheetProps {
|
|
2
|
+
open: boolean;
|
|
3
|
+
onClose: () => void;
|
|
4
|
+
title?: string;
|
|
5
|
+
children?: React.ReactNode;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function BottomSheet({ open, onClose, title, children, className }: BottomSheetProps): import("react").ReactPortal | null;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
import { createPortal } from 'react-dom';
|
|
4
|
+
import { X } from 'lucide-react';
|
|
5
|
+
import { cn } from './cn';
|
|
6
|
+
export function BottomSheet({ open, onClose, title, children, className }) {
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (!open)
|
|
9
|
+
return;
|
|
10
|
+
const onKey = (e) => {
|
|
11
|
+
if (e.key === 'Escape')
|
|
12
|
+
onClose();
|
|
13
|
+
};
|
|
14
|
+
document.body.style.overflow = 'hidden';
|
|
15
|
+
document.addEventListener('keydown', onKey);
|
|
16
|
+
return () => {
|
|
17
|
+
document.body.style.overflow = '';
|
|
18
|
+
document.removeEventListener('keydown', onKey);
|
|
19
|
+
};
|
|
20
|
+
}, [open, onClose]);
|
|
21
|
+
if (!open)
|
|
22
|
+
return null;
|
|
23
|
+
return createPortal(_jsxs("div", { className: "fixed inset-0 z-50 flex items-end justify-center", children: [_jsx("div", { className: "absolute inset-0 bg-black/50", onClick: onClose, "aria-hidden": "true" }), _jsxs("section", { role: "dialog", "aria-modal": "true", "aria-label": title, className: cn('relative w-full max-w-lg rounded-t-2xl bg-white p-6 shadow-xl', className), children: [_jsx("div", { "aria-hidden": "true", className: "mx-auto mb-4 h-1 w-10 rounded-full bg-slate-200" }), title && (_jsxs("div", { className: "mb-2 flex items-center justify-between", children: [_jsx("h2", { className: "text-lg font-bold text-slate-900", children: title }), _jsx("button", { onClick: onClose, className: "rounded-lg p-1 text-slate-400 hover:bg-slate-100", "aria-label": "Close", children: _jsx(X, { className: "h-5 w-5" }) })] })), children] })] }), document.body);
|
|
24
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface Crumb {
|
|
2
|
+
label: string;
|
|
3
|
+
href?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface BreadcrumbProps extends React.HTMLAttributes<HTMLElement> {
|
|
6
|
+
items: Crumb[];
|
|
7
|
+
}
|
|
8
|
+
export declare function Breadcrumb({ items, className, ...props }: BreadcrumbProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ChevronRight } from 'lucide-react';
|
|
3
|
+
import { cn } from './cn';
|
|
4
|
+
export function Breadcrumb({ items, className, ...props }) {
|
|
5
|
+
return (_jsx("nav", { "aria-label": "Breadcrumb", className: className, ...props, children: _jsx("ol", { className: "flex flex-wrap items-center gap-1.5 text-sm", children: items.map((item, i) => {
|
|
6
|
+
const last = i === items.length - 1;
|
|
7
|
+
return (_jsxs("li", { className: "flex items-center gap-1.5", children: [i > 0 && (_jsx(ChevronRight, { "aria-hidden": "true", className: "h-3.5 w-3.5 text-slate-400" })), last || !item.href ? (_jsx("span", { "aria-current": last ? 'page' : undefined, className: cn('font-medium', last ? 'text-slate-900' : 'text-slate-500'), children: item.label })) : (_jsx("a", { href: item.href, className: "font-medium text-lime-700 hover:text-lime-800 hover:underline", children: item.label }))] }, `${item.label}-${i}`));
|
|
8
|
+
}) }) }));
|
|
9
|
+
}
|
package/dist/Button.js
CHANGED
|
@@ -2,10 +2,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { cn } from './cn';
|
|
3
3
|
import { Spinner } from './Spinner';
|
|
4
4
|
const variantClasses = {
|
|
5
|
-
primary: 'bg-
|
|
6
|
-
secondary: 'border border-
|
|
5
|
+
primary: 'bg-lime-600 text-white hover:bg-lime-700 focus-visible:ring-lime-500/40',
|
|
6
|
+
secondary: 'border border-slate-300 bg-white text-slate-700 hover:bg-slate-50 focus-visible:ring-slate-400/40',
|
|
7
7
|
danger: 'bg-red-600 text-white hover:bg-red-700 focus-visible:ring-red-500/40',
|
|
8
|
-
ghost: 'bg-transparent text-
|
|
8
|
+
ghost: 'bg-transparent text-slate-600 hover:bg-slate-100 focus-visible:ring-slate-400/40',
|
|
9
9
|
};
|
|
10
10
|
const sizeClasses = {
|
|
11
11
|
sm: 'px-3 py-1.5 text-xs',
|
package/dist/Card.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
2
|
+
title?: string;
|
|
3
|
+
description?: string;
|
|
4
|
+
footer?: React.ReactNode;
|
|
5
|
+
hoverable?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function Card({ title, description, footer, hoverable, className, children, ...props }: CardProps): import("react").JSX.Element;
|
package/dist/Card.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from './cn';
|
|
3
|
+
export function Card({ title, description, footer, hoverable = false, className, children, ...props }) {
|
|
4
|
+
return (_jsxs("div", { className: cn('rounded-xl border border-slate-200 bg-white', hoverable &&
|
|
5
|
+
'transition-all hover:-translate-y-0.5 hover:border-lime-300 hover:shadow-md', className), ...props, children: [(title || description) && (_jsxs("div", { className: "border-b border-slate-100 px-5 py-4", children: [title && _jsx("h3", { className: "text-base font-bold text-slate-900", children: title }), description && _jsx("p", { className: "mt-0.5 text-sm text-slate-500", children: description })] })), _jsx("div", { className: "px-5 py-4", children: children }), footer && _jsx("div", { className: "border-t border-slate-100 px-5 py-3", children: footer })] }));
|
|
6
|
+
}
|
package/dist/Checkbox.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from './cn';
|
|
3
|
+
export function Checkbox({ label, error, id, className, ...props }) {
|
|
4
|
+
return (_jsxs("div", { className: "grid gap-1.5", children: [_jsxs("label", { htmlFor: id, className: cn('inline-flex cursor-pointer items-start gap-2.5 text-sm', className), children: [_jsx("input", { id: id, type: "checkbox", className: "mt-0.5 h-4 w-4 shrink-0 cursor-pointer rounded border-slate-500 text-lime-600 accent-lime-600 focus:outline-none focus:ring-2 focus:ring-lime-500/40", ...props }), label && (_jsx("span", { className: cn('font-medium', error ? 'text-red-700' : 'text-slate-700'), children: label }))] }), error && _jsx("p", { className: "pl-6.5 text-xs text-red-600", children: error })] }));
|
|
5
|
+
}
|
package/dist/Chip.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type ChipVariant = 'primary' | 'accent' | 'neutral' | 'danger';
|
|
2
|
+
export interface ChipProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
3
|
+
variant?: ChipVariant;
|
|
4
|
+
onRemove?: () => void;
|
|
5
|
+
}
|
|
6
|
+
export declare function Chip({ variant, onRemove, className, children, ...props }: ChipProps): import("react").JSX.Element;
|
|
7
|
+
export {};
|
package/dist/Chip.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { X } from 'lucide-react';
|
|
3
|
+
import { cn } from './cn';
|
|
4
|
+
const variantClasses = {
|
|
5
|
+
primary: 'border-lime-300 bg-lime-50 text-lime-800',
|
|
6
|
+
accent: 'border-purple-300 bg-purple-50 text-purple-900',
|
|
7
|
+
neutral: 'border-slate-300 bg-slate-50 text-slate-700',
|
|
8
|
+
danger: 'border-red-300 bg-red-50 text-red-800',
|
|
9
|
+
};
|
|
10
|
+
export function Chip({ variant = 'neutral', onRemove, className, children, ...props }) {
|
|
11
|
+
return (_jsxs("span", { className: cn('inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-sm font-medium', variantClasses[variant], className), ...props, children: [children, onRemove && (_jsx("button", { type: "button", onClick: e => {
|
|
12
|
+
e.stopPropagation();
|
|
13
|
+
onRemove();
|
|
14
|
+
}, "aria-label": `Remove ${typeof children === 'string' ? children : 'chip'}`, className: "-mr-1 rounded-full p-0.5 hover:bg-black/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-current", children: _jsx(X, { "aria-hidden": "true", className: "h-3 w-3" }) }))] }));
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface Column<T> {
|
|
2
|
+
key: string;
|
|
3
|
+
label: string;
|
|
4
|
+
render?: (row: T) => React.ReactNode;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface DataTableProps<T> {
|
|
8
|
+
columns: Column<T>[];
|
|
9
|
+
rows: T[];
|
|
10
|
+
rowKey: (row: T) => string;
|
|
11
|
+
caption?: string;
|
|
12
|
+
emptyText?: string;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function DataTable<T>({ columns, rows, rowKey, caption, emptyText, className, }: DataTableProps<T>): import("react").JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useId } from 'react';
|
|
3
|
+
import { cn } from './cn';
|
|
4
|
+
export function DataTable({ columns, rows, rowKey, caption, emptyText = 'No rows to show.', className, }) {
|
|
5
|
+
const captionId = useId();
|
|
6
|
+
return (_jsx("div", { className: cn('overflow-x-auto rounded-xl border border-slate-200 bg-white', className), children: _jsxs("table", { className: "w-full min-w-[480px] border-collapse text-left text-sm", children: [caption && _jsx("caption", { className: "sr-only", id: captionId, children: caption }), _jsx("thead", { children: _jsx("tr", { className: "border-b border-slate-200 bg-slate-50 text-xs uppercase tracking-wider text-slate-500", children: columns.map(col => (_jsx("th", { scope: "col", className: "px-4 py-3 font-semibold", children: col.label }, col.key))) }) }), _jsxs("tbody", { className: "divide-y divide-slate-100", children: [rows.map(row => (_jsx("tr", { className: "transition-colors hover:bg-slate-50", children: columns.map(col => (_jsx("td", { className: cn('px-4 py-3 align-middle text-slate-700', col.className), children: col.render ? col.render(row) : String(row[col.key] ?? '') }, col.key))) }, rowKey(row)))), rows.length === 0 && (_jsx("tr", { children: _jsx("td", { colSpan: columns.length, className: "px-4 py-10 text-center text-sm text-slate-400", children: emptyText }) }))] })] }) }));
|
|
7
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useId } from 'react';
|
|
3
|
+
import { CalendarDays } from 'lucide-react';
|
|
4
|
+
import { cn } from './cn';
|
|
5
|
+
export function DatePicker({ label, error, id, className, ...props }) {
|
|
6
|
+
const autoId = useId();
|
|
7
|
+
const inputId = id ?? autoId;
|
|
8
|
+
return (_jsxs("div", { children: [label && (_jsx("label", { htmlFor: inputId, className: "mb-1 block text-sm font-medium text-slate-700", children: label })), _jsxs("div", { className: "relative", children: [_jsx(CalendarDays, { "aria-hidden": "true", className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-400" }), _jsx("input", { id: inputId, type: "date", className: cn('w-full rounded-lg border bg-white py-2.5 pl-9 pr-4 text-sm text-slate-700 shadow-xs', 'focus:outline-none focus:ring-2 focus:ring-lime-500/40 disabled:cursor-not-allowed disabled:bg-slate-100 disabled:text-slate-400', error
|
|
9
|
+
? 'border-red-400 focus:border-red-500'
|
|
10
|
+
: 'border-slate-300 hover:border-slate-400', className), ...props })] }), error && _jsx("p", { className: "mt-1 text-xs text-red-600", children: error })] }));
|
|
11
|
+
}
|
package/dist/Divider.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from './cn';
|
|
3
|
+
export function Divider({ orientation = 'horizontal', label, className, ...props }) {
|
|
4
|
+
if (orientation === 'vertical') {
|
|
5
|
+
return (_jsx("div", { role: "separator", "aria-orientation": "vertical", className: cn('mx-3 my-0 h-auto w-px shrink-0 self-stretch bg-slate-200', className), ...props }));
|
|
6
|
+
}
|
|
7
|
+
if (label) {
|
|
8
|
+
return (_jsxs("div", { className: cn('flex items-center gap-3', className), ...props, children: [_jsx("div", { className: "h-px flex-1 bg-slate-200" }), _jsx("span", { className: "text-xs font-medium uppercase tracking-wider text-slate-400", children: label }), _jsx("div", { className: "h-px flex-1 bg-slate-200" })] }));
|
|
9
|
+
}
|
|
10
|
+
return (_jsx("div", { role: "separator", className: cn('h-px w-full bg-slate-200', className), ...props }));
|
|
11
|
+
}
|
package/dist/Drawer.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface DrawerProps {
|
|
2
|
+
open: boolean;
|
|
3
|
+
onClose: () => void;
|
|
4
|
+
title?: string;
|
|
5
|
+
side?: 'right' | 'left';
|
|
6
|
+
children?: React.ReactNode;
|
|
7
|
+
footer?: React.ReactNode;
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function Drawer({ open, onClose, title, side, children, footer, className, }: DrawerProps): import("react").ReactPortal | null;
|
package/dist/Drawer.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
import { createPortal } from 'react-dom';
|
|
4
|
+
import { X } from 'lucide-react';
|
|
5
|
+
import { cn } from './cn';
|
|
6
|
+
export function Drawer({ open, onClose, title, side = 'right', children, footer, className, }) {
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (!open)
|
|
9
|
+
return;
|
|
10
|
+
const onKey = (e) => {
|
|
11
|
+
if (e.key === 'Escape')
|
|
12
|
+
onClose();
|
|
13
|
+
};
|
|
14
|
+
document.body.style.overflow = 'hidden';
|
|
15
|
+
document.addEventListener('keydown', onKey);
|
|
16
|
+
return () => {
|
|
17
|
+
document.body.style.overflow = '';
|
|
18
|
+
document.removeEventListener('keydown', onKey);
|
|
19
|
+
};
|
|
20
|
+
}, [open, onClose]);
|
|
21
|
+
if (!open)
|
|
22
|
+
return null;
|
|
23
|
+
return createPortal(_jsxs("div", { className: "fixed inset-0 z-50", children: [_jsx("div", { className: "absolute inset-0 bg-black/50", onClick: onClose, "aria-hidden": "true" }), _jsxs("section", { role: "dialog", "aria-modal": "true", "aria-label": title, className: cn('absolute inset-y-0 flex w-full max-w-sm flex-col bg-white shadow-xl', side === 'right' ? 'right-0' : 'left-0', className), children: [title && (_jsxs("div", { className: "flex items-center justify-between border-b border-slate-100 px-6 py-4", children: [_jsx("h2", { className: "text-lg font-bold text-slate-900", children: title }), _jsx("button", { onClick: onClose, className: "rounded-lg p-1 text-slate-400 hover:bg-slate-100", "aria-label": "Close", children: _jsx(X, { className: "h-5 w-5" }) })] })), _jsx("div", { className: "flex-1 overflow-y-auto px-6 py-4", children: children }), footer && _jsx("div", { className: "border-t border-slate-100 px-6 py-4", children: footer })] })] }), document.body);
|
|
24
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface EmptyStateProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
2
|
+
title: string;
|
|
3
|
+
description?: string;
|
|
4
|
+
icon?: React.ReactNode;
|
|
5
|
+
action?: React.ReactNode;
|
|
6
|
+
}
|
|
7
|
+
export declare function EmptyState({ title, description, icon, action, className, ...props }: EmptyStateProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Inbox } from 'lucide-react';
|
|
3
|
+
import { cn } from './cn';
|
|
4
|
+
export function EmptyState({ title, description, icon, action, className, ...props }) {
|
|
5
|
+
return (_jsxs("div", { className: cn('flex flex-col items-center justify-center rounded-xl border-2 border-dashed border-slate-200 bg-white px-8 py-12 text-center', className), ...props, children: [_jsx("div", { className: "mb-3 rounded-full bg-lime-50 p-3 text-lime-600", children: icon ?? _jsx(Inbox, { "aria-hidden": "true", className: "h-8 w-8" }) }), _jsx("h3", { className: "text-base font-bold text-slate-900", children: title }), description && (_jsx("p", { className: "mt-1 max-w-sm text-sm text-slate-500", children: description })), action && _jsx("div", { className: "mt-5", children: action })] }));
|
|
6
|
+
}
|
package/dist/Input.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from './cn';
|
|
3
3
|
export function Input({ label, error, className, id, ...props }) {
|
|
4
|
-
return (_jsxs("div", { className: "w-full", children: [label && (_jsx("label", { htmlFor: id, className: "mb-1 block text-sm font-medium text-
|
|
5
|
-
? 'border-red-
|
|
6
|
-
: 'border-
|
|
4
|
+
return (_jsxs("div", { className: "w-full", children: [label && (_jsx("label", { htmlFor: id, className: "mb-1 block text-sm font-medium text-slate-700", children: label })), _jsx("input", { id: id, className: cn('w-full rounded-lg border bg-white px-4 py-2.5 text-sm text-slate-900 placeholder:text-slate-500 focus:outline-none focus:ring-2', error
|
|
5
|
+
? 'border-red-600 focus:border-red-600 focus:ring-red-500/30'
|
|
6
|
+
: 'border-slate-500 focus:border-lime-600 focus:ring-lime-500/30', className), ...props }), error && _jsx("p", { className: "mt-1 text-xs text-red-600", children: error })] }));
|
|
7
7
|
}
|
package/dist/Link.d.ts
ADDED
package/dist/Link.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ExternalLink } from 'lucide-react';
|
|
3
|
+
import { cn } from './cn';
|
|
4
|
+
export function Link({ external = false, className, children, ...props }) {
|
|
5
|
+
return (_jsxs("a", { className: cn('inline-flex items-center gap-1 font-medium text-lime-700 hover:text-lime-800 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-lime-500/40 rounded-sm', className), ...(external ? { target: '_blank', rel: 'noreferrer' } : {}), ...props, children: [children, external && _jsx(ExternalLink, { "aria-hidden": "true", className: "h-3.5 w-3.5" })] }));
|
|
6
|
+
}
|
package/dist/Menu.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface MenuItem {
|
|
2
|
+
label: string;
|
|
3
|
+
onSelect?: () => void;
|
|
4
|
+
danger?: boolean;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
icon?: React.ReactNode;
|
|
7
|
+
}
|
|
8
|
+
export interface MenuProps {
|
|
9
|
+
trigger: React.ReactNode;
|
|
10
|
+
items: MenuItem[];
|
|
11
|
+
align?: 'start' | 'end';
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function Menu({ trigger, items, align, className }: MenuProps): import("react").JSX.Element;
|
package/dist/Menu.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { cn } from './cn';
|
|
4
|
+
export function Menu({ trigger, items, align = 'end', className }) {
|
|
5
|
+
const [open, setOpen] = useState(false);
|
|
6
|
+
const ref = useRef(null);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (!open)
|
|
9
|
+
return;
|
|
10
|
+
const onDown = (e) => {
|
|
11
|
+
if (ref.current && !ref.current.contains(e.target))
|
|
12
|
+
setOpen(false);
|
|
13
|
+
};
|
|
14
|
+
const onKey = (e) => {
|
|
15
|
+
if (e.key === 'Escape')
|
|
16
|
+
setOpen(false);
|
|
17
|
+
};
|
|
18
|
+
document.addEventListener('mousedown', onDown);
|
|
19
|
+
document.addEventListener('keydown', onKey);
|
|
20
|
+
return () => {
|
|
21
|
+
document.removeEventListener('mousedown', onDown);
|
|
22
|
+
document.removeEventListener('keydown', onKey);
|
|
23
|
+
};
|
|
24
|
+
}, [open]);
|
|
25
|
+
return (_jsxs("div", { ref: ref, className: cn('relative inline-flex', className), children: [_jsx("div", { onClick: () => setOpen(v => !v), children: trigger }), open && (_jsx("div", { role: "menu", className: cn('absolute z-50 mt-1.5 min-w-40 overflow-hidden rounded-lg border border-slate-200 bg-white py-1 shadow-lg', align === 'end' ? 'right-0' : 'left-0'), children: items.map((item, i) => (_jsxs("button", { type: "button", role: "menuitem", disabled: item.disabled, onClick: () => {
|
|
26
|
+
setOpen(false);
|
|
27
|
+
item.onSelect?.();
|
|
28
|
+
}, className: cn('flex w-full items-center gap-2.5 px-4 py-2 text-left text-sm transition-colors disabled:opacity-50 focus-visible:outline-none focus-visible:bg-slate-100', item.danger ? 'text-red-700 hover:bg-red-50' : 'text-slate-700 hover:bg-slate-50'), children: [item.icon, _jsx("span", { className: "flex-1", children: item.label })] }, `${item.label}-${i}`))) }))] }));
|
|
29
|
+
}
|
package/dist/Modal.js
CHANGED
|
@@ -20,5 +20,5 @@ export function Modal({ open, onClose, title, children, className, maxWidth = 'm
|
|
|
20
20
|
}, [open, onClose]);
|
|
21
21
|
if (!open)
|
|
22
22
|
return null;
|
|
23
|
-
return createPortal(_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4", children: _jsxs("div", { className: cn('w-full rounded-2xl bg-white shadow-xl', maxWidth, className), role: "dialog", "aria-modal": "true", children: [title && (_jsxs("div", { className: "flex items-center justify-between border-b border-
|
|
23
|
+
return createPortal(_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4", children: _jsxs("div", { className: cn('w-full rounded-2xl bg-white shadow-xl', maxWidth, className), role: "dialog", "aria-modal": "true", children: [title && (_jsxs("div", { className: "flex items-center justify-between border-b border-slate-100 px-6 py-4", children: [_jsx("h2", { className: "text-lg font-bold text-slate-900", children: title }), _jsx("button", { onClick: onClose, className: "rounded-lg p-1 text-slate-400 hover:bg-slate-100", "aria-label": "Close", children: _jsx(X, { className: "h-5 w-5" }) })] })), children] }) }), document.body);
|
|
24
24
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface NavItem {
|
|
2
|
+
value: string;
|
|
3
|
+
label: string;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface NavigationBarProps {
|
|
7
|
+
items: NavItem[];
|
|
8
|
+
value?: string;
|
|
9
|
+
defaultValue?: string;
|
|
10
|
+
onChange?: (value: string) => void;
|
|
11
|
+
variant?: 'pills' | 'links';
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function NavigationBar({ items, value, defaultValue, onChange, variant, className, }: NavigationBarProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { cn } from './cn';
|
|
4
|
+
export function NavigationBar({ items, value, defaultValue, onChange, variant = 'links', className, }) {
|
|
5
|
+
const isControlled = value !== undefined;
|
|
6
|
+
const [inner, setInner] = useState(defaultValue);
|
|
7
|
+
const active = isControlled ? value : inner;
|
|
8
|
+
return (_jsx("nav", { "aria-label": "Primary", className: cn('flex items-center gap-1', className), children: items.map(item => {
|
|
9
|
+
const selected = active === item.value;
|
|
10
|
+
return (_jsx("button", { type: "button", "aria-current": selected ? 'page' : undefined, disabled: item.disabled, onClick: () => {
|
|
11
|
+
if (!isControlled)
|
|
12
|
+
setInner(item.value);
|
|
13
|
+
onChange?.(item.value);
|
|
14
|
+
}, className: cn('px-4 py-2 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-lime-500/40 disabled:opacity-50', variant === 'pills'
|
|
15
|
+
? cn('rounded-lg', selected
|
|
16
|
+
? 'bg-lime-600 text-white'
|
|
17
|
+
: 'text-slate-600 hover:bg-slate-100 hover:text-slate-900')
|
|
18
|
+
: cn('border-b-2', selected
|
|
19
|
+
? 'border-lime-600 text-lime-700'
|
|
20
|
+
: 'border-transparent text-slate-500 hover:text-slate-900')), children: item.label }, item.value));
|
|
21
|
+
}) }));
|
|
22
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
|
3
|
+
import { cn } from './cn';
|
|
4
|
+
import { Button } from './Button';
|
|
5
|
+
function pageList(page, total) {
|
|
6
|
+
if (total <= 7)
|
|
7
|
+
return Array.from({ length: total }, (_, i) => i + 1);
|
|
8
|
+
const pages = [1];
|
|
9
|
+
const start = Math.max(2, page - 1);
|
|
10
|
+
const end = Math.min(total - 1, page + 1);
|
|
11
|
+
if (start > 2)
|
|
12
|
+
pages.push('…');
|
|
13
|
+
for (let i = start; i <= end; i++)
|
|
14
|
+
pages.push(i);
|
|
15
|
+
if (end < total - 1)
|
|
16
|
+
pages.push('…');
|
|
17
|
+
pages.push(total);
|
|
18
|
+
return pages;
|
|
19
|
+
}
|
|
20
|
+
export function Pagination({ page, totalPages, onChange, className }) {
|
|
21
|
+
return (_jsxs("nav", { "aria-label": "Pagination", className: cn('flex items-center gap-1', className), children: [_jsx(Button, { variant: "ghost", size: "sm", disabled: page <= 1, onClick: () => onChange(page - 1), "aria-label": "Previous page", children: _jsx(ChevronLeft, { className: "h-4 w-4" }) }), pageList(page, totalPages).map((p, i) => p === '…' ? (_jsx("span", { className: "px-1.5 text-sm text-slate-400", children: "\u00E2\u20AC\u00A6" }, `e-${i}`)) : (_jsx("button", { type: "button", onClick: () => onChange(p), "aria-current": p === page ? 'page' : undefined, className: cn('h-8 min-w-8 rounded-lg px-2 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-lime-500/40', p === page
|
|
22
|
+
? 'bg-lime-600 text-white'
|
|
23
|
+
: 'text-slate-600 hover:bg-slate-100 hover:text-slate-900'), children: p }, p))), _jsx(Button, { variant: "ghost", size: "sm", disabled: page >= totalPages, onClick: () => onChange(page + 1), "aria-label": "Next page", children: _jsx(ChevronRight, { className: "h-4 w-4" }) })] }));
|
|
24
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface PopoverProps {
|
|
2
|
+
trigger: React.ReactNode;
|
|
3
|
+
content: React.ReactNode;
|
|
4
|
+
side?: 'top' | 'bottom' | 'left' | 'right';
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function Popover({ trigger, content, side, className }: PopoverProps): import("react").JSX.Element;
|
package/dist/Popover.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from './cn';
|
|
3
|
+
export function Popover({ trigger, content, side = 'bottom', className }) {
|
|
4
|
+
const isTop = side === 'top';
|
|
5
|
+
const isBottom = side === 'bottom';
|
|
6
|
+
const isLeft = side === 'left';
|
|
7
|
+
const isRight = side === 'right';
|
|
8
|
+
return (_jsxs("span", { className: "group relative inline-flex", children: [trigger, _jsx("span", { role: "tooltip", className: cn('pointer-events-none absolute z-50 w-64 rounded-xl border border-slate-200 bg-white p-4 text-sm text-slate-700 opacity-0 shadow-lg transition-opacity duration-200 group-hover:opacity-100 group-focus-within:opacity-100', isBottom && 'left-1/2 top-full mt-2 -translate-x-1/2', isTop && 'bottom-full left-1/2 mb-2 -translate-x-1/2', isLeft && 'right-full top-1/2 mr-2 -translate-y-1/2', isRight && 'left-full top-1/2 ml-2 -translate-y-1/2', className), children: content })] }));
|
|
9
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface ProgressProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
2
|
+
value: number;
|
|
3
|
+
max?: number;
|
|
4
|
+
size?: 'sm' | 'md';
|
|
5
|
+
tone?: 'primary' | 'accent' | 'danger';
|
|
6
|
+
showLabel?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function Progress({ value, max, size, tone, showLabel, className, ...props }: ProgressProps): import("react").JSX.Element;
|
package/dist/Progress.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from './cn';
|
|
3
|
+
const track = {
|
|
4
|
+
sm: 'h-1.5',
|
|
5
|
+
md: 'h-2.5',
|
|
6
|
+
};
|
|
7
|
+
const fill = {
|
|
8
|
+
primary: 'bg-lime-600',
|
|
9
|
+
accent: 'bg-purple-600',
|
|
10
|
+
danger: 'bg-red-600',
|
|
11
|
+
};
|
|
12
|
+
export function Progress({ value, max = 100, size = 'md', tone = 'primary', showLabel = false, className, ...props }) {
|
|
13
|
+
const pct = max > 0 ? Math.min(100, Math.max(0, (value / max) * 100)) : 0;
|
|
14
|
+
return (_jsxs("div", { className: cn('flex items-center gap-3', className), ...props, children: [_jsx("div", { role: "progressbar", "aria-valuenow": value, "aria-valuemin": 0, "aria-valuemax": max, className: cn('w-full overflow-hidden rounded-full bg-slate-200', track[size]), children: _jsx("div", { className: cn('h-full rounded-full transition-all duration-300', fill[tone]), style: { width: `${pct}%` } }) }), showLabel && (_jsxs("span", { className: "w-10 shrink-0 text-right text-xs font-semibold tabular-nums text-slate-600", children: [Math.round(pct), "%"] }))] }));
|
|
15
|
+
}
|
package/dist/Radio.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface RadioProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type'> {
|
|
2
|
+
label?: string;
|
|
3
|
+
}
|
|
4
|
+
export declare function Radio({ label, id, className, ...props }: RadioProps): import("react").JSX.Element;
|
|
5
|
+
export interface RadioGroupProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {
|
|
6
|
+
name: string;
|
|
7
|
+
value?: string | number;
|
|
8
|
+
onChange?: (value: string) => void;
|
|
9
|
+
options: {
|
|
10
|
+
value: string;
|
|
11
|
+
label: string;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
}[];
|
|
14
|
+
}
|
|
15
|
+
export declare function RadioGroup({ name, value, onChange, options, className, ...props }: RadioGroupProps): import("react").JSX.Element;
|