@papernote/ui 1.11.6 → 1.13.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.js CHANGED
@@ -5418,7 +5418,7 @@ function SharedBadge({ sharedWith, variant, size = 'md', maxDisplay = 3, onClick
5418
5418
  }
5419
5419
 
5420
5420
  // Format relative time
5421
- function formatRelativeTime$1(date) {
5421
+ function formatRelativeTime$3(date) {
5422
5422
  const now = new Date();
5423
5423
  const diffMs = now.getTime() - date.getTime();
5424
5424
  const diffMins = Math.floor(diffMs / 60000);
@@ -5450,11 +5450,11 @@ function ActivityFeed({ activities, maxItems, showTimestamps = true, onLoadMore,
5450
5450
  if (activities.length === 0) {
5451
5451
  return (jsxRuntime.jsxs("div", { className: `text-center py-8 ${className}`, children: [jsxRuntime.jsx(lucideReact.Activity, { className: "w-8 h-8 text-ink-300 mx-auto mb-2" }), jsxRuntime.jsx("p", { className: "text-ink-500 text-sm", children: "No activity yet" })] }));
5452
5452
  }
5453
- return (jsxRuntime.jsxs("div", { className: `${className}`, role: "feed", "aria-label": "Activity feed", children: [jsxRuntime.jsx("div", { className: "space-y-4", children: displayedActivities.map((activity, index) => (jsxRuntime.jsxs("div", { className: "flex gap-3", role: "article", "aria-label": `${activity.user.name} ${activity.action}${activity.target ? ` ${activity.target}` : ''}`, children: [jsxRuntime.jsxs("div", { className: "flex flex-col items-center", children: [jsxRuntime.jsx(CollaboratorAvatars, { collaborators: [activity.user], max: 1, size: "sm" }), index < displayedActivities.length - 1 && (jsxRuntime.jsx("div", { className: "w-0.5 flex-1 bg-paper-200 mt-2" }))] }), jsxRuntime.jsx("div", { className: "flex-1 min-w-0 pb-4", children: jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2", children: [jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: jsxRuntime.jsxs("p", { className: "text-sm text-ink-700", children: [jsxRuntime.jsx("span", { className: "font-medium text-ink-800", children: activity.user.name }), ' ', activity.action, activity.target && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [' ', jsxRuntime.jsx("span", { className: "font-medium text-ink-800", children: activity.target })] }))] }) }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [activity.icon && (jsxRuntime.jsx("span", { className: "text-ink-400", children: activity.icon })), showTimestamps && (jsxRuntime.jsx("span", { className: "text-xs text-ink-400 whitespace-nowrap", children: formatRelativeTime$1(activity.timestamp) }))] })] }) })] }, activity.id))) }), (hasMore || onLoadMore) && (jsxRuntime.jsx("div", { className: "mt-4 text-center", children: jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", onClick: onLoadMore, loading: loading, children: loading ? 'Loading...' : 'Load more' }) }))] }));
5453
+ return (jsxRuntime.jsxs("div", { className: `${className}`, role: "feed", "aria-label": "Activity feed", children: [jsxRuntime.jsx("div", { className: "space-y-4", children: displayedActivities.map((activity, index) => (jsxRuntime.jsxs("div", { className: "flex gap-3", role: "article", "aria-label": `${activity.user.name} ${activity.action}${activity.target ? ` ${activity.target}` : ''}`, children: [jsxRuntime.jsxs("div", { className: "flex flex-col items-center", children: [jsxRuntime.jsx(CollaboratorAvatars, { collaborators: [activity.user], max: 1, size: "sm" }), index < displayedActivities.length - 1 && (jsxRuntime.jsx("div", { className: "w-0.5 flex-1 bg-paper-200 mt-2" }))] }), jsxRuntime.jsx("div", { className: "flex-1 min-w-0 pb-4", children: jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2", children: [jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: jsxRuntime.jsxs("p", { className: "text-sm text-ink-700", children: [jsxRuntime.jsx("span", { className: "font-medium text-ink-800", children: activity.user.name }), ' ', activity.action, activity.target && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [' ', jsxRuntime.jsx("span", { className: "font-medium text-ink-800", children: activity.target })] }))] }) }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [activity.icon && (jsxRuntime.jsx("span", { className: "text-ink-400", children: activity.icon })), showTimestamps && (jsxRuntime.jsx("span", { className: "text-xs text-ink-400 whitespace-nowrap", children: formatRelativeTime$3(activity.timestamp) }))] })] }) })] }, activity.id))) }), (hasMore || onLoadMore) && (jsxRuntime.jsx("div", { className: "mt-4 text-center", children: jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", onClick: onLoadMore, loading: loading, children: loading ? 'Loading...' : 'Load more' }) }))] }));
5454
5454
  }
5455
5455
 
5456
5456
  // Format relative time
5457
- function formatRelativeTime(date) {
5457
+ function formatRelativeTime$2(date) {
5458
5458
  const now = new Date();
5459
5459
  const diffMs = now.getTime() - date.getTime();
5460
5460
  const diffMins = Math.floor(diffMs / 60000);
@@ -5522,7 +5522,7 @@ function InviteCard({ onInvite, pending = [], loading = false, maxPending = 5, o
5522
5522
  shadow-card
5523
5523
  p-4
5524
5524
  ${className}
5525
- `, children: jsxRuntime.jsxs(Stack, { gap: "md", children: [jsxRuntime.jsxs(Stack, { direction: "horizontal", gap: "sm", align: "center", children: [jsxRuntime.jsx("div", { className: "p-2 bg-accent-100 rounded-lg", children: jsxRuntime.jsx(lucideReact.Mail, { className: "w-5 h-5 text-accent-600" }) }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(Text, { weight: "semibold", className: "text-ink-800", children: "Invite People" }), jsxRuntime.jsx(Text, { size: "sm", className: "text-ink-500", children: "Share access via email" })] })] }), jsxRuntime.jsx("form", { onSubmit: handleSubmit, children: jsxRuntime.jsxs(Stack, { direction: "horizontal", gap: "sm", children: [jsxRuntime.jsx("div", { className: "flex-1", children: jsxRuntime.jsx(Input, { type: "email", placeholder: "Enter email address", value: email, onChange: (e) => handleEmailChange(e.target.value), validationState: error ? 'error' : undefined, validationMessage: error || undefined, disabled: loading }) }), jsxRuntime.jsx(Button, { type: "submit", variant: "primary", loading: loading, disabled: !email.trim(), icon: jsxRuntime.jsx(lucideReact.Send, { className: "w-4 h-4" }), children: "Send" })] }) }), displayedPending.length > 0 && (jsxRuntime.jsxs(Stack, { gap: "sm", children: [jsxRuntime.jsxs(Stack, { direction: "horizontal", gap: "xs", align: "center", children: [jsxRuntime.jsx(lucideReact.Clock, { className: "w-4 h-4 text-ink-400" }), jsxRuntime.jsxs(Text, { size: "sm", className: "text-ink-500", children: ["Pending invitations (", pending.length, ")"] })] }), jsxRuntime.jsxs("div", { className: "border border-paper-200 rounded-lg divide-y divide-paper-200", children: [displayedPending.map((invite) => (jsxRuntime.jsxs("div", { className: "px-3 py-2 flex items-center justify-between", children: [jsxRuntime.jsxs(Stack, { gap: "xs", children: [jsxRuntime.jsx(Text, { size: "sm", weight: "medium", className: "text-ink-700", children: invite.email }), jsxRuntime.jsxs(Text, { size: "xs", className: "text-ink-400", children: ["Sent ", formatRelativeTime(invite.sentAt)] })] }), onCancelInvite && (jsxRuntime.jsx("button", { onClick: () => onCancelInvite(invite.email), className: "p-1 rounded hover:bg-paper-100 text-ink-400 hover:text-error-500 transition-colors", "aria-label": `Cancel invitation to ${invite.email}`, children: jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" }) }))] }, invite.email))), hasMorePending && (jsxRuntime.jsx("div", { className: "px-3 py-2 text-center", children: jsxRuntime.jsxs(Text, { size: "sm", className: "text-ink-400", children: ["+", pending.length - maxPending, " more"] }) }))] })] }))] }) }));
5525
+ `, children: jsxRuntime.jsxs(Stack, { gap: "md", children: [jsxRuntime.jsxs(Stack, { direction: "horizontal", gap: "sm", align: "center", children: [jsxRuntime.jsx("div", { className: "p-2 bg-accent-100 rounded-lg", children: jsxRuntime.jsx(lucideReact.Mail, { className: "w-5 h-5 text-accent-600" }) }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(Text, { weight: "semibold", className: "text-ink-800", children: "Invite People" }), jsxRuntime.jsx(Text, { size: "sm", className: "text-ink-500", children: "Share access via email" })] })] }), jsxRuntime.jsx("form", { onSubmit: handleSubmit, children: jsxRuntime.jsxs(Stack, { direction: "horizontal", gap: "sm", children: [jsxRuntime.jsx("div", { className: "flex-1", children: jsxRuntime.jsx(Input, { type: "email", placeholder: "Enter email address", value: email, onChange: (e) => handleEmailChange(e.target.value), validationState: error ? 'error' : undefined, validationMessage: error || undefined, disabled: loading }) }), jsxRuntime.jsx(Button, { type: "submit", variant: "primary", loading: loading, disabled: !email.trim(), icon: jsxRuntime.jsx(lucideReact.Send, { className: "w-4 h-4" }), children: "Send" })] }) }), displayedPending.length > 0 && (jsxRuntime.jsxs(Stack, { gap: "sm", children: [jsxRuntime.jsxs(Stack, { direction: "horizontal", gap: "xs", align: "center", children: [jsxRuntime.jsx(lucideReact.Clock, { className: "w-4 h-4 text-ink-400" }), jsxRuntime.jsxs(Text, { size: "sm", className: "text-ink-500", children: ["Pending invitations (", pending.length, ")"] })] }), jsxRuntime.jsxs("div", { className: "border border-paper-200 rounded-lg divide-y divide-paper-200", children: [displayedPending.map((invite) => (jsxRuntime.jsxs("div", { className: "px-3 py-2 flex items-center justify-between", children: [jsxRuntime.jsxs(Stack, { gap: "xs", children: [jsxRuntime.jsx(Text, { size: "sm", weight: "medium", className: "text-ink-700", children: invite.email }), jsxRuntime.jsxs(Text, { size: "xs", className: "text-ink-400", children: ["Sent ", formatRelativeTime$2(invite.sentAt)] })] }), onCancelInvite && (jsxRuntime.jsx("button", { onClick: () => onCancelInvite(invite.email), className: "p-1 rounded hover:bg-paper-100 text-ink-400 hover:text-error-500 transition-colors", "aria-label": `Cancel invitation to ${invite.email}`, children: jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" }) }))] }, invite.email))), hasMorePending && (jsxRuntime.jsx("div", { className: "px-3 py-2 text-center", children: jsxRuntime.jsxs(Text, { size: "sm", className: "text-ink-400", children: ["+", pending.length - maxPending, " more"] }) }))] })] }))] }) }));
5526
5526
  }
5527
5527
 
5528
5528
  /**
@@ -13205,8 +13205,13 @@ function Sidebar({ items, onNavigate, className = '', header, footer, currentPat
13205
13205
  };
13206
13206
  // Sidebar content (shared between desktop and mobile)
13207
13207
  const sidebarContent = (jsxRuntime.jsxs("div", { ref: sidebarRef, className: `flex flex-col h-full bg-white border-r border-paper-300 notebook-binding ${width} ${className}`, children: [mobileOpen !== undefined && (jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 pt-4 md:hidden", children: [jsxRuntime.jsx("div", { className: "flex-1", children: header }), jsxRuntime.jsx("button", { onClick: onMobileClose, className: "\n flex items-center justify-center\n w-10 h-10 -mr-2\n text-ink-500 hover:text-ink-700\n hover:bg-paper-100 rounded-full\n transition-colors\n ", "aria-label": "Close sidebar", children: jsxRuntime.jsx(lucideReact.X, { className: "w-5 h-5" }) })] })), header && mobileOpen === undefined && (jsxRuntime.jsx("div", { className: "px-6 pt-6 pb-4", children: header })), header && mobileOpen !== undefined && (jsxRuntime.jsx("div", { className: "px-6 pt-2 pb-4 hidden md:block", children: header })), jsxRuntime.jsx("nav", { className: "flex-1 px-3 py-2 space-y-1 overflow-y-auto", children: items.map((item) => {
13208
- // Render separator
13208
+ // Render separator or section header
13209
13209
  if (item.separator) {
13210
+ // Section header: separator with a label
13211
+ if (item.label) {
13212
+ return (jsxRuntime.jsx("div", { className: "mt-6 mb-2 px-3", "data-testid": item.dataAttributes?.['data-testid'] || `sidebar-section-${item.id}`, ...item.dataAttributes, children: jsxRuntime.jsx("div", { className: "border-t border-paper-300 pt-3", children: jsxRuntime.jsx("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-ink-400", children: item.label }) }) }, item.id));
13213
+ }
13214
+ // Plain separator: just a line
13210
13215
  return (jsxRuntime.jsx("div", { className: "my-4 border-t border-paper-300", "data-testid": item.dataAttributes?.['data-testid'] || `sidebar-separator-${item.id}`, ...item.dataAttributes }, item.id));
13211
13216
  }
13212
13217
  // Render nav item
@@ -61846,7 +61851,7 @@ function AdminModal({ isOpen, onClose, title, subtitle, onSubmit, isSaving = fal
61846
61851
  };
61847
61852
  return (jsxRuntime.jsx("div", { className: "fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4 admin-modal-overlay", children: jsxRuntime.jsxs("div", { className: `bg-white rounded-lg w-full ${sizeClasses[size]} flex flex-col overflow-hidden shadow-2xl admin-modal-content`, style: { height: height }, children: [jsxRuntime.jsx("div", { className: "fixed inset-0 pointer-events-none admin-modal-sidebar-placeholder" }), jsxRuntime.jsxs("div", { className: "px-6 py-4 border-b", children: [jsxRuntime.jsx("h3", { className: "text-lg font-semibold", children: title }), subtitle && jsxRuntime.jsx("p", { className: "text-sm text-gray-500 mt-1", children: subtitle })] }), tabs.length > 1 && (jsxRuntime.jsx("div", { className: "border-b border-gray-200 bg-white", children: jsxRuntime.jsx("nav", { className: "-mb-px flex items-center px-6 admin-modal-tabs", "aria-label": "Tabs", children: tabs.map((tab, index) => (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsx("button", { type: "button", onClick: () => onTabChange(tab.id), className: `whitespace-nowrap border-b-2 py-3 px-4 text-sm font-medium transition-colors ${activeTabId === tab.id
61848
61853
  ? 'border-blue-500 text-blue-600'
61849
- : 'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700'}`, "aria-current": activeTabId === tab.id ? 'page' : undefined, children: tab.label }), index < tabs.length - 1 && (jsxRuntime.jsx("div", { className: "admin-modal-tab-separator" }))] }, tab.id))) }) })), onSubmit ? (jsxRuntime.jsx("form", { className: "flex-1 overflow-y-auto min-h-0 h-0 px-6 py-6 admin-modal-form", onSubmit: handleFormSubmit, id: formId, children: activeTab?.content || children })) : (jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto min-h-0 h-0 px-6 py-6 admin-modal-content-area", children: activeTab?.content || children })), jsxRuntime.jsxs("div", { className: "px-6 py-4 border-t bg-gray-50 flex justify-between gap-3", children: [jsxRuntime.jsx("button", { type: "button", onClick: onClose, className: "px-4 py-2 text-sm text-gray-600 hover:text-gray-800", disabled: isSaving, children: "Cancel" }), jsxRuntime.jsxs("div", { className: "flex gap-3", children: [customFooterActions, onSubmit && (jsxRuntime.jsx("button", { type: "submit", form: formId, disabled: isSaving, className: "px-4 py-2 text-sm bg-primary-600 text-white rounded hover:bg-primary-700 disabled:opacity-50 disabled:cursor-not-allowed", children: isSaving ? 'Saving...' : 'Save Changes' }))] })] })] }) }));
61854
+ : 'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700'}`, "aria-current": activeTabId === tab.id ? 'page' : undefined, children: tab.label }), index < tabs.length - 1 && (jsxRuntime.jsx("div", { className: "admin-modal-tab-separator" }))] }, tab.id))) }) })), onSubmit ? (jsxRuntime.jsx("form", { className: "flex-1 overflow-y-auto min-h-0 h-0 px-6 py-6 admin-modal-form", onSubmit: handleFormSubmit, id: formId, noValidate: true, children: activeTab?.content || children })) : (jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto min-h-0 h-0 px-6 py-6 admin-modal-content-area", children: activeTab?.content || children })), jsxRuntime.jsxs("div", { className: "px-6 py-4 border-t bg-gray-50 flex justify-between gap-3", children: [jsxRuntime.jsx("button", { type: "button", onClick: onClose, className: "px-4 py-2 text-sm text-gray-600 hover:text-gray-800", disabled: isSaving, children: "Cancel" }), jsxRuntime.jsxs("div", { className: "flex gap-3", children: [customFooterActions, onSubmit && (jsxRuntime.jsx("button", { type: "submit", form: formId, disabled: isSaving, className: "px-4 py-2 text-sm bg-primary-600 text-white rounded hover:bg-primary-700 disabled:opacity-50 disabled:cursor-not-allowed", children: isSaving ? 'Saving...' : 'Save Changes' }))] })] })] }) }));
61850
61855
  }
61851
61856
 
61852
61857
  /**
@@ -62614,6 +62619,149 @@ function Responsive({ mobile, tablet, desktop, }) {
62614
62619
  return jsxRuntime.jsx(jsxRuntime.Fragment, { children: mobile || tablet || desktop });
62615
62620
  }
62616
62621
 
62622
+ function formatRelativeTime$1(date) {
62623
+ const now = new Date();
62624
+ const diffMs = now.getTime() - date.getTime();
62625
+ const diffMins = Math.floor(diffMs / 60000);
62626
+ const diffHours = Math.floor(diffMs / 3600000);
62627
+ const diffDays = Math.floor(diffMs / 86400000);
62628
+ if (diffMins < 1)
62629
+ return 'Just now';
62630
+ if (diffMins < 60)
62631
+ return `${diffMins}m ago`;
62632
+ if (diffHours < 24)
62633
+ return `${diffHours}h ago`;
62634
+ if (diffDays < 7)
62635
+ return `${diffDays}d ago`;
62636
+ return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
62637
+ }
62638
+ /**
62639
+ * ChatUI - Conversational chat interface component.
62640
+ *
62641
+ * Renders a scrollable message thread with user/assistant bubbles,
62642
+ * a typing indicator, an input bar with send button (Enter to send,
62643
+ * Shift+Enter for newline), and optional suggested question chips.
62644
+ *
62645
+ * @example
62646
+ * ```tsx
62647
+ * <ChatUI
62648
+ * messages={messages}
62649
+ * inputValue={input}
62650
+ * isLoading={loading}
62651
+ * onInputChange={setInput}
62652
+ * onSend={handleSend}
62653
+ * suggestedQuestions={['What are my top deals?']}
62654
+ * onSuggestedQuestionClick={handleQuestion}
62655
+ * />
62656
+ * ```
62657
+ */
62658
+ const ChatUI = React.forwardRef(({ messages, inputValue, isLoading = false, placeholder = 'Ask a question...', suggestedQuestions = [], onInputChange, onSend, onSuggestedQuestionClick, messagesEndRef, height = '600px', className = '', }, ref) => {
62659
+ const handleKeyDown = (e) => {
62660
+ if (e.key === 'Enter' && !e.shiftKey) {
62661
+ e.preventDefault();
62662
+ if (inputValue.trim()) {
62663
+ onSend();
62664
+ }
62665
+ }
62666
+ };
62667
+ return (jsxRuntime.jsxs("div", { ref: ref, className: `flex flex-col bg-white rounded-lg border border-paper-200 overflow-hidden ${className}`, style: { height }, children: [jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto p-4 space-y-4", children: [messages.length === 0 && !isLoading && (jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center h-full text-center", children: [jsxRuntime.jsx(lucideReact.Bot, { className: "w-10 h-10 text-ink-300 mb-3" }), jsxRuntime.jsx("p", { className: "text-ink-500 text-sm", children: "No messages yet. Start a conversation!" })] })), messages.map((message) => (jsxRuntime.jsxs("div", { className: `flex gap-3 ${message.role === 'user' ? 'flex-row-reverse' : 'flex-row'}`, children: [jsxRuntime.jsx("div", { className: `flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center ${message.role === 'user'
62668
+ ? 'bg-primary-100 text-primary-600'
62669
+ : 'bg-paper-200 text-ink-500'}`, children: message.role === 'user' ? (jsxRuntime.jsx(lucideReact.User, { className: "w-4 h-4" })) : (jsxRuntime.jsx(lucideReact.Bot, { className: "w-4 h-4" })) }), jsxRuntime.jsxs("div", { className: `max-w-[75%] rounded-xl px-4 py-2.5 ${message.role === 'user'
62670
+ ? 'bg-primary-500 text-white rounded-br-sm'
62671
+ : 'bg-paper-100 text-ink-800 border border-paper-200 rounded-bl-sm'}`, children: [jsxRuntime.jsx("p", { className: "text-sm whitespace-pre-wrap", children: message.content }), jsxRuntime.jsx("p", { className: `text-[10px] mt-1 ${message.role === 'user' ? 'text-primary-200' : 'text-ink-400'}`, children: formatRelativeTime$1(message.timestamp) })] })] }, message.id))), isLoading && (jsxRuntime.jsxs("div", { className: "flex gap-3", children: [jsxRuntime.jsx("div", { className: "flex-shrink-0 w-8 h-8 rounded-full bg-paper-200 text-ink-500 flex items-center justify-center", children: jsxRuntime.jsx(lucideReact.Bot, { className: "w-4 h-4" }) }), jsxRuntime.jsx("div", { className: "bg-paper-100 border border-paper-200 rounded-xl rounded-bl-sm px-4 py-3", children: jsxRuntime.jsxs("div", { className: "flex gap-1.5", children: [jsxRuntime.jsx("span", { className: "w-2 h-2 bg-ink-400 rounded-full animate-bounce", style: { animationDelay: '0ms' } }), jsxRuntime.jsx("span", { className: "w-2 h-2 bg-ink-400 rounded-full animate-bounce", style: { animationDelay: '150ms' } }), jsxRuntime.jsx("span", { className: "w-2 h-2 bg-ink-400 rounded-full animate-bounce", style: { animationDelay: '300ms' } })] }) })] })), messagesEndRef && jsxRuntime.jsx("div", { ref: messagesEndRef })] }), suggestedQuestions.length > 0 && messages.length === 0 && (jsxRuntime.jsx("div", { className: "px-4 pb-2 flex flex-wrap gap-2", children: suggestedQuestions.map((question, index) => (jsxRuntime.jsx("button", { onClick: () => onSuggestedQuestionClick?.(question), className: "text-xs px-3 py-1.5 rounded-full border border-primary-200 text-primary-700 bg-primary-50 hover:bg-primary-100 transition-colors", children: question }, index))) })), jsxRuntime.jsx("div", { className: "border-t border-paper-200 p-3 bg-paper-50", children: jsxRuntime.jsxs("div", { className: "flex items-end gap-2", children: [jsxRuntime.jsx("textarea", { value: inputValue, onChange: (e) => onInputChange(e.target.value), onKeyDown: handleKeyDown, placeholder: placeholder, rows: 1, className: "flex-1 resize-none rounded-lg border border-paper-300 bg-white px-3 py-2 text-sm text-ink-800 placeholder:text-ink-400 focus:outline-none focus:ring-2 focus:ring-primary-300 focus:border-primary-300" }), jsxRuntime.jsx("button", { onClick: onSend, disabled: !inputValue.trim() || isLoading, className: "flex-shrink-0 p-2 rounded-lg bg-primary-500 text-white hover:bg-primary-600 disabled:opacity-40 disabled:cursor-not-allowed transition-colors", "aria-label": "Send message", children: jsxRuntime.jsx(lucideReact.Send, { className: "w-4 h-4" }) })] }) })] }));
62672
+ });
62673
+ ChatUI.displayName = 'ChatUI';
62674
+
62675
+ const FILTER_OPTIONS = [
62676
+ { key: 'all', label: 'All' },
62677
+ { key: 'trend', label: 'Trends' },
62678
+ { key: 'anomaly', label: 'Anomalies' },
62679
+ { key: 'forecast', label: 'Forecasts' },
62680
+ { key: 'recommendation', label: 'Recommendations' },
62681
+ ];
62682
+ function getTypeIcon(type) {
62683
+ switch (type) {
62684
+ case 'trend':
62685
+ return jsxRuntime.jsx(lucideReact.TrendingUp, { className: "w-4 h-4 text-green-600" });
62686
+ case 'anomaly':
62687
+ return jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "w-4 h-4 text-red-600" });
62688
+ case 'forecast':
62689
+ return jsxRuntime.jsx(lucideReact.Target, { className: "w-4 h-4 text-purple-600" });
62690
+ case 'recommendation':
62691
+ return jsxRuntime.jsx(lucideReact.Lightbulb, { className: "w-4 h-4 text-amber-600" });
62692
+ }
62693
+ }
62694
+ function getTypeBgColor(type) {
62695
+ switch (type) {
62696
+ case 'trend': return 'bg-green-50';
62697
+ case 'anomaly': return 'bg-red-50';
62698
+ case 'forecast': return 'bg-purple-50';
62699
+ case 'recommendation': return 'bg-amber-50';
62700
+ }
62701
+ }
62702
+ function getConfidenceBadge(confidence) {
62703
+ const pct = Math.round(confidence * 100);
62704
+ let colorClasses;
62705
+ if (confidence >= 0.8) {
62706
+ colorClasses = 'bg-green-100 text-green-700';
62707
+ }
62708
+ else if (confidence >= 0.6) {
62709
+ colorClasses = 'bg-yellow-100 text-yellow-700';
62710
+ }
62711
+ else {
62712
+ colorClasses = 'bg-red-100 text-red-700';
62713
+ }
62714
+ return (jsxRuntime.jsxs("span", { className: `inline-flex items-center text-[10px] font-medium px-1.5 py-0.5 rounded-full ${colorClasses}`, children: [pct, "%"] }));
62715
+ }
62716
+ function formatRelativeTime(date) {
62717
+ const now = new Date();
62718
+ const diffMs = now.getTime() - date.getTime();
62719
+ const diffMins = Math.floor(diffMs / 60000);
62720
+ const diffHours = Math.floor(diffMs / 3600000);
62721
+ const diffDays = Math.floor(diffMs / 86400000);
62722
+ if (diffMins < 1)
62723
+ return 'Just now';
62724
+ if (diffMins < 60)
62725
+ return `${diffMins}m ago`;
62726
+ if (diffHours < 24)
62727
+ return `${diffHours}h ago`;
62728
+ if (diffDays < 7)
62729
+ return `${diffDays}d ago`;
62730
+ return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
62731
+ }
62732
+ /**
62733
+ * InsightsPanelUI - Structured display of analytics insights.
62734
+ *
62735
+ * Renders a header with title and refresh button, filter chips
62736
+ * (All / Trends / Anomalies / Forecasts / Recommendations), and
62737
+ * insight cards with type icon, title, summary, confidence badge,
62738
+ * and relative timestamp. Includes loading skeleton and empty state.
62739
+ *
62740
+ * @example
62741
+ * ```tsx
62742
+ * <InsightsPanelUI
62743
+ * insights={insights}
62744
+ * isLoading={loading}
62745
+ * filter={activeFilter}
62746
+ * maxInsights={8}
62747
+ * onFilterChange={setFilter}
62748
+ * onRefresh={refreshInsights}
62749
+ * />
62750
+ * ```
62751
+ */
62752
+ const InsightsPanelUI = React.forwardRef(({ insights, isLoading = false, filter = 'all', maxInsights, onFilterChange, onRefresh, className = '', }, ref) => {
62753
+ const filtered = filter === 'all'
62754
+ ? insights
62755
+ : insights.filter((i) => i.type === filter);
62756
+ const displayed = maxInsights ? filtered.slice(0, maxInsights) : filtered;
62757
+ return (jsxRuntime.jsxs("div", { ref: ref, className: `bg-white rounded-lg border border-paper-200 ${className}`, children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-5 py-4 border-b border-paper-200", children: [jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-ink-900", children: "AI Insights" }), onRefresh && (jsxRuntime.jsx("button", { onClick: onRefresh, disabled: isLoading, className: "p-1.5 rounded-md text-ink-500 hover:text-ink-700 hover:bg-paper-100 disabled:opacity-40 transition-colors", "aria-label": "Refresh insights", children: jsxRuntime.jsx(lucideReact.RefreshCw, { className: `w-4 h-4 ${isLoading ? 'animate-spin' : ''}` }) }))] }), onFilterChange && (jsxRuntime.jsx("div", { className: "px-5 pt-3 pb-1 flex flex-wrap gap-2", children: FILTER_OPTIONS.map((opt) => (jsxRuntime.jsx("button", { onClick: () => onFilterChange(opt.key), className: `text-xs font-medium px-3 py-1.5 rounded-full transition-colors ${filter === opt.key
62758
+ ? 'bg-primary-500 text-white'
62759
+ : 'bg-paper-100 text-ink-600 hover:bg-paper-200'}`, children: opt.label }, opt.key))) })), jsxRuntime.jsxs("div", { className: "p-5 space-y-3", children: [isLoading && displayed.length === 0 && (jsxRuntime.jsx("div", { className: "space-y-3", children: [1, 2, 3].map((i) => (jsxRuntime.jsxs("div", { className: "animate-pulse rounded-lg border border-paper-200 p-4", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-3 mb-2", children: [jsxRuntime.jsx("div", { className: "w-8 h-8 bg-paper-200 rounded-lg" }), jsxRuntime.jsxs("div", { className: "flex-1", children: [jsxRuntime.jsx("div", { className: "h-4 bg-paper-200 rounded w-2/3 mb-1" }), jsxRuntime.jsx("div", { className: "h-3 bg-paper-100 rounded w-1/3" })] })] }), jsxRuntime.jsx("div", { className: "h-3 bg-paper-100 rounded w-full mb-1" }), jsxRuntime.jsx("div", { className: "h-3 bg-paper-100 rounded w-4/5" })] }, i))) })), !isLoading && displayed.length === 0 && (jsxRuntime.jsxs("div", { className: "text-center py-8", children: [jsxRuntime.jsx(lucideReact.BrainCircuit, { className: "w-10 h-10 text-ink-300 mx-auto mb-3" }), jsxRuntime.jsx("p", { className: "text-ink-500 text-sm", children: filter === 'all'
62760
+ ? 'No insights available yet.'
62761
+ : `No ${filter} insights found.` })] })), displayed.map((insight) => (jsxRuntime.jsx("div", { className: "rounded-lg border border-paper-200 p-4 hover:shadow-sm transition-shadow", children: jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [jsxRuntime.jsx("div", { className: `flex-shrink-0 w-8 h-8 rounded-lg flex items-center justify-center ${getTypeBgColor(insight.type)}`, children: getTypeIcon(insight.type) }), jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 mb-1", children: [jsxRuntime.jsx("h4", { className: "text-sm font-medium text-ink-900 truncate", children: insight.title }), getConfidenceBadge(insight.confidence)] }), jsxRuntime.jsx("p", { className: "text-xs text-ink-600 leading-relaxed", children: insight.summary }), jsxRuntime.jsx("p", { className: "text-[10px] text-ink-400 mt-1.5", children: formatRelativeTime(insight.timestamp) })] })] }) }, insight.id)))] })] }));
62762
+ });
62763
+ InsightsPanelUI.displayName = 'InsightsPanelUI';
62764
+
62617
62765
  exports.Accordion = Accordion;
62618
62766
  exports.AchievementBadge = AchievementBadge;
62619
62767
  exports.AchievementUnlock = AchievementUnlock;
@@ -62654,6 +62802,7 @@ exports.CardView = CardView;
62654
62802
  exports.Carousel = Carousel;
62655
62803
  exports.CaseQueueItem = CaseQueueItem;
62656
62804
  exports.Celebration = Celebration;
62805
+ exports.ChatUI = ChatUI;
62657
62806
  exports.Checkbox = Checkbox;
62658
62807
  exports.CheckboxList = CheckboxList;
62659
62808
  exports.Chip = Chip;
@@ -62721,6 +62870,7 @@ exports.HorizontalScroll = HorizontalScroll;
62721
62870
  exports.HoverCard = HoverCard;
62722
62871
  exports.InfiniteScroll = InfiniteScroll;
62723
62872
  exports.Input = Input;
62873
+ exports.InsightsPanelUI = InsightsPanelUI;
62724
62874
  exports.InviteCard = InviteCard;
62725
62875
  exports.KanbanBoard = KanbanBoard;
62726
62876
  exports.Layout = Layout;