@papernote/ui 1.10.13 → 1.10.15
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/components/CollapsibleSection.d.ts +68 -0
- package/dist/components/CollapsibleSection.d.ts.map +1 -0
- package/dist/components/PriorityAlertBanner.d.ts +58 -0
- package/dist/components/PriorityAlertBanner.d.ts.map +1 -0
- package/dist/components/SummaryCard.d.ts +88 -0
- package/dist/components/SummaryCard.d.ts.map +1 -0
- package/dist/components/index.d.ts +6 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/index.d.ts +211 -2
- package/dist/index.esm.js +411 -97
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +411 -94
- package/dist/index.js.map +1 -1
- package/dist/styles.css +20 -0
- package/package.json +1 -1
- package/src/components/AchievementBadge.stories.tsx +3 -3
- package/src/components/AchievementUnlock.stories.tsx +3 -3
- package/src/components/ActivityFeed.stories.tsx +1 -1
- package/src/components/CollaboratorAvatars.stories.tsx +1 -1
- package/src/components/CollapsibleSection.tsx +219 -0
- package/src/components/MotivationalMessage.stories.tsx +2 -2
- package/src/components/PermissionBadge.stories.tsx +1 -1
- package/src/components/PriorityAlertBanner.tsx +219 -0
- package/src/components/ProgressCelebration.stories.tsx +5 -5
- package/src/components/SharedBadge.stories.tsx +1 -1
- package/src/components/StreakBadge.stories.tsx +3 -3
- package/src/components/SuccessCheck.stories.tsx +3 -3
- package/src/components/SummaryCard.tsx +255 -0
- package/src/components/Text.stories.tsx +1 -1
- package/src/components/index.ts +9 -0
package/dist/index.js
CHANGED
|
@@ -9370,6 +9370,370 @@ function Collapsible({ trigger, children, defaultOpen = false, open: controlledO
|
|
|
9370
9370
|
` }))] }), jsxRuntime.jsx("div", { id: "collapsible-content", ref: contentRef, className: "overflow-hidden transition-all duration-300 ease-in-out", style: { height: `${height}px` }, "aria-hidden": !isOpen, children: jsxRuntime.jsx("div", { className: contentClassName, children: children }) })] }));
|
|
9371
9371
|
}
|
|
9372
9372
|
|
|
9373
|
+
function Badge({ children, variant = 'neutral', size = 'md', icon, onRemove, className = '', dot = false, pill = false, truncate = false, maxWidth, animate = false, }) {
|
|
9374
|
+
const variantStyles = {
|
|
9375
|
+
success: 'bg-success-50 text-success-700 border-success-200',
|
|
9376
|
+
warning: 'bg-warning-50 text-warning-700 border-warning-200',
|
|
9377
|
+
error: 'bg-error-50 text-error-700 border-error-200',
|
|
9378
|
+
info: 'bg-primary-50 text-primary-700 border-primary-200',
|
|
9379
|
+
neutral: 'bg-paper-100 text-ink-700 border-paper-300',
|
|
9380
|
+
};
|
|
9381
|
+
const dotVariantStyles = {
|
|
9382
|
+
success: 'bg-success-500',
|
|
9383
|
+
warning: 'bg-warning-500',
|
|
9384
|
+
error: 'bg-error-500',
|
|
9385
|
+
info: 'bg-primary-500',
|
|
9386
|
+
neutral: 'bg-ink-400',
|
|
9387
|
+
};
|
|
9388
|
+
const sizeStyles = {
|
|
9389
|
+
sm: 'px-2 py-0.5 text-xs gap-1',
|
|
9390
|
+
md: 'px-3 py-1 text-xs gap-1.5',
|
|
9391
|
+
lg: 'px-3 py-1.5 text-sm gap-2',
|
|
9392
|
+
};
|
|
9393
|
+
// Pill variant has tighter horizontal padding and fully rounded ends
|
|
9394
|
+
const pillSizeStyles = {
|
|
9395
|
+
sm: 'px-1.5 py-0.5 text-xs gap-1',
|
|
9396
|
+
md: 'px-2 py-0.5 text-xs gap-1',
|
|
9397
|
+
lg: 'px-2.5 py-1 text-sm gap-1.5',
|
|
9398
|
+
};
|
|
9399
|
+
const dotSizeStyles = {
|
|
9400
|
+
sm: 'h-1.5 w-1.5',
|
|
9401
|
+
md: 'h-2 w-2',
|
|
9402
|
+
lg: 'h-2.5 w-2.5',
|
|
9403
|
+
};
|
|
9404
|
+
const iconSize = {
|
|
9405
|
+
sm: 'h-3 w-3',
|
|
9406
|
+
md: 'h-3.5 w-3.5',
|
|
9407
|
+
lg: 'h-4 w-4',
|
|
9408
|
+
};
|
|
9409
|
+
// Dot variant - just a colored circle
|
|
9410
|
+
if (dot) {
|
|
9411
|
+
return (jsxRuntime.jsx("span", { className: `
|
|
9412
|
+
inline-block rounded-full
|
|
9413
|
+
${dotVariantStyles[variant]}
|
|
9414
|
+
${dotSizeStyles[size]}
|
|
9415
|
+
${animate ? 'animate-fade-in' : ''}
|
|
9416
|
+
${className}
|
|
9417
|
+
`, "aria-label": `${variant} indicator` }));
|
|
9418
|
+
}
|
|
9419
|
+
// Regular badge
|
|
9420
|
+
return (jsxRuntime.jsxs("span", { className: `
|
|
9421
|
+
inline-flex items-center border font-medium whitespace-nowrap
|
|
9422
|
+
${pill ? 'rounded-full' : 'rounded-full'}
|
|
9423
|
+
${variantStyles[variant]}
|
|
9424
|
+
${pill ? pillSizeStyles[size] : sizeStyles[size]}
|
|
9425
|
+
${truncate ? 'max-w-full overflow-hidden' : ''}
|
|
9426
|
+
${animate ? 'animate-fade-in' : ''}
|
|
9427
|
+
${className}
|
|
9428
|
+
`, style: maxWidth ? { maxWidth } : undefined, children: [icon && jsxRuntime.jsx("span", { className: `${iconSize[size]} flex-shrink-0`, children: icon }), jsxRuntime.jsx("span", { className: truncate ? 'truncate' : '', children: children }), onRemove && (jsxRuntime.jsx("button", { onClick: onRemove, className: "ml-1 hover:opacity-70 transition-opacity flex-shrink-0", "aria-label": "Remove badge", children: jsxRuntime.jsx(lucideReact.X, { className: iconSize[size] }) }))] }));
|
|
9429
|
+
}
|
|
9430
|
+
|
|
9431
|
+
/**
|
|
9432
|
+
* CollapsibleSection - A card-style collapsible container for dashboard sections
|
|
9433
|
+
*
|
|
9434
|
+
* Wraps content with a styled header that includes title, optional icon, badge count,
|
|
9435
|
+
* and "View All" navigation. Supports both controlled and uncontrolled modes for
|
|
9436
|
+
* localStorage persistence via onOpenChange callback.
|
|
9437
|
+
*
|
|
9438
|
+
* @example Basic usage
|
|
9439
|
+
* ```tsx
|
|
9440
|
+
* <CollapsibleSection
|
|
9441
|
+
* title="Upcoming Bills"
|
|
9442
|
+
* badge={5}
|
|
9443
|
+
* badgeVariant="warning"
|
|
9444
|
+
* viewAllHref="/bills"
|
|
9445
|
+
* >
|
|
9446
|
+
* <BillsList bills={upcomingBills} />
|
|
9447
|
+
* </CollapsibleSection>
|
|
9448
|
+
* ```
|
|
9449
|
+
*
|
|
9450
|
+
* @example With localStorage persistence
|
|
9451
|
+
* ```tsx
|
|
9452
|
+
* const [isOpen, setIsOpen] = useState(() =>
|
|
9453
|
+
* localStorage.getItem('section-open') !== 'false'
|
|
9454
|
+
* );
|
|
9455
|
+
*
|
|
9456
|
+
* <CollapsibleSection
|
|
9457
|
+
* title="Pending Items"
|
|
9458
|
+
* badge={pendingCount}
|
|
9459
|
+
* open={isOpen}
|
|
9460
|
+
* onOpenChange={(open) => {
|
|
9461
|
+
* setIsOpen(open);
|
|
9462
|
+
* localStorage.setItem('section-open', String(open));
|
|
9463
|
+
* }}
|
|
9464
|
+
* >
|
|
9465
|
+
* {children}
|
|
9466
|
+
* </CollapsibleSection>
|
|
9467
|
+
* ```
|
|
9468
|
+
*/
|
|
9469
|
+
function CollapsibleSection({ title, icon, badge, badgeVariant = 'neutral', viewAllHref, viewAllLabel = 'View All', onViewAll, defaultOpen = true, open: controlledOpen, onOpenChange, children, className = '', }) {
|
|
9470
|
+
const isControlled = controlledOpen !== undefined;
|
|
9471
|
+
const [internalOpen, setInternalOpen] = React.useState(defaultOpen);
|
|
9472
|
+
const isOpen = isControlled ? controlledOpen : internalOpen;
|
|
9473
|
+
const contentRef = React.useRef(null);
|
|
9474
|
+
const [height, setHeight] = React.useState(0);
|
|
9475
|
+
const handleToggle = () => {
|
|
9476
|
+
const newOpen = !isOpen;
|
|
9477
|
+
if (!isControlled) {
|
|
9478
|
+
setInternalOpen(newOpen);
|
|
9479
|
+
}
|
|
9480
|
+
onOpenChange?.(newOpen);
|
|
9481
|
+
};
|
|
9482
|
+
const handleViewAllClick = (e) => {
|
|
9483
|
+
if (onViewAll) {
|
|
9484
|
+
e.preventDefault();
|
|
9485
|
+
onViewAll();
|
|
9486
|
+
}
|
|
9487
|
+
};
|
|
9488
|
+
// Update height when content changes or open state changes
|
|
9489
|
+
React.useEffect(() => {
|
|
9490
|
+
if (!contentRef.current)
|
|
9491
|
+
return;
|
|
9492
|
+
if (isOpen) {
|
|
9493
|
+
const contentHeight = contentRef.current.scrollHeight;
|
|
9494
|
+
setHeight(contentHeight);
|
|
9495
|
+
}
|
|
9496
|
+
else {
|
|
9497
|
+
setHeight(0);
|
|
9498
|
+
}
|
|
9499
|
+
}, [isOpen, children]);
|
|
9500
|
+
// Recalculate height when window resizes
|
|
9501
|
+
React.useEffect(() => {
|
|
9502
|
+
if (!isOpen)
|
|
9503
|
+
return;
|
|
9504
|
+
const handleResize = () => {
|
|
9505
|
+
if (contentRef.current) {
|
|
9506
|
+
setHeight(contentRef.current.scrollHeight);
|
|
9507
|
+
}
|
|
9508
|
+
};
|
|
9509
|
+
window.addEventListener('resize', handleResize);
|
|
9510
|
+
return () => window.removeEventListener('resize', handleResize);
|
|
9511
|
+
}, [isOpen]);
|
|
9512
|
+
const ViewAllContent = (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { children: viewAllLabel }), jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-3.5 w-3.5" })] }));
|
|
9513
|
+
return (jsxRuntime.jsxs("div", { className: `
|
|
9514
|
+
bg-white bg-subtle-grain border-2 border-paper-300 rounded-xl shadow-sm
|
|
9515
|
+
${className}
|
|
9516
|
+
`, children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-5 py-4 border-b border-paper-200", children: [jsxRuntime.jsxs("button", { type: "button", onClick: handleToggle, className: "flex items-center gap-3 text-left flex-1 min-w-0 group", "aria-expanded": isOpen, children: [jsxRuntime.jsx(lucideReact.ChevronDown, { className: `
|
|
9517
|
+
h-5 w-5 text-ink-400 transition-transform duration-200 flex-shrink-0
|
|
9518
|
+
group-hover:text-ink-600
|
|
9519
|
+
${isOpen ? 'rotate-0' : '-rotate-90'}
|
|
9520
|
+
` }), icon && (jsxRuntime.jsx("span", { className: "flex-shrink-0 text-ink-500", children: icon })), jsxRuntime.jsx("span", { className: "font-medium text-ink-900 truncate", children: title }), badge !== undefined && (jsxRuntime.jsx(Badge, { variant: badgeVariant, size: "sm", pill: true, children: badge }))] }), (viewAllHref || onViewAll) && (viewAllHref ? (jsxRuntime.jsx(reactRouterDom.Link, { to: viewAllHref, onClick: onViewAll ? handleViewAllClick : undefined, className: "flex items-center gap-1.5 text-sm text-primary-600 hover:text-primary-700 font-medium flex-shrink-0 ml-4", children: ViewAllContent })) : (jsxRuntime.jsx("button", { onClick: onViewAll, className: "flex items-center gap-1.5 text-sm text-primary-600 hover:text-primary-700 font-medium flex-shrink-0 ml-4", children: ViewAllContent })))] }), jsxRuntime.jsx("div", { ref: contentRef, className: "overflow-hidden transition-all duration-300 ease-in-out", style: { height: `${height}px` }, "aria-hidden": !isOpen, children: jsxRuntime.jsx("div", { className: "p-5", children: children }) })] }));
|
|
9521
|
+
}
|
|
9522
|
+
|
|
9523
|
+
/**
|
|
9524
|
+
* SummaryCard - Dashboard metric card with trend indicators and actions
|
|
9525
|
+
*
|
|
9526
|
+
* Displays a key metric with optional trend indicator, subtitle, and quick actions.
|
|
9527
|
+
* Suitable for dashboard grids showing financial summaries, goal progress, etc.
|
|
9528
|
+
*
|
|
9529
|
+
* @example Basic metric
|
|
9530
|
+
* ```tsx
|
|
9531
|
+
* <SummaryCard
|
|
9532
|
+
* title="Net Worth"
|
|
9533
|
+
* icon={<Wallet className="h-5 w-5" />}
|
|
9534
|
+
* value={125000}
|
|
9535
|
+
* valuePrefix="$"
|
|
9536
|
+
* trend={{ direction: 'up', value: '12.5%', label: 'vs last month' }}
|
|
9537
|
+
* />
|
|
9538
|
+
* ```
|
|
9539
|
+
*
|
|
9540
|
+
* @example With actions
|
|
9541
|
+
* ```tsx
|
|
9542
|
+
* <SummaryCard
|
|
9543
|
+
* title="Monthly Income"
|
|
9544
|
+
* value="$8,500"
|
|
9545
|
+
* trend={{ direction: 'up', value: '+$500' }}
|
|
9546
|
+
* subtitle="3 income sources"
|
|
9547
|
+
* actions={[
|
|
9548
|
+
* { label: 'View Details', href: '/income' },
|
|
9549
|
+
* { label: 'Add Income', onClick: openAddModal }
|
|
9550
|
+
* ]}
|
|
9551
|
+
* />
|
|
9552
|
+
* ```
|
|
9553
|
+
*
|
|
9554
|
+
* @example Clickable card
|
|
9555
|
+
* ```tsx
|
|
9556
|
+
* <SummaryCard
|
|
9557
|
+
* title="Goals Progress"
|
|
9558
|
+
* value="3/5"
|
|
9559
|
+
* valueSuffix=" completed"
|
|
9560
|
+
* href="/goals"
|
|
9561
|
+
* subtitle="2 goals due this month"
|
|
9562
|
+
* />
|
|
9563
|
+
* ```
|
|
9564
|
+
*/
|
|
9565
|
+
function SummaryCard({ title, icon, value, valuePrefix, valueSuffix, trend, subtitle, href, onClick, actions = [], className = '', loading = false, }) {
|
|
9566
|
+
const isClickable = !!(href || onClick);
|
|
9567
|
+
const handleCardClick = () => {
|
|
9568
|
+
if (onClick) {
|
|
9569
|
+
onClick();
|
|
9570
|
+
}
|
|
9571
|
+
};
|
|
9572
|
+
const handleKeyDown = (e) => {
|
|
9573
|
+
if (isClickable && (e.key === 'Enter' || e.key === ' ')) {
|
|
9574
|
+
e.preventDefault();
|
|
9575
|
+
handleCardClick();
|
|
9576
|
+
}
|
|
9577
|
+
};
|
|
9578
|
+
const getTrendColor = (direction) => {
|
|
9579
|
+
switch (direction) {
|
|
9580
|
+
case 'up':
|
|
9581
|
+
return 'text-success-600';
|
|
9582
|
+
case 'down':
|
|
9583
|
+
return 'text-error-600';
|
|
9584
|
+
case 'neutral':
|
|
9585
|
+
return 'text-ink-500';
|
|
9586
|
+
}
|
|
9587
|
+
};
|
|
9588
|
+
const getTrendIcon = (direction) => {
|
|
9589
|
+
switch (direction) {
|
|
9590
|
+
case 'up':
|
|
9591
|
+
return jsxRuntime.jsx(lucideReact.TrendingUp, { className: "h-4 w-4" });
|
|
9592
|
+
case 'down':
|
|
9593
|
+
return jsxRuntime.jsx(lucideReact.TrendingDown, { className: "h-4 w-4" });
|
|
9594
|
+
case 'neutral':
|
|
9595
|
+
return jsxRuntime.jsx(lucideReact.Minus, { className: "h-4 w-4" });
|
|
9596
|
+
}
|
|
9597
|
+
};
|
|
9598
|
+
const cardContent = (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-3", children: [icon && (jsxRuntime.jsx("span", { className: "flex-shrink-0 text-ink-500", children: icon })), jsxRuntime.jsx("span", { className: "text-sm font-medium text-ink-600 truncate", children: title }), isClickable && (jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4 text-ink-400 ml-auto flex-shrink-0" }))] }), jsxRuntime.jsxs("div", { className: "text-3xl font-semibold text-ink-900 tracking-tight", children: [valuePrefix, typeof value === 'number' ? value.toLocaleString() : value, valueSuffix && (jsxRuntime.jsx("span", { className: "text-lg font-normal text-ink-500", children: valueSuffix }))] }), trend && (jsxRuntime.jsxs("div", { className: `flex items-center gap-1.5 mt-2 text-sm font-medium ${getTrendColor(trend.direction)}`, children: [getTrendIcon(trend.direction), jsxRuntime.jsx("span", { children: trend.value }), trend.label && (jsxRuntime.jsx("span", { className: "text-ink-500 font-normal", children: trend.label }))] })), subtitle && (jsxRuntime.jsx("div", { className: "text-sm text-ink-500 mt-2", children: subtitle })), actions.length > 0 && (jsxRuntime.jsx("div", { className: "flex flex-wrap gap-3 mt-4 pt-3 border-t border-paper-200", children: actions.map((action, index) => {
|
|
9599
|
+
const actionContent = (jsxRuntime.jsx("span", { className: "text-sm font-medium text-primary-600 hover:text-primary-700", children: action.label }));
|
|
9600
|
+
return action.href ? (jsxRuntime.jsx(reactRouterDom.Link, { to: action.href, onClick: (e) => e.stopPropagation(), children: actionContent }, index)) : (jsxRuntime.jsx("button", { onClick: (e) => {
|
|
9601
|
+
e.stopPropagation();
|
|
9602
|
+
action.onClick?.();
|
|
9603
|
+
}, className: "text-sm font-medium text-primary-600 hover:text-primary-700", children: action.label }, index));
|
|
9604
|
+
}) }))] }));
|
|
9605
|
+
const cardProps = {
|
|
9606
|
+
variant: 'compact',
|
|
9607
|
+
loading,
|
|
9608
|
+
className: `${className} ${isClickable ? 'cursor-pointer' : ''}`,
|
|
9609
|
+
hoverable: isClickable,
|
|
9610
|
+
...(onClick && !href && {
|
|
9611
|
+
onClick: handleCardClick,
|
|
9612
|
+
role: 'button',
|
|
9613
|
+
tabIndex: 0,
|
|
9614
|
+
onKeyDown: handleKeyDown,
|
|
9615
|
+
}),
|
|
9616
|
+
};
|
|
9617
|
+
// If href is provided, wrap in Link
|
|
9618
|
+
if (href) {
|
|
9619
|
+
return (jsxRuntime.jsx(reactRouterDom.Link, { to: href, className: "block", children: jsxRuntime.jsx(Card, { ...cardProps, children: cardContent }) }));
|
|
9620
|
+
}
|
|
9621
|
+
return (jsxRuntime.jsx(Card, { ...cardProps, children: cardContent }));
|
|
9622
|
+
}
|
|
9623
|
+
|
|
9624
|
+
/**
|
|
9625
|
+
* PriorityAlertBanner - Displays urgent/action-required alerts
|
|
9626
|
+
*
|
|
9627
|
+
* Shows a stack of priority alerts at the top of a page. Supports multiple
|
|
9628
|
+
* severity levels, dismissible alerts, and navigation to related pages.
|
|
9629
|
+
* Auto-hides when no alerts are present.
|
|
9630
|
+
*
|
|
9631
|
+
* @example Basic usage
|
|
9632
|
+
* ```tsx
|
|
9633
|
+
* <PriorityAlertBanner
|
|
9634
|
+
* alerts={[
|
|
9635
|
+
* { id: '1', severity: 'error', message: 'overdue bills', count: 3, href: '/bills' },
|
|
9636
|
+
* { id: '2', severity: 'warning', message: 'Bank sync failed', dismissible: true }
|
|
9637
|
+
* ]}
|
|
9638
|
+
* onDismiss={(id) => dismissAlert(id)}
|
|
9639
|
+
* />
|
|
9640
|
+
* ```
|
|
9641
|
+
*
|
|
9642
|
+
* @example Sticky at top of page
|
|
9643
|
+
* ```tsx
|
|
9644
|
+
* <PriorityAlertBanner
|
|
9645
|
+
* alerts={alerts}
|
|
9646
|
+
* onDismiss={handleDismiss}
|
|
9647
|
+
* sticky
|
|
9648
|
+
* />
|
|
9649
|
+
* ```
|
|
9650
|
+
*/
|
|
9651
|
+
function PriorityAlertBanner({ alerts, onDismiss, sticky = false, className = '', }) {
|
|
9652
|
+
// Don't render if no alerts
|
|
9653
|
+
if (alerts.length === 0) {
|
|
9654
|
+
return null;
|
|
9655
|
+
}
|
|
9656
|
+
const getSeverityStyles = (severity) => {
|
|
9657
|
+
switch (severity) {
|
|
9658
|
+
case 'error':
|
|
9659
|
+
return {
|
|
9660
|
+
container: 'bg-error-50 border-error-200 text-error-900',
|
|
9661
|
+
icon: jsxRuntime.jsx(lucideReact.AlertCircle, { className: "h-5 w-5 text-error-600 flex-shrink-0" }),
|
|
9662
|
+
hoverBg: 'hover:bg-error-100',
|
|
9663
|
+
dismissHover: 'hover:text-error-700 hover:bg-error-100',
|
|
9664
|
+
};
|
|
9665
|
+
case 'warning':
|
|
9666
|
+
return {
|
|
9667
|
+
container: 'bg-warning-50 border-warning-200 text-warning-900',
|
|
9668
|
+
icon: jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-5 w-5 text-warning-600 flex-shrink-0" }),
|
|
9669
|
+
hoverBg: 'hover:bg-warning-100',
|
|
9670
|
+
dismissHover: 'hover:text-warning-700 hover:bg-warning-100',
|
|
9671
|
+
};
|
|
9672
|
+
case 'info':
|
|
9673
|
+
return {
|
|
9674
|
+
container: 'bg-primary-50 border-primary-200 text-primary-900',
|
|
9675
|
+
icon: jsxRuntime.jsx(lucideReact.Info, { className: "h-5 w-5 text-primary-600 flex-shrink-0" }),
|
|
9676
|
+
hoverBg: 'hover:bg-primary-100',
|
|
9677
|
+
dismissHover: 'hover:text-primary-700 hover:bg-primary-100',
|
|
9678
|
+
};
|
|
9679
|
+
}
|
|
9680
|
+
};
|
|
9681
|
+
const formatAlertContent = (alert) => {
|
|
9682
|
+
const parts = [];
|
|
9683
|
+
if (alert.count !== undefined) {
|
|
9684
|
+
parts.push(alert.count.toString());
|
|
9685
|
+
}
|
|
9686
|
+
if (alert.amount !== undefined) {
|
|
9687
|
+
parts.push(new Intl.NumberFormat('en-US', {
|
|
9688
|
+
style: 'currency',
|
|
9689
|
+
currency: 'USD',
|
|
9690
|
+
}).format(alert.amount));
|
|
9691
|
+
}
|
|
9692
|
+
if (parts.length > 0) {
|
|
9693
|
+
return `${parts.join(' • ')} ${alert.message}`;
|
|
9694
|
+
}
|
|
9695
|
+
return alert.message;
|
|
9696
|
+
};
|
|
9697
|
+
const renderAlert = (alert) => {
|
|
9698
|
+
const styles = getSeverityStyles(alert.severity);
|
|
9699
|
+
const isClickable = !!(alert.href || alert.onClick);
|
|
9700
|
+
const content = formatAlertContent(alert);
|
|
9701
|
+
const alertContent = (jsxRuntime.jsxs("div", { className: "flex items-center gap-3 flex-1 min-w-0", children: [styles.icon, jsxRuntime.jsx("span", { className: "text-sm font-medium truncate", children: content }), isClickable && (jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4 opacity-60 flex-shrink-0" }))] }));
|
|
9702
|
+
const handleClick = (e) => {
|
|
9703
|
+
if (alert.onClick) {
|
|
9704
|
+
e.preventDefault();
|
|
9705
|
+
alert.onClick();
|
|
9706
|
+
}
|
|
9707
|
+
};
|
|
9708
|
+
const handleDismiss = (e) => {
|
|
9709
|
+
e.preventDefault();
|
|
9710
|
+
e.stopPropagation();
|
|
9711
|
+
onDismiss?.(alert.id);
|
|
9712
|
+
};
|
|
9713
|
+
const containerClassName = `
|
|
9714
|
+
flex items-center gap-2 px-4 py-3 border-b last:border-b-0
|
|
9715
|
+
${styles.container}
|
|
9716
|
+
${isClickable ? `cursor-pointer ${styles.hoverBg} transition-colors` : ''}
|
|
9717
|
+
`;
|
|
9718
|
+
const dismissButton = alert.dismissible && onDismiss && (jsxRuntime.jsx("button", { onClick: handleDismiss, className: `
|
|
9719
|
+
p-1 rounded-md opacity-70 hover:opacity-100 transition-all
|
|
9720
|
+
${styles.dismissHover}
|
|
9721
|
+
`, "aria-label": "Dismiss alert", children: jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" }) }));
|
|
9722
|
+
if (alert.href) {
|
|
9723
|
+
return (jsxRuntime.jsxs(reactRouterDom.Link, { to: alert.href, onClick: alert.onClick ? handleClick : undefined, className: containerClassName, children: [alertContent, dismissButton] }, alert.id));
|
|
9724
|
+
}
|
|
9725
|
+
if (alert.onClick) {
|
|
9726
|
+
return (jsxRuntime.jsxs("button", { onClick: handleClick, className: `${containerClassName} w-full text-left`, children: [alertContent, dismissButton] }, alert.id));
|
|
9727
|
+
}
|
|
9728
|
+
return (jsxRuntime.jsxs("div", { className: containerClassName, children: [alertContent, dismissButton] }, alert.id));
|
|
9729
|
+
};
|
|
9730
|
+
return (jsxRuntime.jsx("div", { className: `
|
|
9731
|
+
bg-white border border-paper-300 rounded-lg shadow-sm overflow-hidden
|
|
9732
|
+
${sticky ? 'sticky top-0 z-50' : ''}
|
|
9733
|
+
${className}
|
|
9734
|
+
`, role: "alert", "aria-live": "polite", children: alerts.map(renderAlert) }));
|
|
9735
|
+
}
|
|
9736
|
+
|
|
9373
9737
|
const sizeClasses$2 = {
|
|
9374
9738
|
sm: {
|
|
9375
9739
|
header: 'h-10 px-3',
|
|
@@ -10901,64 +11265,6 @@ function Breadcrumbs({ items, showHome = true }) {
|
|
|
10901
11265
|
})] }));
|
|
10902
11266
|
}
|
|
10903
11267
|
|
|
10904
|
-
function Badge({ children, variant = 'neutral', size = 'md', icon, onRemove, className = '', dot = false, pill = false, truncate = false, maxWidth, animate = false, }) {
|
|
10905
|
-
const variantStyles = {
|
|
10906
|
-
success: 'bg-success-50 text-success-700 border-success-200',
|
|
10907
|
-
warning: 'bg-warning-50 text-warning-700 border-warning-200',
|
|
10908
|
-
error: 'bg-error-50 text-error-700 border-error-200',
|
|
10909
|
-
info: 'bg-primary-50 text-primary-700 border-primary-200',
|
|
10910
|
-
neutral: 'bg-paper-100 text-ink-700 border-paper-300',
|
|
10911
|
-
};
|
|
10912
|
-
const dotVariantStyles = {
|
|
10913
|
-
success: 'bg-success-500',
|
|
10914
|
-
warning: 'bg-warning-500',
|
|
10915
|
-
error: 'bg-error-500',
|
|
10916
|
-
info: 'bg-primary-500',
|
|
10917
|
-
neutral: 'bg-ink-400',
|
|
10918
|
-
};
|
|
10919
|
-
const sizeStyles = {
|
|
10920
|
-
sm: 'px-2 py-0.5 text-xs gap-1',
|
|
10921
|
-
md: 'px-3 py-1 text-xs gap-1.5',
|
|
10922
|
-
lg: 'px-3 py-1.5 text-sm gap-2',
|
|
10923
|
-
};
|
|
10924
|
-
// Pill variant has tighter horizontal padding and fully rounded ends
|
|
10925
|
-
const pillSizeStyles = {
|
|
10926
|
-
sm: 'px-1.5 py-0.5 text-xs gap-1',
|
|
10927
|
-
md: 'px-2 py-0.5 text-xs gap-1',
|
|
10928
|
-
lg: 'px-2.5 py-1 text-sm gap-1.5',
|
|
10929
|
-
};
|
|
10930
|
-
const dotSizeStyles = {
|
|
10931
|
-
sm: 'h-1.5 w-1.5',
|
|
10932
|
-
md: 'h-2 w-2',
|
|
10933
|
-
lg: 'h-2.5 w-2.5',
|
|
10934
|
-
};
|
|
10935
|
-
const iconSize = {
|
|
10936
|
-
sm: 'h-3 w-3',
|
|
10937
|
-
md: 'h-3.5 w-3.5',
|
|
10938
|
-
lg: 'h-4 w-4',
|
|
10939
|
-
};
|
|
10940
|
-
// Dot variant - just a colored circle
|
|
10941
|
-
if (dot) {
|
|
10942
|
-
return (jsxRuntime.jsx("span", { className: `
|
|
10943
|
-
inline-block rounded-full
|
|
10944
|
-
${dotVariantStyles[variant]}
|
|
10945
|
-
${dotSizeStyles[size]}
|
|
10946
|
-
${animate ? 'animate-fade-in' : ''}
|
|
10947
|
-
${className}
|
|
10948
|
-
`, "aria-label": `${variant} indicator` }));
|
|
10949
|
-
}
|
|
10950
|
-
// Regular badge
|
|
10951
|
-
return (jsxRuntime.jsxs("span", { className: `
|
|
10952
|
-
inline-flex items-center border font-medium whitespace-nowrap
|
|
10953
|
-
${pill ? 'rounded-full' : 'rounded-full'}
|
|
10954
|
-
${variantStyles[variant]}
|
|
10955
|
-
${pill ? pillSizeStyles[size] : sizeStyles[size]}
|
|
10956
|
-
${truncate ? 'max-w-full overflow-hidden' : ''}
|
|
10957
|
-
${animate ? 'animate-fade-in' : ''}
|
|
10958
|
-
${className}
|
|
10959
|
-
`, style: maxWidth ? { maxWidth } : undefined, children: [icon && jsxRuntime.jsx("span", { className: `${iconSize[size]} flex-shrink-0`, children: icon }), jsxRuntime.jsx("span", { className: truncate ? 'truncate' : '', children: children }), onRemove && (jsxRuntime.jsx("button", { onClick: onRemove, className: "ml-1 hover:opacity-70 transition-opacity flex-shrink-0", "aria-label": "Remove badge", children: jsxRuntime.jsx(lucideReact.X, { className: iconSize[size] }) }))] }));
|
|
10960
|
-
}
|
|
10961
|
-
|
|
10962
11268
|
const TabsContext = React.createContext(null);
|
|
10963
11269
|
function useTabsContext() {
|
|
10964
11270
|
const context = React.useContext(TabsContext);
|
|
@@ -14417,44 +14723,52 @@ function getAugmentedNamespace(n) {
|
|
|
14417
14723
|
* (A1, A1:C5, ...)
|
|
14418
14724
|
*/
|
|
14419
14725
|
|
|
14420
|
-
|
|
14726
|
+
var collection;
|
|
14727
|
+
var hasRequiredCollection;
|
|
14728
|
+
|
|
14729
|
+
function requireCollection () {
|
|
14730
|
+
if (hasRequiredCollection) return collection;
|
|
14731
|
+
hasRequiredCollection = 1;
|
|
14732
|
+
class Collection {
|
|
14421
14733
|
|
|
14422
|
-
|
|
14423
|
-
|
|
14424
|
-
|
|
14425
|
-
|
|
14426
|
-
|
|
14427
|
-
|
|
14428
|
-
|
|
14429
|
-
|
|
14430
|
-
|
|
14431
|
-
|
|
14432
|
-
|
|
14734
|
+
constructor(data, refs) {
|
|
14735
|
+
if (data == null && refs == null) {
|
|
14736
|
+
this._data = [];
|
|
14737
|
+
this._refs = [];
|
|
14738
|
+
} else {
|
|
14739
|
+
if (data.length !== refs.length)
|
|
14740
|
+
throw Error('Collection: data length should match references length.');
|
|
14741
|
+
this._data = data;
|
|
14742
|
+
this._refs = refs;
|
|
14743
|
+
}
|
|
14744
|
+
}
|
|
14433
14745
|
|
|
14434
|
-
|
|
14435
|
-
|
|
14436
|
-
|
|
14746
|
+
get data() {
|
|
14747
|
+
return this._data;
|
|
14748
|
+
}
|
|
14437
14749
|
|
|
14438
|
-
|
|
14439
|
-
|
|
14440
|
-
|
|
14750
|
+
get refs() {
|
|
14751
|
+
return this._refs;
|
|
14752
|
+
}
|
|
14441
14753
|
|
|
14442
|
-
|
|
14443
|
-
|
|
14444
|
-
|
|
14754
|
+
get length() {
|
|
14755
|
+
return this._data.length;
|
|
14756
|
+
}
|
|
14445
14757
|
|
|
14446
|
-
|
|
14447
|
-
|
|
14448
|
-
|
|
14449
|
-
|
|
14450
|
-
|
|
14451
|
-
|
|
14452
|
-
|
|
14453
|
-
|
|
14454
|
-
|
|
14455
|
-
}
|
|
14758
|
+
/**
|
|
14759
|
+
* Add data and references to this collection.
|
|
14760
|
+
* @param {{}} obj - data
|
|
14761
|
+
* @param {{}} ref - reference
|
|
14762
|
+
*/
|
|
14763
|
+
add(obj, ref) {
|
|
14764
|
+
this._data.push(obj);
|
|
14765
|
+
this._refs.push(ref);
|
|
14766
|
+
}
|
|
14767
|
+
}
|
|
14456
14768
|
|
|
14457
|
-
|
|
14769
|
+
collection = Collection;
|
|
14770
|
+
return collection;
|
|
14771
|
+
}
|
|
14458
14772
|
|
|
14459
14773
|
var helpers;
|
|
14460
14774
|
var hasRequiredHelpers;
|
|
@@ -14463,7 +14777,7 @@ function requireHelpers () {
|
|
|
14463
14777
|
if (hasRequiredHelpers) return helpers;
|
|
14464
14778
|
hasRequiredHelpers = 1;
|
|
14465
14779
|
const FormulaError = requireError();
|
|
14466
|
-
const Collection =
|
|
14780
|
+
const Collection = requireCollection();
|
|
14467
14781
|
|
|
14468
14782
|
const Types = {
|
|
14469
14783
|
NUMBER: 0,
|
|
@@ -24117,7 +24431,7 @@ var engineering = EngineeringFunctions;
|
|
|
24117
24431
|
|
|
24118
24432
|
const FormulaError$b = requireError();
|
|
24119
24433
|
const {FormulaHelpers: FormulaHelpers$8, Types: Types$6, WildCard, Address: Address$3} = requireHelpers();
|
|
24120
|
-
const Collection$2 =
|
|
24434
|
+
const Collection$2 = requireCollection();
|
|
24121
24435
|
const H$5 = FormulaHelpers$8;
|
|
24122
24436
|
|
|
24123
24437
|
const ReferenceFunctions$1 = {
|
|
@@ -35745,7 +36059,7 @@ var parsing = {
|
|
|
35745
36059
|
const FormulaError$4 = requireError();
|
|
35746
36060
|
const {Address: Address$1} = requireHelpers();
|
|
35747
36061
|
const {Prefix: Prefix$1, Postfix: Postfix$1, Infix: Infix$1, Operators: Operators$1} = operators;
|
|
35748
|
-
const Collection$1 =
|
|
36062
|
+
const Collection$1 = requireCollection();
|
|
35749
36063
|
const MAX_ROW$1 = 1048576, MAX_COLUMN$1 = 16384;
|
|
35750
36064
|
const {NotAllInputParsedException} = require$$4;
|
|
35751
36065
|
|
|
@@ -36507,7 +36821,7 @@ var hooks$1 = {
|
|
|
36507
36821
|
const FormulaError$2 = requireError();
|
|
36508
36822
|
const {FormulaHelpers: FormulaHelpers$1, Types, Address} = requireHelpers();
|
|
36509
36823
|
const {Prefix, Postfix, Infix, Operators} = operators;
|
|
36510
|
-
const Collection =
|
|
36824
|
+
const Collection = requireCollection();
|
|
36511
36825
|
const MAX_ROW = 1048576, MAX_COLUMN = 16384;
|
|
36512
36826
|
|
|
36513
36827
|
let Utils$1 = class Utils {
|
|
@@ -61055,6 +61369,7 @@ exports.Chip = Chip;
|
|
|
61055
61369
|
exports.ChipGroup = ChipGroup;
|
|
61056
61370
|
exports.CollaboratorAvatars = CollaboratorAvatars;
|
|
61057
61371
|
exports.Collapsible = Collapsible;
|
|
61372
|
+
exports.CollapsibleSection = CollapsibleSection;
|
|
61058
61373
|
exports.ColorPicker = ColorPicker;
|
|
61059
61374
|
exports.Combobox = Combobox;
|
|
61060
61375
|
exports.ComingSoon = ComingSoon;
|
|
@@ -61142,6 +61457,7 @@ exports.Pagination = Pagination;
|
|
|
61142
61457
|
exports.PasswordInput = PasswordInput;
|
|
61143
61458
|
exports.PermissionBadge = PermissionBadge;
|
|
61144
61459
|
exports.Popover = Popover;
|
|
61460
|
+
exports.PriorityAlertBanner = PriorityAlertBanner;
|
|
61145
61461
|
exports.Progress = Progress;
|
|
61146
61462
|
exports.ProgressCelebration = ProgressCelebration;
|
|
61147
61463
|
exports.PullToRefresh = PullToRefresh;
|
|
@@ -61175,6 +61491,7 @@ exports.StepIndicator = StepIndicator;
|
|
|
61175
61491
|
exports.Stepper = Stepper;
|
|
61176
61492
|
exports.StreakBadge = StreakBadge;
|
|
61177
61493
|
exports.SuccessCheck = SuccessCheck;
|
|
61494
|
+
exports.SummaryCard = SummaryCard;
|
|
61178
61495
|
exports.SwipeActions = SwipeActions;
|
|
61179
61496
|
exports.SwipeableCard = SwipeableCard;
|
|
61180
61497
|
exports.SwipeableListItem = SwipeableListItem;
|