@papernote/ui 1.11.5 → 1.12.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/components/ChatUI.d.ts +59 -0
- package/dist/components/ChatUI.d.ts.map +1 -0
- package/dist/components/FunnelChart.d.ts +3 -1
- package/dist/components/FunnelChart.d.ts.map +1 -1
- package/dist/components/InsightsPanelUI.d.ts +56 -0
- package/dist/components/InsightsPanelUI.d.ts.map +1 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/index.d.ts +117 -3
- package/dist/index.esm.js +160 -8
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +160 -6
- package/dist/index.js.map +1 -1
- package/dist/styles.css +59 -0
- package/package.json +1 -1
- package/src/components/ChatUI.tsx +214 -0
- package/src/components/FunnelChart.tsx +27 -15
- package/src/components/InsightsPanelUI.tsx +244 -0
- package/src/components/index.ts +6 -0
package/dist/index.esm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import React__default, { forwardRef, useState, useRef, useEffect, useId, useCallback, useImperativeHandle, useMemo, Children, isValidElement, cloneElement, Component, createContext as createContext$1, useContext, useLayoutEffect, createElement, useReducer } from 'react';
|
|
4
|
-
import { Loader2, Check, X, EyeOff, Eye, AlertTriangle, CheckCircle, AlertCircle, ChevronDown, Search, Minus, Star, Calendar as Calendar$1, ChevronLeft, ChevronRight, Clock, ChevronUp, Plus, TrendingUp, TrendingDown, Lightbulb, Sparkles, PartyPopper, Flame, Shield, Pencil, User, Users, Activity, Mail, Send, Info, Trash2, HelpCircle, ChevronsLeft, ChevronsRight, Circle, MoreVertical, GripVertical, Upload, Bold, Italic, Underline, List, ListOrdered, Code, Link, ExternalLink, MoreHorizontal, Home, ArrowUp, ArrowDown, RotateCcw, ArrowRight, FileText, Image, File as File$1, Menu as Menu$1, Settings, LogOut, Moon, Sun, Bell, Edit, Trash, Pin, PinOff, Download, Save, ArrowUpDown, Filter, XCircle, BarChart3, MessageSquare } from 'lucide-react';
|
|
4
|
+
import { Loader2, Check, X, EyeOff, Eye, AlertTriangle, CheckCircle, AlertCircle, ChevronDown, Search, Minus, Star, Calendar as Calendar$1, ChevronLeft, ChevronRight, Clock, ChevronUp, Plus, TrendingUp, TrendingDown, Lightbulb, Sparkles, PartyPopper, Flame, Shield, Pencil, User, Users, Activity, Mail, Send, Info, Trash2, HelpCircle, ChevronsLeft, ChevronsRight, Circle, MoreVertical, GripVertical, Upload, Bold, Italic, Underline, List, ListOrdered, Code, Link, ExternalLink, MoreHorizontal, Home, ArrowUp, ArrowDown, RotateCcw, ArrowRight, FileText, Image, File as File$1, Menu as Menu$1, Settings, LogOut, Moon, Sun, Bell, Edit, Trash, Pin, PinOff, Download, Save, ArrowUpDown, Filter, XCircle, BarChart3, MessageSquare, Bot, RefreshCw, BrainCircuit, Target } from 'lucide-react';
|
|
5
5
|
import { createPortal } from 'react-dom';
|
|
6
6
|
import { Link as Link$1, useInRouterContext, useNavigate, useLocation } from 'react-router-dom';
|
|
7
7
|
|
|
@@ -5398,7 +5398,7 @@ function SharedBadge({ sharedWith, variant, size = 'md', maxDisplay = 3, onClick
|
|
|
5398
5398
|
}
|
|
5399
5399
|
|
|
5400
5400
|
// Format relative time
|
|
5401
|
-
function formatRelativeTime$
|
|
5401
|
+
function formatRelativeTime$3(date) {
|
|
5402
5402
|
const now = new Date();
|
|
5403
5403
|
const diffMs = now.getTime() - date.getTime();
|
|
5404
5404
|
const diffMins = Math.floor(diffMs / 60000);
|
|
@@ -5430,11 +5430,11 @@ function ActivityFeed({ activities, maxItems, showTimestamps = true, onLoadMore,
|
|
|
5430
5430
|
if (activities.length === 0) {
|
|
5431
5431
|
return (jsxs("div", { className: `text-center py-8 ${className}`, children: [jsx(Activity, { className: "w-8 h-8 text-ink-300 mx-auto mb-2" }), jsx("p", { className: "text-ink-500 text-sm", children: "No activity yet" })] }));
|
|
5432
5432
|
}
|
|
5433
|
-
return (jsxs("div", { className: `${className}`, role: "feed", "aria-label": "Activity feed", children: [jsx("div", { className: "space-y-4", children: displayedActivities.map((activity, index) => (jsxs("div", { className: "flex gap-3", role: "article", "aria-label": `${activity.user.name} ${activity.action}${activity.target ? ` ${activity.target}` : ''}`, children: [jsxs("div", { className: "flex flex-col items-center", children: [jsx(CollaboratorAvatars, { collaborators: [activity.user], max: 1, size: "sm" }), index < displayedActivities.length - 1 && (jsx("div", { className: "w-0.5 flex-1 bg-paper-200 mt-2" }))] }), jsx("div", { className: "flex-1 min-w-0 pb-4", children: jsxs("div", { className: "flex items-start justify-between gap-2", children: [jsx("div", { className: "flex-1 min-w-0", children: jsxs("p", { className: "text-sm text-ink-700", children: [jsx("span", { className: "font-medium text-ink-800", children: activity.user.name }), ' ', activity.action, activity.target && (jsxs(Fragment, { children: [' ', jsx("span", { className: "font-medium text-ink-800", children: activity.target })] }))] }) }), jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [activity.icon && (jsx("span", { className: "text-ink-400", children: activity.icon })), showTimestamps && (jsx("span", { className: "text-xs text-ink-400 whitespace-nowrap", children: formatRelativeTime$
|
|
5433
|
+
return (jsxs("div", { className: `${className}`, role: "feed", "aria-label": "Activity feed", children: [jsx("div", { className: "space-y-4", children: displayedActivities.map((activity, index) => (jsxs("div", { className: "flex gap-3", role: "article", "aria-label": `${activity.user.name} ${activity.action}${activity.target ? ` ${activity.target}` : ''}`, children: [jsxs("div", { className: "flex flex-col items-center", children: [jsx(CollaboratorAvatars, { collaborators: [activity.user], max: 1, size: "sm" }), index < displayedActivities.length - 1 && (jsx("div", { className: "w-0.5 flex-1 bg-paper-200 mt-2" }))] }), jsx("div", { className: "flex-1 min-w-0 pb-4", children: jsxs("div", { className: "flex items-start justify-between gap-2", children: [jsx("div", { className: "flex-1 min-w-0", children: jsxs("p", { className: "text-sm text-ink-700", children: [jsx("span", { className: "font-medium text-ink-800", children: activity.user.name }), ' ', activity.action, activity.target && (jsxs(Fragment, { children: [' ', jsx("span", { className: "font-medium text-ink-800", children: activity.target })] }))] }) }), jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [activity.icon && (jsx("span", { className: "text-ink-400", children: activity.icon })), showTimestamps && (jsx("span", { className: "text-xs text-ink-400 whitespace-nowrap", children: formatRelativeTime$3(activity.timestamp) }))] })] }) })] }, activity.id))) }), (hasMore || onLoadMore) && (jsx("div", { className: "mt-4 text-center", children: jsx(Button, { variant: "ghost", size: "sm", onClick: onLoadMore, loading: loading, children: loading ? 'Loading...' : 'Load more' }) }))] }));
|
|
5434
5434
|
}
|
|
5435
5435
|
|
|
5436
5436
|
// Format relative time
|
|
5437
|
-
function formatRelativeTime(date) {
|
|
5437
|
+
function formatRelativeTime$2(date) {
|
|
5438
5438
|
const now = new Date();
|
|
5439
5439
|
const diffMs = now.getTime() - date.getTime();
|
|
5440
5440
|
const diffMins = Math.floor(diffMs / 60000);
|
|
@@ -5502,7 +5502,7 @@ function InviteCard({ onInvite, pending = [], loading = false, maxPending = 5, o
|
|
|
5502
5502
|
shadow-card
|
|
5503
5503
|
p-4
|
|
5504
5504
|
${className}
|
|
5505
|
-
`, children: jsxs(Stack, { gap: "md", children: [jsxs(Stack, { direction: "horizontal", gap: "sm", align: "center", children: [jsx("div", { className: "p-2 bg-accent-100 rounded-lg", children: jsx(Mail, { className: "w-5 h-5 text-accent-600" }) }), jsxs("div", { children: [jsx(Text, { weight: "semibold", className: "text-ink-800", children: "Invite People" }), jsx(Text, { size: "sm", className: "text-ink-500", children: "Share access via email" })] })] }), jsx("form", { onSubmit: handleSubmit, children: jsxs(Stack, { direction: "horizontal", gap: "sm", children: [jsx("div", { className: "flex-1", children: 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 }) }), jsx(Button, { type: "submit", variant: "primary", loading: loading, disabled: !email.trim(), icon: jsx(Send, { className: "w-4 h-4" }), children: "Send" })] }) }), displayedPending.length > 0 && (jsxs(Stack, { gap: "sm", children: [jsxs(Stack, { direction: "horizontal", gap: "xs", align: "center", children: [jsx(Clock, { className: "w-4 h-4 text-ink-400" }), jsxs(Text, { size: "sm", className: "text-ink-500", children: ["Pending invitations (", pending.length, ")"] })] }), jsxs("div", { className: "border border-paper-200 rounded-lg divide-y divide-paper-200", children: [displayedPending.map((invite) => (jsxs("div", { className: "px-3 py-2 flex items-center justify-between", children: [jsxs(Stack, { gap: "xs", children: [jsx(Text, { size: "sm", weight: "medium", className: "text-ink-700", children: invite.email }), jsxs(Text, { size: "xs", className: "text-ink-400", children: ["Sent ", formatRelativeTime(invite.sentAt)] })] }), onCancelInvite && (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: jsx(X, { className: "w-4 h-4" }) }))] }, invite.email))), hasMorePending && (jsx("div", { className: "px-3 py-2 text-center", children: jsxs(Text, { size: "sm", className: "text-ink-400", children: ["+", pending.length - maxPending, " more"] }) }))] })] }))] }) }));
|
|
5505
|
+
`, children: jsxs(Stack, { gap: "md", children: [jsxs(Stack, { direction: "horizontal", gap: "sm", align: "center", children: [jsx("div", { className: "p-2 bg-accent-100 rounded-lg", children: jsx(Mail, { className: "w-5 h-5 text-accent-600" }) }), jsxs("div", { children: [jsx(Text, { weight: "semibold", className: "text-ink-800", children: "Invite People" }), jsx(Text, { size: "sm", className: "text-ink-500", children: "Share access via email" })] })] }), jsx("form", { onSubmit: handleSubmit, children: jsxs(Stack, { direction: "horizontal", gap: "sm", children: [jsx("div", { className: "flex-1", children: 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 }) }), jsx(Button, { type: "submit", variant: "primary", loading: loading, disabled: !email.trim(), icon: jsx(Send, { className: "w-4 h-4" }), children: "Send" })] }) }), displayedPending.length > 0 && (jsxs(Stack, { gap: "sm", children: [jsxs(Stack, { direction: "horizontal", gap: "xs", align: "center", children: [jsx(Clock, { className: "w-4 h-4 text-ink-400" }), jsxs(Text, { size: "sm", className: "text-ink-500", children: ["Pending invitations (", pending.length, ")"] })] }), jsxs("div", { className: "border border-paper-200 rounded-lg divide-y divide-paper-200", children: [displayedPending.map((invite) => (jsxs("div", { className: "px-3 py-2 flex items-center justify-between", children: [jsxs(Stack, { gap: "xs", children: [jsx(Text, { size: "sm", weight: "medium", className: "text-ink-700", children: invite.email }), jsxs(Text, { size: "xs", className: "text-ink-400", children: ["Sent ", formatRelativeTime$2(invite.sentAt)] })] }), onCancelInvite && (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: jsx(X, { className: "w-4 h-4" }) }))] }, invite.email))), hasMorePending && (jsx("div", { className: "px-3 py-2 text-center", children: jsxs(Text, { size: "sm", className: "text-ink-400", children: ["+", pending.length - maxPending, " more"] }) }))] })] }))] }) }));
|
|
5506
5506
|
}
|
|
5507
5507
|
|
|
5508
5508
|
/**
|
|
@@ -12296,6 +12296,14 @@ const defaultColors = [
|
|
|
12296
12296
|
'#f3e8ff', // purple ultra light
|
|
12297
12297
|
];
|
|
12298
12298
|
// =============================================================================
|
|
12299
|
+
// Label Size Presets
|
|
12300
|
+
// =============================================================================
|
|
12301
|
+
const labelSizes = {
|
|
12302
|
+
sm: { name: '9px', value: '8px', count: '10px', conversion: '8px' },
|
|
12303
|
+
md: { name: '11px', value: '10px', count: '12px', conversion: '10px' },
|
|
12304
|
+
lg: { name: '13px', value: '12px', count: '14px', conversion: '12px' },
|
|
12305
|
+
};
|
|
12306
|
+
// =============================================================================
|
|
12299
12307
|
// Component
|
|
12300
12308
|
// =============================================================================
|
|
12301
12309
|
/**
|
|
@@ -12305,9 +12313,10 @@ const defaultColors = [
|
|
|
12305
12313
|
* to its count relative to the first (widest) stage.
|
|
12306
12314
|
* Shows stage names, counts, values, and optional conversion rates.
|
|
12307
12315
|
*/
|
|
12308
|
-
function FunnelChart({ stages, height = 300, showConversion = true, onStageClick, className = '', }) {
|
|
12316
|
+
function FunnelChart({ stages, height = 300, showConversion = true, labelSize = 'md', onStageClick, className = '', }) {
|
|
12309
12317
|
if (stages.length === 0)
|
|
12310
12318
|
return null;
|
|
12319
|
+
const sizes = labelSizes[labelSize];
|
|
12311
12320
|
const maxCount = Math.max(...stages.map(s => s.count), 1);
|
|
12312
12321
|
const stageHeight = height / stages.length;
|
|
12313
12322
|
const svgWidth = 450;
|
|
@@ -12335,7 +12344,7 @@ function FunnelChart({ stages, height = 300, showConversion = true, onStageClick
|
|
|
12335
12344
|
L ${centerX - bottomWidth / 2} ${y + stageHeight - 2}
|
|
12336
12345
|
Z
|
|
12337
12346
|
`;
|
|
12338
|
-
return (jsxs("g", { onClick: () => onStageClick?.(stage.name), style: onStageClick ? { cursor: 'pointer' } : undefined, role: onStageClick ? 'button' : undefined, children: [jsx("path", { d: path, fill: color, opacity: 0.85, className: "transition-opacity hover:opacity-100" }), jsx("text", { x: centerX, y: y + stageHeight / 2 + 1, textAnchor: "middle", dominantBaseline: "middle", className: "fill-white
|
|
12347
|
+
return (jsxs("g", { onClick: () => onStageClick?.(stage.name), style: onStageClick ? { cursor: 'pointer' } : undefined, role: onStageClick ? 'button' : undefined, children: [jsx("path", { d: path, fill: color, opacity: 0.85, className: "transition-opacity hover:opacity-100" }), jsx("text", { x: centerX, y: y + stageHeight / 2 + 1, textAnchor: "middle", dominantBaseline: "middle", className: "fill-white font-bold", style: { fontSize: sizes.count }, children: stage.count.toLocaleString() }), jsx("text", { x: centerX + funnelWidth / 2 + 12, y: y + stageHeight / 2 - 4, className: "fill-ink-700 dark:fill-ink-300", style: { fontSize: sizes.name, fontWeight: 500 }, children: stage.name }), stage.value && (jsx("text", { x: centerX + funnelWidth / 2 + 12, y: y + stageHeight / 2 + 7, className: "fill-ink-400", style: { fontSize: sizes.value }, children: stage.value })), showConversion && conversionRate !== null && (jsxs("text", { x: centerX - funnelWidth / 2 - 16, y: y + 4, textAnchor: "end", className: "fill-ink-500", style: { fontSize: sizes.conversion, fontWeight: 500 }, children: ["\u2193 ", conversionRate, "%"] }))] }, stage.name));
|
|
12339
12348
|
}) }) }));
|
|
12340
12349
|
}
|
|
12341
12350
|
|
|
@@ -62577,5 +62586,148 @@ function Responsive({ mobile, tablet, desktop, }) {
|
|
|
62577
62586
|
return jsx(Fragment, { children: mobile || tablet || desktop });
|
|
62578
62587
|
}
|
|
62579
62588
|
|
|
62580
|
-
|
|
62589
|
+
function formatRelativeTime$1(date) {
|
|
62590
|
+
const now = new Date();
|
|
62591
|
+
const diffMs = now.getTime() - date.getTime();
|
|
62592
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
62593
|
+
const diffHours = Math.floor(diffMs / 3600000);
|
|
62594
|
+
const diffDays = Math.floor(diffMs / 86400000);
|
|
62595
|
+
if (diffMins < 1)
|
|
62596
|
+
return 'Just now';
|
|
62597
|
+
if (diffMins < 60)
|
|
62598
|
+
return `${diffMins}m ago`;
|
|
62599
|
+
if (diffHours < 24)
|
|
62600
|
+
return `${diffHours}h ago`;
|
|
62601
|
+
if (diffDays < 7)
|
|
62602
|
+
return `${diffDays}d ago`;
|
|
62603
|
+
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
|
|
62604
|
+
}
|
|
62605
|
+
/**
|
|
62606
|
+
* ChatUI - Conversational chat interface component.
|
|
62607
|
+
*
|
|
62608
|
+
* Renders a scrollable message thread with user/assistant bubbles,
|
|
62609
|
+
* a typing indicator, an input bar with send button (Enter to send,
|
|
62610
|
+
* Shift+Enter for newline), and optional suggested question chips.
|
|
62611
|
+
*
|
|
62612
|
+
* @example
|
|
62613
|
+
* ```tsx
|
|
62614
|
+
* <ChatUI
|
|
62615
|
+
* messages={messages}
|
|
62616
|
+
* inputValue={input}
|
|
62617
|
+
* isLoading={loading}
|
|
62618
|
+
* onInputChange={setInput}
|
|
62619
|
+
* onSend={handleSend}
|
|
62620
|
+
* suggestedQuestions={['What are my top deals?']}
|
|
62621
|
+
* onSuggestedQuestionClick={handleQuestion}
|
|
62622
|
+
* />
|
|
62623
|
+
* ```
|
|
62624
|
+
*/
|
|
62625
|
+
const ChatUI = forwardRef(({ messages, inputValue, isLoading = false, placeholder = 'Ask a question...', suggestedQuestions = [], onInputChange, onSend, onSuggestedQuestionClick, messagesEndRef, height = '600px', className = '', }, ref) => {
|
|
62626
|
+
const handleKeyDown = (e) => {
|
|
62627
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
62628
|
+
e.preventDefault();
|
|
62629
|
+
if (inputValue.trim()) {
|
|
62630
|
+
onSend();
|
|
62631
|
+
}
|
|
62632
|
+
}
|
|
62633
|
+
};
|
|
62634
|
+
return (jsxs("div", { ref: ref, className: `flex flex-col bg-white rounded-lg border border-paper-200 overflow-hidden ${className}`, style: { height }, children: [jsxs("div", { className: "flex-1 overflow-y-auto p-4 space-y-4", children: [messages.length === 0 && !isLoading && (jsxs("div", { className: "flex flex-col items-center justify-center h-full text-center", children: [jsx(Bot, { className: "w-10 h-10 text-ink-300 mb-3" }), jsx("p", { className: "text-ink-500 text-sm", children: "No messages yet. Start a conversation!" })] })), messages.map((message) => (jsxs("div", { className: `flex gap-3 ${message.role === 'user' ? 'flex-row-reverse' : 'flex-row'}`, children: [jsx("div", { className: `flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center ${message.role === 'user'
|
|
62635
|
+
? 'bg-primary-100 text-primary-600'
|
|
62636
|
+
: 'bg-paper-200 text-ink-500'}`, children: message.role === 'user' ? (jsx(User, { className: "w-4 h-4" })) : (jsx(Bot, { className: "w-4 h-4" })) }), jsxs("div", { className: `max-w-[75%] rounded-xl px-4 py-2.5 ${message.role === 'user'
|
|
62637
|
+
? 'bg-primary-500 text-white rounded-br-sm'
|
|
62638
|
+
: 'bg-paper-100 text-ink-800 border border-paper-200 rounded-bl-sm'}`, children: [jsx("p", { className: "text-sm whitespace-pre-wrap", children: message.content }), jsx("p", { className: `text-[10px] mt-1 ${message.role === 'user' ? 'text-primary-200' : 'text-ink-400'}`, children: formatRelativeTime$1(message.timestamp) })] })] }, message.id))), isLoading && (jsxs("div", { className: "flex gap-3", children: [jsx("div", { className: "flex-shrink-0 w-8 h-8 rounded-full bg-paper-200 text-ink-500 flex items-center justify-center", children: jsx(Bot, { className: "w-4 h-4" }) }), jsx("div", { className: "bg-paper-100 border border-paper-200 rounded-xl rounded-bl-sm px-4 py-3", children: jsxs("div", { className: "flex gap-1.5", children: [jsx("span", { className: "w-2 h-2 bg-ink-400 rounded-full animate-bounce", style: { animationDelay: '0ms' } }), jsx("span", { className: "w-2 h-2 bg-ink-400 rounded-full animate-bounce", style: { animationDelay: '150ms' } }), jsx("span", { className: "w-2 h-2 bg-ink-400 rounded-full animate-bounce", style: { animationDelay: '300ms' } })] }) })] })), messagesEndRef && jsx("div", { ref: messagesEndRef })] }), suggestedQuestions.length > 0 && messages.length === 0 && (jsx("div", { className: "px-4 pb-2 flex flex-wrap gap-2", children: suggestedQuestions.map((question, index) => (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))) })), jsx("div", { className: "border-t border-paper-200 p-3 bg-paper-50", children: jsxs("div", { className: "flex items-end gap-2", children: [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" }), 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: jsx(Send, { className: "w-4 h-4" }) })] }) })] }));
|
|
62639
|
+
});
|
|
62640
|
+
ChatUI.displayName = 'ChatUI';
|
|
62641
|
+
|
|
62642
|
+
const FILTER_OPTIONS = [
|
|
62643
|
+
{ key: 'all', label: 'All' },
|
|
62644
|
+
{ key: 'trend', label: 'Trends' },
|
|
62645
|
+
{ key: 'anomaly', label: 'Anomalies' },
|
|
62646
|
+
{ key: 'forecast', label: 'Forecasts' },
|
|
62647
|
+
{ key: 'recommendation', label: 'Recommendations' },
|
|
62648
|
+
];
|
|
62649
|
+
function getTypeIcon(type) {
|
|
62650
|
+
switch (type) {
|
|
62651
|
+
case 'trend':
|
|
62652
|
+
return jsx(TrendingUp, { className: "w-4 h-4 text-green-600" });
|
|
62653
|
+
case 'anomaly':
|
|
62654
|
+
return jsx(AlertTriangle, { className: "w-4 h-4 text-red-600" });
|
|
62655
|
+
case 'forecast':
|
|
62656
|
+
return jsx(Target, { className: "w-4 h-4 text-purple-600" });
|
|
62657
|
+
case 'recommendation':
|
|
62658
|
+
return jsx(Lightbulb, { className: "w-4 h-4 text-amber-600" });
|
|
62659
|
+
}
|
|
62660
|
+
}
|
|
62661
|
+
function getTypeBgColor(type) {
|
|
62662
|
+
switch (type) {
|
|
62663
|
+
case 'trend': return 'bg-green-50';
|
|
62664
|
+
case 'anomaly': return 'bg-red-50';
|
|
62665
|
+
case 'forecast': return 'bg-purple-50';
|
|
62666
|
+
case 'recommendation': return 'bg-amber-50';
|
|
62667
|
+
}
|
|
62668
|
+
}
|
|
62669
|
+
function getConfidenceBadge(confidence) {
|
|
62670
|
+
const pct = Math.round(confidence * 100);
|
|
62671
|
+
let colorClasses;
|
|
62672
|
+
if (confidence >= 0.8) {
|
|
62673
|
+
colorClasses = 'bg-green-100 text-green-700';
|
|
62674
|
+
}
|
|
62675
|
+
else if (confidence >= 0.6) {
|
|
62676
|
+
colorClasses = 'bg-yellow-100 text-yellow-700';
|
|
62677
|
+
}
|
|
62678
|
+
else {
|
|
62679
|
+
colorClasses = 'bg-red-100 text-red-700';
|
|
62680
|
+
}
|
|
62681
|
+
return (jsxs("span", { className: `inline-flex items-center text-[10px] font-medium px-1.5 py-0.5 rounded-full ${colorClasses}`, children: [pct, "%"] }));
|
|
62682
|
+
}
|
|
62683
|
+
function formatRelativeTime(date) {
|
|
62684
|
+
const now = new Date();
|
|
62685
|
+
const diffMs = now.getTime() - date.getTime();
|
|
62686
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
62687
|
+
const diffHours = Math.floor(diffMs / 3600000);
|
|
62688
|
+
const diffDays = Math.floor(diffMs / 86400000);
|
|
62689
|
+
if (diffMins < 1)
|
|
62690
|
+
return 'Just now';
|
|
62691
|
+
if (diffMins < 60)
|
|
62692
|
+
return `${diffMins}m ago`;
|
|
62693
|
+
if (diffHours < 24)
|
|
62694
|
+
return `${diffHours}h ago`;
|
|
62695
|
+
if (diffDays < 7)
|
|
62696
|
+
return `${diffDays}d ago`;
|
|
62697
|
+
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
|
|
62698
|
+
}
|
|
62699
|
+
/**
|
|
62700
|
+
* InsightsPanelUI - Structured display of analytics insights.
|
|
62701
|
+
*
|
|
62702
|
+
* Renders a header with title and refresh button, filter chips
|
|
62703
|
+
* (All / Trends / Anomalies / Forecasts / Recommendations), and
|
|
62704
|
+
* insight cards with type icon, title, summary, confidence badge,
|
|
62705
|
+
* and relative timestamp. Includes loading skeleton and empty state.
|
|
62706
|
+
*
|
|
62707
|
+
* @example
|
|
62708
|
+
* ```tsx
|
|
62709
|
+
* <InsightsPanelUI
|
|
62710
|
+
* insights={insights}
|
|
62711
|
+
* isLoading={loading}
|
|
62712
|
+
* filter={activeFilter}
|
|
62713
|
+
* maxInsights={8}
|
|
62714
|
+
* onFilterChange={setFilter}
|
|
62715
|
+
* onRefresh={refreshInsights}
|
|
62716
|
+
* />
|
|
62717
|
+
* ```
|
|
62718
|
+
*/
|
|
62719
|
+
const InsightsPanelUI = forwardRef(({ insights, isLoading = false, filter = 'all', maxInsights, onFilterChange, onRefresh, className = '', }, ref) => {
|
|
62720
|
+
const filtered = filter === 'all'
|
|
62721
|
+
? insights
|
|
62722
|
+
: insights.filter((i) => i.type === filter);
|
|
62723
|
+
const displayed = maxInsights ? filtered.slice(0, maxInsights) : filtered;
|
|
62724
|
+
return (jsxs("div", { ref: ref, className: `bg-white rounded-lg border border-paper-200 ${className}`, children: [jsxs("div", { className: "flex items-center justify-between px-5 py-4 border-b border-paper-200", children: [jsx("h3", { className: "text-lg font-semibold text-ink-900", children: "AI Insights" }), onRefresh && (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: jsx(RefreshCw, { className: `w-4 h-4 ${isLoading ? 'animate-spin' : ''}` }) }))] }), onFilterChange && (jsx("div", { className: "px-5 pt-3 pb-1 flex flex-wrap gap-2", children: FILTER_OPTIONS.map((opt) => (jsx("button", { onClick: () => onFilterChange(opt.key), className: `text-xs font-medium px-3 py-1.5 rounded-full transition-colors ${filter === opt.key
|
|
62725
|
+
? 'bg-primary-500 text-white'
|
|
62726
|
+
: 'bg-paper-100 text-ink-600 hover:bg-paper-200'}`, children: opt.label }, opt.key))) })), jsxs("div", { className: "p-5 space-y-3", children: [isLoading && displayed.length === 0 && (jsx("div", { className: "space-y-3", children: [1, 2, 3].map((i) => (jsxs("div", { className: "animate-pulse rounded-lg border border-paper-200 p-4", children: [jsxs("div", { className: "flex items-center gap-3 mb-2", children: [jsx("div", { className: "w-8 h-8 bg-paper-200 rounded-lg" }), jsxs("div", { className: "flex-1", children: [jsx("div", { className: "h-4 bg-paper-200 rounded w-2/3 mb-1" }), jsx("div", { className: "h-3 bg-paper-100 rounded w-1/3" })] })] }), jsx("div", { className: "h-3 bg-paper-100 rounded w-full mb-1" }), jsx("div", { className: "h-3 bg-paper-100 rounded w-4/5" })] }, i))) })), !isLoading && displayed.length === 0 && (jsxs("div", { className: "text-center py-8", children: [jsx(BrainCircuit, { className: "w-10 h-10 text-ink-300 mx-auto mb-3" }), jsx("p", { className: "text-ink-500 text-sm", children: filter === 'all'
|
|
62727
|
+
? 'No insights available yet.'
|
|
62728
|
+
: `No ${filter} insights found.` })] })), displayed.map((insight) => (jsx("div", { className: "rounded-lg border border-paper-200 p-4 hover:shadow-sm transition-shadow", children: jsxs("div", { className: "flex items-start gap-3", children: [jsx("div", { className: `flex-shrink-0 w-8 h-8 rounded-lg flex items-center justify-center ${getTypeBgColor(insight.type)}`, children: getTypeIcon(insight.type) }), jsxs("div", { className: "flex-1 min-w-0", children: [jsxs("div", { className: "flex items-center justify-between gap-2 mb-1", children: [jsx("h4", { className: "text-sm font-medium text-ink-900 truncate", children: insight.title }), getConfidenceBadge(insight.confidence)] }), jsx("p", { className: "text-xs text-ink-600 leading-relaxed", children: insight.summary }), jsx("p", { className: "text-[10px] text-ink-400 mt-1.5", children: formatRelativeTime(insight.timestamp) })] })] }) }, insight.id)))] })] }));
|
|
62729
|
+
});
|
|
62730
|
+
InsightsPanelUI.displayName = 'InsightsPanelUI';
|
|
62731
|
+
|
|
62732
|
+
export { Accordion, AchievementBadge, AchievementUnlock, ActionBar, ActionBarCenter, ActionBarLeft, ActionBarRight, ActionButton, ActionCard, ActivityFeed, AdminModal, Alert, AlertDialog, AnomalyBanner, AppLayout, Autocomplete, Avatar, BREAKPOINTS, Badge, BottomNavigation, BottomNavigationSpacer, BottomSheet, BottomSheetActions, BottomSheetContent, BottomSheetHeader, Box, Breadcrumbs, Button, ButtonGroup, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CardView, Carousel, CaseQueueItem, Celebration, ChatUI, Checkbox, CheckboxList, Chip, ChipGroup, CollaboratorAvatars, Collapsible, CollapsibleSection, ColorPicker, Combobox, ComingSoon, CommandPalette, CompactStat, ConfidenceBadge, ConfidenceIndicator, ConfirmDialog, ContextMenu, ControlBar, CurrencyDisplay, CurrencyInput, Dashboard, DashboardContent, DashboardHeader, DataGrid, DataTable, DataTableCardView, DateDisplay, DatePicker, DateRangePicker, DateTimePicker, DesktopOnly, Drawer, DrawerFooter, DropZone, Dropdown, DropdownTrigger, EmptyState, EntityCard, ErrorBoundary, ExpandablePanel, ExpandablePanelContainer, ExpandablePanelSpacer, ExpandableRowButton, ExpandableToolbar, ExpandedRowEditForm, ExportButton, FORMULA_CATEGORIES, FORMULA_DEFINITIONS, FORMULA_NAMES, FieldArray, FileUpload, FilterBar, FilterControls, FilterStatusBanner, FloatingActionButton, Form, FormContext, FormControl, FormWizard, FunnelChart, Grid, GridItem, HelpTooltip, Hide, HorizontalScroll, HoverCard, InfiniteScroll, Input, InsightsPanelUI, InviteCard, KanbanBoard, Layout, Loading, LoadingOverlay, Logo, MarkdownEditor, MaskedInput, MatchIndicator, Menu, MenuDivider, MobileHeader, MobileHeaderSpacer, MobileLayout, MobileOnly, MobileProvider, Modal, ModalFooter, MotivationalMessage, MultiSelect, NotificationBanner, NotificationBar, NotificationBell, NotificationIndicator, NumberInput, Page, PageHeader, PageLayout, PageNavigation, Pagination, PasswordInput, PermissionBadge, PersonaDashboard, PivotTable, Popover, PriorityAlertBanner, ProcessHealthBar, ProcessIndicator, Progress, ProgressCelebration, PullToRefresh, QueryTransparency, RadioGroup, Rating, Responsive, ReviewDecisionCard, RichTextEditor, SLAIndicator, SearchBar, SearchableList, Select, Separator, SharedBadge, Show, Sidebar, SidebarGroup, Skeleton, SkeletonCard$1 as SkeletonCard, SkeletonTable, SkipLink, Slider, SplitPane, Spreadsheet, SpreadsheetReport, Stack, StatCard, StatItem, StatsCardGrid, StatsGrid, StatusBadge, StatusBar, StepIndicator, Stepper, StreakBadge, SuccessCheck, SummaryCard, SwipeActions, SwipeableCard, SwipeableListItem, Switch, SystemActionEntry, Tabs, TabsContent, TabsList, TabsRoot, TabsTrigger, Text, Textarea, ThemeToggle, TimePicker, Timeline, TimezoneSelector, Toast, ToastContainer, Tooltip, Transfer, TreeView, TwoColumnContent, UserProfileButton, VarianceDisplay, addErrorMessage, addInfoMessage, addSuccessMessage, addWarningMessage, calculateColumnWidth, createActionsSection, createFiltersSection, createMultiSheetExcel, createPageControlsSection, createQueryDetailsSection, exportDataTableToExcel, exportToExcel, formatStatisticValue, formatStatistics, getFormula, getFormulasByCategory, getLocalTimezone, isValidTimezone, loadColumnOrder, loadColumnWidths, reorderArray, saveColumnOrder, saveColumnWidths, searchFormulas, statusManager, useBreadcrumbReset, useBreakpoint, useBreakpointValue, useCelebration, useColumnReorder, useColumnResize, useCommandPalette, useConfirmDialog, useDelighters, useFABScroll, useFormContext, useIsDesktop, useIsMobile, useIsTablet, useIsTouchDevice, useMediaQuery, useMobileContext, useOrientation, usePrefersMobile, useResponsiveCallback, useSafeAreaInsets, useViewportSize, withMobileContext };
|
|
62581
62733
|
//# sourceMappingURL=index.esm.js.map
|