@sybilion/uilib 1.3.9 → 1.3.11

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.
Files changed (74) hide show
  1. package/dist/esm/components/ui/ChartAreaInteractive/ChartAreaInteractive.js +4 -2
  2. package/dist/esm/components/ui/Chat/ChatChrome/ChatChrome.js +52 -17
  3. package/dist/esm/components/ui/Chat/ChatChrome/ChatChrome.styl.js +2 -2
  4. package/dist/esm/components/ui/Chat/ChatMessage/ChatMessage.styl.js +2 -2
  5. package/dist/esm/components/ui/Chat/ChatMessage/UserCsvAttachmentBubble.js +3 -4
  6. package/dist/esm/components/ui/Chat/ChatPrompt/ChatPrompt.js +6 -4
  7. package/dist/esm/components/ui/Chat/ChatPrompt/ChatPrompt.styl.js +2 -2
  8. package/dist/esm/components/ui/Chat/ChatPrompt/ChatPromptAttachments.js +11 -0
  9. package/dist/esm/components/ui/Chat/ChatSheet/ChatSelector.js +1 -1
  10. package/dist/esm/components/ui/Chat/ChatSheet/useChatPanelChromeModel.js +4 -1
  11. package/dist/esm/components/ui/Chat/chatAttachmentAccept.js +54 -0
  12. package/dist/esm/components/ui/Chat/chatAttachmentExtract.js +26 -0
  13. package/dist/esm/components/ui/Chat/chatPdfExtract.js +31 -0
  14. package/dist/esm/components/ui/DropZone/DropZone.js +50 -21
  15. package/dist/esm/components/ui/DropZone/DropZone.styl.js +2 -2
  16. package/dist/esm/components/ui/FileChip/FileChip.js +26 -0
  17. package/dist/esm/components/ui/FileChip/FileChip.styl.js +7 -0
  18. package/dist/esm/index.js +2 -0
  19. package/dist/esm/types/src/components/ui/ChartAreaInteractive/ChartAreaInteractive.d.ts +1 -1
  20. package/dist/esm/types/src/components/ui/ChartAreaInteractive/ChartAreaInteractive.types.d.ts +2 -0
  21. package/dist/esm/types/src/components/ui/Chat/Chat.types.d.ts +10 -1
  22. package/dist/esm/types/src/components/ui/Chat/ChatChrome/ChatChrome.d.ts +1 -1
  23. package/dist/esm/types/src/components/ui/Chat/ChatChrome/ChatChrome.types.d.ts +9 -2
  24. package/dist/esm/types/src/components/ui/Chat/ChatChrome/index.d.ts +1 -1
  25. package/dist/esm/types/src/components/ui/Chat/ChatPrompt/ChatPrompt.d.ts +1 -1
  26. package/dist/esm/types/src/components/ui/Chat/ChatPrompt/ChatPromptAttachments.d.ts +8 -0
  27. package/dist/esm/types/src/components/ui/Chat/ChatSheet/useChatPanelChromeModel.d.ts +7 -1
  28. package/dist/esm/types/src/components/ui/Chat/chatAttachmentAccept.d.ts +8 -0
  29. package/dist/esm/types/src/components/ui/Chat/chatAttachmentExtract.d.ts +2 -0
  30. package/dist/esm/types/src/components/ui/Chat/chatPdfExtract.d.ts +2 -0
  31. package/dist/esm/types/src/components/ui/Chat/index.d.ts +2 -1
  32. package/dist/esm/types/src/components/ui/DropZone/DropZone.d.ts +2 -0
  33. package/dist/esm/types/src/components/ui/FileChip/FileChip.d.ts +2 -0
  34. package/dist/esm/types/src/components/ui/FileChip/FileChip.types.d.ts +10 -0
  35. package/dist/esm/types/src/components/ui/FileChip/index.d.ts +2 -0
  36. package/dist/esm/types/src/docs/pages/ChatAttachmentsDropzonePage.d.ts +1 -0
  37. package/dist/esm/types/src/docs/pages/FileChipPage.d.ts +1 -0
  38. package/dist/esm/types/src/index.d.ts +1 -0
  39. package/package.json +2 -1
  40. package/src/components/ui/ChartAreaInteractive/ChartAreaInteractive.tsx +4 -1
  41. package/src/components/ui/ChartAreaInteractive/ChartAreaInteractive.types.ts +2 -0
  42. package/src/components/ui/Chat/Chat.types.ts +11 -1
  43. package/src/components/ui/Chat/ChatChrome/ChatChrome.styl +20 -0
  44. package/src/components/ui/Chat/ChatChrome/ChatChrome.styl.d.ts +2 -0
  45. package/src/components/ui/Chat/ChatChrome/ChatChrome.tsx +88 -4
  46. package/src/components/ui/Chat/ChatChrome/ChatChrome.types.ts +18 -2
  47. package/src/components/ui/Chat/ChatChrome/index.ts +1 -0
  48. package/src/components/ui/Chat/ChatMessage/ChatMessage.styl +0 -56
  49. package/src/components/ui/Chat/ChatMessage/ChatMessage.styl.d.ts +0 -5
  50. package/src/components/ui/Chat/ChatMessage/UserCsvAttachmentBubble.tsx +6 -15
  51. package/src/components/ui/Chat/ChatPrompt/ChatPrompt.styl +11 -15
  52. package/src/components/ui/Chat/ChatPrompt/ChatPrompt.styl.d.ts +2 -1
  53. package/src/components/ui/Chat/ChatPrompt/ChatPrompt.tsx +17 -8
  54. package/src/components/ui/Chat/ChatPrompt/ChatPromptAttachments.tsx +34 -0
  55. package/src/components/ui/Chat/ChatSheet/ChatSelector.tsx +12 -11
  56. package/src/components/ui/Chat/ChatSheet/ChatSheet.styl.d.ts +13 -13
  57. package/src/components/ui/Chat/ChatSheet/useChatPanelChromeModel.tsx +14 -0
  58. package/src/components/ui/Chat/chat-preset-utils.ts +4 -1
  59. package/src/components/ui/Chat/chatAttachmentAccept.ts +70 -0
  60. package/src/components/ui/Chat/chatAttachmentExtract.ts +33 -0
  61. package/src/components/ui/Chat/chatPdfExtract.ts +37 -0
  62. package/src/components/ui/Chat/index.ts +5 -0
  63. package/src/components/ui/DropZone/DropZone.styl +24 -0
  64. package/src/components/ui/DropZone/DropZone.styl.d.ts +3 -0
  65. package/src/components/ui/DropZone/DropZone.tsx +77 -24
  66. package/src/components/ui/FileChip/FileChip.styl +108 -0
  67. package/src/components/ui/FileChip/FileChip.styl.d.ts +12 -0
  68. package/src/components/ui/FileChip/FileChip.tsx +93 -0
  69. package/src/components/ui/FileChip/FileChip.types.ts +11 -0
  70. package/src/components/ui/FileChip/index.ts +2 -0
  71. package/src/docs/pages/ChatAttachmentsDropzonePage.tsx +162 -0
  72. package/src/docs/pages/FileChipPage.tsx +50 -0
  73. package/src/docs/registry.ts +12 -0
  74. package/src/index.ts +1 -0
@@ -16,7 +16,7 @@ import { ThresholdsOverlay } from './overlays/ThresholdsOverlay/ThresholdsOverla
16
16
  const chartConfig = {
17
17
  // Chart now supports light/dark themes with dynamic colors
18
18
  };
19
- function ChartAreaInteractive({ className, chartContainerClassName, legendClassName, xAxisClassName, yAxisClassName, timeRange, onTimeRangeChange, pinMonth, onPinMonthChange, onPreviewMonthChange, chartData, forecastData, error, loading = false, isDarkTheme = false, footerActions, mode, selectedForecast, upperQuantiles, lowerQuantiles, selectedLowerQuantile, selectedUpperQuantile, onLowerQuantileChange, onUpperQuantileChange, lowerThreshold, upperThreshold, onLowerThresholdChange, onUpperThresholdChange, discreteThresholdValues, headerActions, excludeLegendIds, loadingAnalyses, onLegendClick, onAnalysisSelect, disableTimeRangeSelector, forecastLineStyle = 'dashed', selectedAnalysisId, chartRenderId, toggleLegendSeries, ensureAnalysisSeriesVisible, overlayForecastData = {}, hiddenSeries, disableForecastHistoricalBridge, overlayElements: overlayElementsProp, ...restProps }) {
19
+ function ChartAreaInteractive({ className, chartContainerClassName, legendClassName, xAxisClassName, yAxisClassName, timeRange, onTimeRangeChange, pinMonth, onPinMonthChange, onPreviewMonthChange, chartData, forecastData, error, loading = false, isDarkTheme = false, footerActions, mode, selectedForecast, upperQuantiles, lowerQuantiles, selectedLowerQuantile, selectedUpperQuantile, onLowerQuantileChange, onUpperQuantileChange, lowerThreshold, upperThreshold, onLowerThresholdChange, onUpperThresholdChange, discreteThresholdValues, headerActions, excludeLegendIds, loadingAnalyses, onLegendClick, onAnalysisSelect, disableTimeRangeSelector, enableTimeRangeBrush = false, forecastLineStyle = 'dashed', selectedAnalysisId, chartRenderId, toggleLegendSeries, ensureAnalysisSeriesVisible, overlayForecastData = {}, hiddenSeries, disableForecastHistoricalBridge, overlayElements: overlayElementsProp, ...restProps }) {
20
20
  const seriesHidden = hiddenSeries ?? new Set();
21
21
  const hiddenSeriesRef = useRef(seriesHidden);
22
22
  const prevSelectedAnalysisIdRef = useRef(selectedAnalysisId);
@@ -95,7 +95,9 @@ function ChartAreaInteractive({ className, chartContainerClassName, legendClassN
95
95
  // loadingAnalyses,
96
96
  ...restProps,
97
97
  };
98
- const brushEnabled = !disableTimeRangeSelector && !loading && bridgedChartData.length > 1;
98
+ const brushEnabled = (!disableTimeRangeSelector || enableTimeRangeBrush) &&
99
+ !loading &&
100
+ bridgedChartData.length > 1;
99
101
  const renderChart = () => {
100
102
  const overlayClassName = cn(chartContainerClassName);
101
103
  switch (mode) {
@@ -1,17 +1,52 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import cn from 'classnames';
3
- import { useEffect } from 'react';
3
+ import { useMemo, useState, useCallback, useEffect } from 'react';
4
4
  import { displayLabelForBranchKeyFromMessages, humanizeBranchKey } from '../ChatMessage/presetScript.js';
5
5
  import { TextShimmer } from '../../TextShimmer/TextShimmer.js';
6
6
  import { Scroll } from '@homecode/ui';
7
7
  import { X, PaperPlaneRightIcon, ChartLineIcon } from '@phosphor-icons/react';
8
8
  import { Button } from '../../Button/Button.js';
9
+ import { DropZone } from '../../DropZone/DropZone.js';
9
10
  import { PanelResizeHandle } from '../../Sidebar/Sidebar.js';
10
11
  import SidebarStem from '../../Sidebar/Sidebar.styl.js';
11
12
  import { Chat } from '../Chat.js';
13
+ import { filterToTextAttachments, isAttachmentsDropzoneEnabled, buildAcceptAttr } from '../chatAttachmentAccept.js';
14
+ import { extractChatAttachmentItems } from '../chatAttachmentExtract.js';
12
15
  import S from './ChatChrome.styl.js';
13
16
 
14
- function ChatChrome({ showResizeHandle, resizeHandle, onClose, isEmpty, renderPresets, messages, onQuickReply, suppressedQuickReplyKeys, isLoading, scriptContinueLabel, onScriptContinue, renderMessageChart, showBranchActionsRow, showSyntheticBranchButtons, unusedBranchKeys, isScriptComplete, onGenerateDashboard, generatingDashboard, onGenerateDashboardClick, showInlinePresets, isLastMessageFromUser, scrollRef, effectiveScopeId, onPromptSubmit, onChatDeleted, promptPrefill, footerClassName, emptyState, }) {
17
+ function ChatChrome({ showResizeHandle, resizeHandle, onClose, isEmpty, renderPresets, messages, onQuickReply, suppressedQuickReplyKeys, isLoading, scriptContinueLabel, onScriptContinue, renderMessageChart, showBranchActionsRow, showSyntheticBranchButtons, unusedBranchKeys, isScriptComplete, onGenerateDashboard, generatingDashboard, onGenerateDashboardClick, showInlinePresets, isLastMessageFromUser, scrollRef, effectiveScopeId, onPromptSubmit, onChatDeleted, promptPrefill, footerClassName, emptyState, allowedAttachments, allowPdfAttachments = false, onAttachmentsDropped, }) {
18
+ const filteredAllowedAttachments = useMemo(() => filterToTextAttachments(allowedAttachments), [allowedAttachments]);
19
+ const attachmentsDropzoneEnabled = isAttachmentsDropzoneEnabled(allowedAttachments, allowPdfAttachments);
20
+ const attachmentAccept = useMemo(() => buildAcceptAttr(filteredAllowedAttachments, allowPdfAttachments), [filteredAllowedAttachments, allowPdfAttachments]);
21
+ const [pendingAttachments, setPendingAttachments] = useState([]);
22
+ const [isExtractingAttachments, setIsExtractingAttachments] = useState(false);
23
+ const promptBusy = isLoading || isExtractingAttachments;
24
+ const handleAttachmentFiles = useCallback((files) => {
25
+ if (promptBusy || files.length === 0)
26
+ return;
27
+ setIsExtractingAttachments(true);
28
+ void extractChatAttachmentItems(files, allowPdfAttachments)
29
+ .then(items => {
30
+ if (items.length > 0) {
31
+ setPendingAttachments(prev => [...prev, ...items]);
32
+ }
33
+ })
34
+ .finally(() => setIsExtractingAttachments(false));
35
+ }, [allowPdfAttachments, promptBusy]);
36
+ const handleRemoveAttachment = useCallback((index) => {
37
+ setPendingAttachments(prev => prev.filter((_, i) => i !== index));
38
+ }, []);
39
+ const handlePromptSubmitWithAttachments = useCallback((message, submittedAttachments) => {
40
+ const trimmed = message.trim();
41
+ const attachments = submittedAttachments ?? [];
42
+ if (!trimmed && attachments.length === 0)
43
+ return;
44
+ void onPromptSubmit(trimmed, attachments);
45
+ if (attachments.length > 0 && onAttachmentsDropped) {
46
+ void onAttachmentsDropped(attachments);
47
+ }
48
+ setPendingAttachments([]);
49
+ }, [onAttachmentsDropped, onPromptSubmit]);
15
50
  useEffect(() => {
16
51
  if (isEmpty)
17
52
  return;
@@ -28,21 +63,21 @@ function ChatChrome({ showResizeHandle, resizeHandle, onClose, isEmpty, renderPr
28
63
  if (inner)
29
64
  setTimeout(scrollToBottom, 100);
30
65
  }, [isEmpty, messages.length]);
31
- return (jsxs("div", { className: S.root, children: [showResizeHandle && resizeHandle ? (jsx(PanelResizeHandle, { edge: "leading", isActive: resizeHandle.isActive, startWidthPx: resizeHandle.startWidthPx, getShellWidth: resizeHandle.getShellWidth, onDragWidth: resizeHandle.onDragWidth, onDragComplete: resizeHandle.onDragComplete, className: cn(SidebarStem.sidebarResizeHandle, S.chatResizeHandle) })) : null, jsx("div", { className: S.panelHeader, children: onClose ? (jsx(Button, { type: "button", variant: "ghost", icon: true, className: S.panelClose, "aria-label": "Close chat", onClick: onClose, children: jsx(X, { className: "size-4" }) })) : null }), jsx("div", { className: S.content, children: jsxs(Chat, { isEmpty: isEmpty, scopeId: effectiveScopeId, onChatDeleted: onChatDeleted, children: [isEmpty ? (jsxs(Fragment, { children: [jsx(Chat.EmptyState, { ...emptyState }), renderPresets('fixed')] })) : (jsx("div", { className: S.scrollWrapper, children: jsxs(Scroll, { y: true, yScrollbarClassName: S.scrollbar, className: S.scroll, innerClassName: S.scrollInner, offset: { y: { before: 56, after: 180 } }, fadeSize: "m", autoHide: true, ref: scrollRef, children: [messages.map((msg, index, arr) => {
32
- const isLast = index === arr.length - 1;
33
- return (jsx(Chat.Message, { role: msg.role, text: msg.text, userCsvAttachment: msg.userCsvAttachment, onQuickReply: onQuickReply, suppressedQuickReplyKeys: suppressedQuickReplyKeys, quickReplyDisabled: isLoading, isLastMessage: isLast, scriptContinue: isLast && scriptContinueLabel
34
- ? { label: scriptContinueLabel }
35
- : undefined, onScriptContinue: isLast && scriptContinueLabel
36
- ? onScriptContinue
37
- : undefined, renderMessageChart: renderMessageChart }, msg.id));
38
- }), showBranchActionsRow && (jsxs("div", { className: S.branchRow, children: [showSyntheticBranchButtons
39
- ? unusedBranchKeys.map(key => {
40
- const label = displayLabelForBranchKeyFromMessages(key, messages) ?? humanizeBranchKey(key);
41
- return (jsx("span", { className: S.branchBtnWrap, children: jsxs(Button, { type: "button", variant: "outline", size: "sm", disabled: isLoading, onClick: () => onQuickReply(key, label), children: [jsx(PaperPlaneRightIcon, {}), label] }) }, key));
42
- })
43
- : null, isScriptComplete &&
44
- onGenerateDashboard &&
45
- !generatingDashboard ? (jsxs(Button, { type: "button", variant: "default", size: "lg", disabled: isLoading, onClick: onGenerateDashboardClick, children: [jsx(ChartLineIcon, {}), "Generate Dashboard"] })) : null] })), showInlinePresets && renderPresets('inline'), isLoading && isLastMessageFromUser && (jsx(TextShimmer, { duration: 1, spread: 5, className: S.loader, children: "Thinking..." }))] }) })), jsx("div", { className: cn(S.footer, footerClassName), children: jsx(Chat.Prompt, { onSubmit: onPromptSubmit, disabled: isLoading, prefillMessage: promptPrefill ?? undefined, showNotice: isEmpty }) })] }) })] }));
66
+ return (jsxs("div", { className: S.root, children: [showResizeHandle && resizeHandle ? (jsx(PanelResizeHandle, { edge: "leading", isActive: resizeHandle.isActive, startWidthPx: resizeHandle.startWidthPx, getShellWidth: resizeHandle.getShellWidth, onDragWidth: resizeHandle.onDragWidth, onDragComplete: resizeHandle.onDragComplete, className: cn(SidebarStem.sidebarResizeHandle, S.chatResizeHandle) })) : null, jsx("div", { className: S.panelHeader, children: onClose ? (jsx(Button, { type: "button", variant: "ghost", icon: true, className: S.panelClose, "aria-label": "Close chat", onClick: onClose, children: jsx(X, { className: "size-4" }) })) : null }), jsxs("div", { className: S.content, children: [attachmentsDropzoneEnabled ? (jsx(DropZone, { accept: attachmentAccept, label: "Drop text files to attach", multiple: true, ghost: true, overlayScope: "container", disabled: promptBusy, className: S.attachmentDropzone, onFiles: handleAttachmentFiles })) : null, jsxs(Chat, { isEmpty: isEmpty, scopeId: effectiveScopeId, onChatDeleted: onChatDeleted, children: [isEmpty ? (jsxs(Fragment, { children: [jsx(Chat.EmptyState, { ...emptyState }), renderPresets('fixed')] })) : (jsx("div", { className: S.scrollWrapper, children: jsxs(Scroll, { y: true, yScrollbarClassName: S.scrollbar, className: S.scroll, innerClassName: S.scrollInner, offset: { y: { before: 56, after: 180 } }, fadeSize: "m", autoHide: true, ref: scrollRef, children: [messages.map((msg, index, arr) => {
67
+ const isLast = index === arr.length - 1;
68
+ return (jsx(Chat.Message, { role: msg.role, text: msg.text, userCsvAttachment: msg.userCsvAttachment, onQuickReply: onQuickReply, suppressedQuickReplyKeys: suppressedQuickReplyKeys, quickReplyDisabled: isLoading, isLastMessage: isLast, scriptContinue: isLast && scriptContinueLabel
69
+ ? { label: scriptContinueLabel }
70
+ : undefined, onScriptContinue: isLast && scriptContinueLabel
71
+ ? onScriptContinue
72
+ : undefined, renderMessageChart: renderMessageChart }, msg.id));
73
+ }), showBranchActionsRow && (jsxs("div", { className: S.branchRow, children: [showSyntheticBranchButtons
74
+ ? unusedBranchKeys.map(key => {
75
+ const label = displayLabelForBranchKeyFromMessages(key, messages) ?? humanizeBranchKey(key);
76
+ return (jsx("span", { className: S.branchBtnWrap, children: jsxs(Button, { type: "button", variant: "outline", size: "sm", disabled: isLoading, onClick: () => onQuickReply(key, label), children: [jsx(PaperPlaneRightIcon, {}), label] }) }, key));
77
+ })
78
+ : null, isScriptComplete &&
79
+ onGenerateDashboard &&
80
+ !generatingDashboard ? (jsxs(Button, { type: "button", variant: "default", size: "lg", disabled: isLoading, onClick: onGenerateDashboardClick, children: [jsx(ChartLineIcon, {}), "Generate Dashboard"] })) : null] })), showInlinePresets && renderPresets('inline'), isLoading && isLastMessageFromUser && (jsx(TextShimmer, { duration: 1, spread: 5, className: S.loader, children: "Thinking..." }))] }) })), jsxs("div", { className: cn(S.footer, footerClassName), children: [isEmpty ? (jsx("div", { className: S.notice, children: "Forecast Assistant can make mistakes." })) : null, jsx(Chat.Prompt, { onSubmit: handlePromptSubmitWithAttachments, disabled: promptBusy, attachments: pendingAttachments, onRemoveAttachment: handleRemoveAttachment, prefillMessage: promptPrefill ?? undefined })] })] })] })] }));
46
81
  }
47
82
 
48
83
  export { ChatChrome };
@@ -1,7 +1,7 @@
1
1
  import styleInject from 'style-inject';
2
2
 
3
- var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.ChatChrome_root__oh4Ay{border-radius:var(--p-4);display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden;position:relative}.ChatChrome_chatResizeHandle__epfiT{background-color:var(--page-color);border-radius:2.5px;height:calc(100vh + 200px);left:0;opacity:0;position:absolute;right:auto;top:-200px;touch-action:none;transition:opacity .15s ease-out;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:5px;z-index:30}.ChatChrome_chatResizeHandle__epfiT:before{left:0;right:auto}.ChatChrome_panelHeader__Hkfit{align-items:center;display:flex;flex-shrink:0;justify-content:flex-end;min-height:70px;padding:var(--p-2) var(--p-3);position:absolute;width:100%;z-index:100}.ChatChrome_panelClose__DbKxz{flex-shrink:0}.ChatChrome_content__5qFEi{display:flex;flex:1;flex-direction:column;min-height:0;position:relative}.ChatChrome_scrollWrapper__m4HMu{flex:1;min-height:0;position:relative}.ChatChrome_scroll__oCxoJ{align-items:flex-end;height:100%;max-height:100%;max-width:100%;padding-bottom:var(--p-2);position:absolute;width:100%;z-index:3}.ChatChrome_scrollbar__Hu0aG{right:0!important}.ChatChrome_scrollInner__K9hIy{min-height:100%;padding-top:var(--p-10)}.ChatChrome_scrollInner__K9hIy:after{content:\"\";display:block;height:170px}.ChatChrome_footer__a5Bpp{backdrop-filter:blur(30px);background-color:var(--background-alpha-800);border-top:1px solid var(--border);bottom:0;box-shadow:0 0 20px 16px var(--background);display:flex;flex-direction:column;position:absolute;width:100%;z-index:50}.ChatChrome_loader__9-lnf{color:var(--muted-foreground);margin:var(--p-2) var(--p-6) var(--p-10)}.ChatChrome_branchRow__NMDNv{display:flex;flex-wrap:wrap;gap:8px;margin-top:var(--p-6);padding:0 var(--p-6);width:100%}.ChatChrome_branchBtnWrap__aOSVP{display:inline-flex;vertical-align:middle}";
4
- var S = {"root":"ChatChrome_root__oh4Ay","chatResizeHandle":"ChatChrome_chatResizeHandle__epfiT","panelHeader":"ChatChrome_panelHeader__Hkfit","panelClose":"ChatChrome_panelClose__DbKxz","content":"ChatChrome_content__5qFEi","scrollWrapper":"ChatChrome_scrollWrapper__m4HMu","scroll":"ChatChrome_scroll__oCxoJ","scrollbar":"ChatChrome_scrollbar__Hu0aG","scrollInner":"ChatChrome_scrollInner__K9hIy","footer":"ChatChrome_footer__a5Bpp","loader":"ChatChrome_loader__9-lnf","branchRow":"ChatChrome_branchRow__NMDNv","branchBtnWrap":"ChatChrome_branchBtnWrap__aOSVP"};
3
+ var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.ChatChrome_root__oh4Ay{border-radius:var(--p-4);display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden;position:relative}.ChatChrome_chatResizeHandle__epfiT{background-color:var(--page-color);border-radius:2.5px;height:calc(100vh + 200px);left:0;opacity:0;position:absolute;right:auto;top:-200px;touch-action:none;transition:opacity .15s ease-out;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:5px;z-index:30}.ChatChrome_chatResizeHandle__epfiT:before{left:0;right:auto}.ChatChrome_panelHeader__Hkfit{align-items:center;display:flex;flex-shrink:0;justify-content:flex-end;min-height:70px;padding:var(--p-2) var(--p-3);position:absolute;width:100%;z-index:100}.ChatChrome_panelClose__DbKxz{flex-shrink:0}.ChatChrome_content__5qFEi{display:flex;flex:1;flex-direction:column;min-height:0;position:relative}.ChatChrome_attachmentDropzone__OC8UI{inset:0;position:absolute;z-index:200}.ChatChrome_scrollWrapper__m4HMu{flex:1;min-height:0;position:relative}.ChatChrome_scroll__oCxoJ{align-items:flex-end;height:100%;max-height:100%;max-width:100%;padding-bottom:var(--p-2);position:absolute;width:100%;z-index:3}.ChatChrome_scrollbar__Hu0aG{right:0!important}.ChatChrome_scrollInner__K9hIy{min-height:100%;padding-top:var(--p-10)}.ChatChrome_scrollInner__K9hIy:after{content:\"\";display:block;height:170px}.ChatChrome_footer__a5Bpp{backdrop-filter:blur(30px);background-color:var(--background-alpha-800);border-top:1px solid var(--border);bottom:0;box-shadow:0 0 20px 16px var(--background);display:flex;flex-direction:column;position:absolute;width:100%;z-index:50}.ChatChrome_notice__JACIw{color:var(--muted-foreground);font-size:var(--text-xs);left:0;margin-bottom:var(--p-1);pointer-events:none;position:absolute;right:0;text-align:center;top:calc(var(--p-7)*-1)}@media (max-width:768px){.ChatChrome_notice__JACIw{font-size:10px}}.ChatChrome_loader__9-lnf{color:var(--muted-foreground);margin:var(--p-2) var(--p-6) var(--p-10)}.ChatChrome_branchRow__NMDNv{display:flex;flex-wrap:wrap;gap:8px;margin-top:var(--p-6);padding:0 var(--p-6);width:100%}.ChatChrome_branchBtnWrap__aOSVP{display:inline-flex;vertical-align:middle}";
4
+ var S = {"root":"ChatChrome_root__oh4Ay","chatResizeHandle":"ChatChrome_chatResizeHandle__epfiT","panelHeader":"ChatChrome_panelHeader__Hkfit","panelClose":"ChatChrome_panelClose__DbKxz","content":"ChatChrome_content__5qFEi","attachmentDropzone":"ChatChrome_attachmentDropzone__OC8UI","scrollWrapper":"ChatChrome_scrollWrapper__m4HMu","scroll":"ChatChrome_scroll__oCxoJ","scrollbar":"ChatChrome_scrollbar__Hu0aG","scrollInner":"ChatChrome_scrollInner__K9hIy","footer":"ChatChrome_footer__a5Bpp","notice":"ChatChrome_notice__JACIw","loader":"ChatChrome_loader__9-lnf","branchRow":"ChatChrome_branchRow__NMDNv","branchBtnWrap":"ChatChrome_branchBtnWrap__aOSVP"};
5
5
  styleInject(css_248z);
6
6
 
7
7
  export { S as default };
@@ -1,7 +1,7 @@
1
1
  import styleInject from 'style-inject';
2
2
 
3
- var css_248z = ".ChatMessage_root__6rnsF{background:var(--bg-secondary);display:flex;flex-direction:column;gap:var(--p-1);padding:var(--p-6)}.ChatMessage_text__Y1XNR{color:var(--text-secondary);font-size:var(--text-sm);max-width:100%;-webkit-user-select:text;-moz-user-select:text;user-select:text;width:-moz-fit-content;width:fit-content}.ChatMessage_role-user__u4JPV{align-items:flex-end}.ChatMessage_role-user__u4JPV .ChatMessage_userColumn__cQM6-{align-items:flex-end;display:flex;flex-direction:column;gap:var(--p-2);max-width:100%}.ChatMessage_role-user__u4JPV .ChatMessage_text__Y1XNR{background-color:var(--sb-slate-100);border-radius:var(--p-4);border-bottom-right-radius:0;padding:var(--p-3) var(--p-4);white-space:pre-wrap}.dark .ChatMessage_role-user__u4JPV .ChatMessage_text__Y1XNR{background-color:var(--sb-gray-800)}.ChatMessage_role-user__u4JPV .ChatMessage_userCsvCard__D1M7y{align-items:center;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--background);border:0;border-radius:var(--p-3);box-shadow:0 0 0 1px var(--border);cursor:pointer;display:flex;font:inherit;gap:var(--p-2);margin:0;max-width:100%;padding:var(--p-3);padding-right:var(--p-4);text-align:left;transition:background-color .15s;width:-moz-fit-content;width:fit-content}.ChatMessage_role-user__u4JPV .ChatMessage_userCsvCard__D1M7y:hover{background-color:var(--sb-gray-50)}.ChatMessage_role-user__u4JPV .ChatMessage_userCsvCard__D1M7y:focus-visible{outline:2px solid var(--ring);outline-offset:2px}.dark .ChatMessage_role-user__u4JPV .ChatMessage_userCsvCard__D1M7y{background-color:var(--sb-gray-800)}.dark .ChatMessage_role-user__u4JPV .ChatMessage_userCsvCard__D1M7y:hover{background-color:var(--sb-gray-900)}.ChatMessage_role-user__u4JPV .ChatMessage_userCsvCardIcon__0-KS6{align-items:center;display:flex;flex-shrink:0;height:32px;justify-content:center;width:32px}.ChatMessage_role-user__u4JPV .ChatMessage_userCsvCardContent__LoMGE{display:flex;flex:1;flex-direction:column;min-width:0}.ChatMessage_role-user__u4JPV .ChatMessage_userCsvCardTitle__9W76E{font-size:var(--text-sm);font-weight:500;line-height:1.4}.ChatMessage_role-user__u4JPV .ChatMessage_userCsvCardSubtitle__YZeHv{color:var(--muted-foreground);font-size:var(--text-xs);line-height:1.4}.ChatMessage_role-system__g13OP{align-items:center}.ChatMessage_role-system__g13OP .ChatMessage_text__Y1XNR{color:var(--muted-foreground);font-size:var(--text-xs);width:100%}.ChatMessage_role-assistant__wketE .ChatMessage_text__Y1XNR{width:100%}.ChatMessage_role-assistant__wketE h3{line-height:2.4}.ChatMessage_role-assistant__wketE h4{font-size:1.1em;font-weight:600;line-height:2.2}.ChatMessage_role-assistant__wketE .ChatMessage_bullet__6vAhq{display:inline-block;margin-left:4px;margin-right:6px}.ChatMessage_role-assistant__wketE .ChatMessage_bullet__6vAhq:before{color:var(--text-secondary);content:\"•\";display:inline-block}.ChatMessage_role-assistant__wketE .ChatMessage_scrollHorizontal__Rms9n{max-width:100%}.ChatMessage_role-assistant__wketE table{border:1px solid var(--border);border-collapse:collapse;border-radius:var(--p-2);border-spacing:0;margin:var(--p-4) 0;overflow:hidden}.ChatMessage_role-assistant__wketE table td,.ChatMessage_role-assistant__wketE table th{border:1px solid var(--border);min-width:100px;padding:var(--p-1)}.ChatMessage_role-assistant__wketE table th{text-align:left}.ChatMessage_role-assistant__wketE ol,.ChatMessage_role-assistant__wketE ul{padding-left:var(--p-4)}.ChatMessage_role-assistant__wketE ul{list-style-type:disc}.ChatMessage_role-assistant__wketE ol{list-style-type:decimal}.ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLink__Pxy-T{align-items:center;border:1px dashed var(--sb-slate-300);border-radius:8px;color:var(--foreground);display:inline-flex;font-size:var(--text-xs);gap:6px;margin:1px;max-width:100%;padding:2px 6px 2px 4px;text-decoration:none;vertical-align:middle}.ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLink__Pxy-T:hover{background-color:var(--sb-slate-50);border-color:var(--sb-slate-400);border-style:solid}.dark .ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLink__Pxy-T{border-color:var(--sb-gray-600)}.dark .ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLink__Pxy-T:hover{background-color:var(--sb-gray-900)}.ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLinkLabel__PMU7e{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ChatMessage_role-assistant__wketE .ChatMessage_quickReplyWrap__1UFyD{display:inline-block;margin:var(--p-1) var(--p-1) var(--p-1) 0;vertical-align:middle}.ChatMessage_role-assistant__wketE .ChatMessage_downloadButtons__RygM-{display:flex;gap:var(--p-2);margin-top:var(--p-4)}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCard__NsNRa{align-items:center;background-color:var(--background);border-radius:var(--p-3);box-shadow:0 0 0 1px var(--border);cursor:pointer;display:flex;gap:var(--p-4);margin-top:var(--p-3);padding:var(--p-3);padding-right:var(--p-4);transition:all .15s;width:-moz-fit-content;width:fit-content}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCard__NsNRa:hover{background-color:var(--sb-gray-50);border-color:var(--border)}.dark .ChatMessage_role-assistant__wketE .ChatMessage_downloadCard__NsNRa{background-color:var(--sb-gray-900);border-color:var(--border)}.dark .ChatMessage_role-assistant__wketE .ChatMessage_downloadCard__NsNRa:hover{background-color:var(--sb-gray-800)}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCardIcon__jkxDJ{align-items:center;border-radius:var(--p-2);display:flex;flex-shrink:0;height:32px;justify-content:center;width:32px}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCardContent__PTPwz{display:flex;flex:1;flex-direction:column;min-width:0}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCardTitle__K1wqr{font-size:var(--text-base);font-weight:600;line-height:1.4}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCardSubtitle__fVeF2{color:var(--muted-foreground);font-size:var(--text-sm);line-height:1.4}";
4
- var S = {"root":"ChatMessage_root__6rnsF","text":"ChatMessage_text__Y1XNR","role-user":"ChatMessage_role-user__u4JPV","userColumn":"ChatMessage_userColumn__cQM6-","userCsvCard":"ChatMessage_userCsvCard__D1M7y","userCsvCardIcon":"ChatMessage_userCsvCardIcon__0-KS6","userCsvCardContent":"ChatMessage_userCsvCardContent__LoMGE","userCsvCardTitle":"ChatMessage_userCsvCardTitle__9W76E","userCsvCardSubtitle":"ChatMessage_userCsvCardSubtitle__YZeHv","role-system":"ChatMessage_role-system__g13OP","role-assistant":"ChatMessage_role-assistant__wketE","bullet":"ChatMessage_bullet__6vAhq","scrollHorizontal":"ChatMessage_scrollHorizontal__Rms9n","datasetAppLink":"ChatMessage_datasetAppLink__Pxy-T","datasetAppLinkLabel":"ChatMessage_datasetAppLinkLabel__PMU7e","quickReplyWrap":"ChatMessage_quickReplyWrap__1UFyD","downloadButtons":"ChatMessage_downloadButtons__RygM-","downloadCard":"ChatMessage_downloadCard__NsNRa","downloadCardIcon":"ChatMessage_downloadCardIcon__jkxDJ","downloadCardContent":"ChatMessage_downloadCardContent__PTPwz","downloadCardTitle":"ChatMessage_downloadCardTitle__K1wqr","downloadCardSubtitle":"ChatMessage_downloadCardSubtitle__fVeF2"};
3
+ var css_248z = ".ChatMessage_root__6rnsF{background:var(--bg-secondary);display:flex;flex-direction:column;gap:var(--p-1);padding:var(--p-6)}.ChatMessage_text__Y1XNR{color:var(--text-secondary);font-size:var(--text-sm);max-width:100%;-webkit-user-select:text;-moz-user-select:text;user-select:text;width:-moz-fit-content;width:fit-content}.ChatMessage_role-user__u4JPV{align-items:flex-end}.ChatMessage_role-user__u4JPV .ChatMessage_userColumn__cQM6-{align-items:flex-end;display:flex;flex-direction:column;gap:var(--p-2);max-width:100%}.ChatMessage_role-user__u4JPV .ChatMessage_text__Y1XNR{background-color:var(--sb-slate-100);border-radius:var(--p-4);border-bottom-right-radius:0;padding:var(--p-3) var(--p-4);white-space:pre-wrap}.dark .ChatMessage_role-user__u4JPV .ChatMessage_text__Y1XNR{background-color:var(--sb-gray-800)}.ChatMessage_role-system__g13OP{align-items:center}.ChatMessage_role-system__g13OP .ChatMessage_text__Y1XNR{color:var(--muted-foreground);font-size:var(--text-xs);width:100%}.ChatMessage_role-assistant__wketE .ChatMessage_text__Y1XNR{width:100%}.ChatMessage_role-assistant__wketE h3{line-height:2.4}.ChatMessage_role-assistant__wketE h4{font-size:1.1em;font-weight:600;line-height:2.2}.ChatMessage_role-assistant__wketE .ChatMessage_bullet__6vAhq{display:inline-block;margin-left:4px;margin-right:6px}.ChatMessage_role-assistant__wketE .ChatMessage_bullet__6vAhq:before{color:var(--text-secondary);content:\"•\";display:inline-block}.ChatMessage_role-assistant__wketE .ChatMessage_scrollHorizontal__Rms9n{max-width:100%}.ChatMessage_role-assistant__wketE table{border:1px solid var(--border);border-collapse:collapse;border-radius:var(--p-2);border-spacing:0;margin:var(--p-4) 0;overflow:hidden}.ChatMessage_role-assistant__wketE table td,.ChatMessage_role-assistant__wketE table th{border:1px solid var(--border);min-width:100px;padding:var(--p-1)}.ChatMessage_role-assistant__wketE table th{text-align:left}.ChatMessage_role-assistant__wketE ol,.ChatMessage_role-assistant__wketE ul{padding-left:var(--p-4)}.ChatMessage_role-assistant__wketE ul{list-style-type:disc}.ChatMessage_role-assistant__wketE ol{list-style-type:decimal}.ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLink__Pxy-T{align-items:center;border:1px dashed var(--sb-slate-300);border-radius:8px;color:var(--foreground);display:inline-flex;font-size:var(--text-xs);gap:6px;margin:1px;max-width:100%;padding:2px 6px 2px 4px;text-decoration:none;vertical-align:middle}.ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLink__Pxy-T:hover{background-color:var(--sb-slate-50);border-color:var(--sb-slate-400);border-style:solid}.dark .ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLink__Pxy-T{border-color:var(--sb-gray-600)}.dark .ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLink__Pxy-T:hover{background-color:var(--sb-gray-900)}.ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLinkLabel__PMU7e{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ChatMessage_role-assistant__wketE .ChatMessage_quickReplyWrap__1UFyD{display:inline-block;margin:var(--p-1) var(--p-1) var(--p-1) 0;vertical-align:middle}.ChatMessage_role-assistant__wketE .ChatMessage_downloadButtons__RygM-{display:flex;gap:var(--p-2);margin-top:var(--p-4)}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCard__NsNRa{align-items:center;background-color:var(--background);border-radius:var(--p-3);box-shadow:0 0 0 1px var(--border);cursor:pointer;display:flex;gap:var(--p-4);margin-top:var(--p-3);padding:var(--p-3);padding-right:var(--p-4);transition:all .15s;width:-moz-fit-content;width:fit-content}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCard__NsNRa:hover{background-color:var(--sb-gray-50);border-color:var(--border)}.dark .ChatMessage_role-assistant__wketE .ChatMessage_downloadCard__NsNRa{background-color:var(--sb-gray-900);border-color:var(--border)}.dark .ChatMessage_role-assistant__wketE .ChatMessage_downloadCard__NsNRa:hover{background-color:var(--sb-gray-800)}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCardIcon__jkxDJ{align-items:center;border-radius:var(--p-2);display:flex;flex-shrink:0;height:32px;justify-content:center;width:32px}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCardContent__PTPwz{display:flex;flex:1;flex-direction:column;min-width:0}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCardTitle__K1wqr{font-size:var(--text-base);font-weight:600;line-height:1.4}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCardSubtitle__fVeF2{color:var(--muted-foreground);font-size:var(--text-sm);line-height:1.4}";
4
+ var S = {"root":"ChatMessage_root__6rnsF","text":"ChatMessage_text__Y1XNR","role-user":"ChatMessage_role-user__u4JPV","userColumn":"ChatMessage_userColumn__cQM6-","role-system":"ChatMessage_role-system__g13OP","role-assistant":"ChatMessage_role-assistant__wketE","bullet":"ChatMessage_bullet__6vAhq","scrollHorizontal":"ChatMessage_scrollHorizontal__Rms9n","datasetAppLink":"ChatMessage_datasetAppLink__Pxy-T","datasetAppLinkLabel":"ChatMessage_datasetAppLinkLabel__PMU7e","quickReplyWrap":"ChatMessage_quickReplyWrap__1UFyD","downloadButtons":"ChatMessage_downloadButtons__RygM-","downloadCard":"ChatMessage_downloadCard__NsNRa","downloadCardIcon":"ChatMessage_downloadCardIcon__jkxDJ","downloadCardContent":"ChatMessage_downloadCardContent__PTPwz","downloadCardTitle":"ChatMessage_downloadCardTitle__K1wqr","downloadCardSubtitle":"ChatMessage_downloadCardSubtitle__fVeF2"};
5
5
  styleInject(css_248z);
6
6
 
7
7
  export { S as default };
@@ -1,11 +1,10 @@
1
- import { jsxs, jsx } from 'react/jsx-runtime';
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { FileChip } from '../../FileChip/FileChip.js';
2
3
  import { downloadTextFile } from '../../../../utils/downloadTextFile.js';
3
- import { CsvIcon } from '../../../icons/CsvIcon/CsvIcon.js';
4
- import S from './ChatMessage.styl.js';
5
4
 
6
5
  const CSV_DOWNLOAD_HINT = 'Download .CSV file';
7
6
  function UserCsvAttachmentBubble({ attachment, }) {
8
- return (jsxs("button", { type: "button", className: S.userCsvCard, "aria-label": `${CSV_DOWNLOAD_HINT}: ${attachment.displayName}`, onClick: () => downloadTextFile(attachment.content, attachment.filename, 'text/csv;charset=utf-8'), children: [jsx("div", { className: S.userCsvCardIcon, children: jsx(CsvIcon, { size: 32 }) }), jsxs("div", { className: S.userCsvCardContent, children: [jsx("div", { className: S.userCsvCardTitle, children: attachment.displayName }), jsx("div", { className: S.userCsvCardSubtitle, children: CSV_DOWNLOAD_HINT })] })] }));
7
+ return (jsx(FileChip, { name: attachment.displayName, format: "csv", hint: CSV_DOWNLOAD_HINT, onClick: () => downloadTextFile(attachment.content, attachment.filename, 'text/csv;charset=utf-8') }));
9
8
  }
10
9
 
11
10
  export { UserCsvAttachmentBubble };
@@ -7,8 +7,9 @@ import { Button } from '../../Button/Button.js';
7
7
  import { Input } from '../../Input/Input.js';
8
8
  import { syncChatPromptTextareaHeight } from './ChatPrompt.helpers.js';
9
9
  import S from './ChatPrompt.styl.js';
10
+ import { ChatPromptAttachments } from './ChatPromptAttachments.js';
10
11
 
11
- function ChatPrompt({ onSubmit, placeholder, className, footer, prefillMessage, showNotice = true, }) {
12
+ function ChatPrompt({ onSubmit, placeholder, className, footer, prefillMessage, attachments = [], onRemoveAttachment, disabled = false, }) {
12
13
  const [message, setMessage] = useState('');
13
14
  const inputRef = useRef(null);
14
15
  useLayoutEffect(() => {
@@ -24,9 +25,10 @@ function ChatPrompt({ onSubmit, placeholder, className, footer, prefillMessage,
24
25
  }, [prefillMessage]);
25
26
  const handleSubmit = (e) => {
26
27
  const trimmedMessage = message.trim();
27
- if (trimmedMessage) {
28
+ const hasAttachments = attachments.length > 0;
29
+ if (trimmedMessage || hasAttachments) {
28
30
  e.preventDefault();
29
- onSubmit(trimmedMessage);
31
+ onSubmit(trimmedMessage, hasAttachments ? attachments : undefined);
30
32
  setMessage('');
31
33
  }
32
34
  };
@@ -40,7 +42,7 @@ function ChatPrompt({ onSubmit, placeholder, className, footer, prefillMessage,
40
42
  }
41
43
  },
42
44
  });
43
- return (jsxs("form", { onSubmit: handleSubmit, className: cn(S.root, className), children: [jsxs("div", { className: S.composer, children: [showNotice ? (jsx("div", { className: S.notice, children: "Forecast Assistant can make mistakes." })) : null, jsx(Input, { ref: inputRef, type: "textarea", rows: 1, value: message, onChange: e => setMessage(e.target.value), placeholder: placeholder || 'Type a message...', className: cn(S.input) }), jsx("div", { className: S.submitColumn, children: jsx(Button, { type: "submit", size: "sm", disabled: !message.trim(), children: jsx(SendHorizontalIcon, { size: 16 }) }) })] }), footer] }));
45
+ return (jsxs("form", { onSubmit: handleSubmit, className: cn(S.root, className), children: [jsx(ChatPromptAttachments, { attachments: attachments, onRemove: index => onRemoveAttachment?.(index), disabled: disabled }), jsxs("div", { className: S.composer, children: [jsx(Input, { ref: inputRef, type: "textarea", rows: 1, value: message, onChange: e => setMessage(e.target.value), placeholder: placeholder || 'Type a message...', className: cn(S.input) }), jsx("div", { className: S.submitColumn, children: jsx(Button, { type: "submit", size: "sm", disabled: disabled || (!message.trim() && attachments.length === 0), children: jsx(SendHorizontalIcon, { size: 16 }) }) })] }), footer] }));
44
46
  }
45
47
 
46
48
  export { ChatPrompt };
@@ -1,7 +1,7 @@
1
1
  import styleInject from 'style-inject';
2
2
 
3
- var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.ChatPrompt_root__5G5bq{align-items:stretch;display:flex;flex-direction:column;gap:var(--p-2);padding:var(--p-6);padding-top:var(--p-5);position:relative}.ChatPrompt_composer__H3c3N{align-items:flex-end;display:flex;flex-direction:row;gap:var(--p-3);position:relative;width:100%}.ChatPrompt_notice__B-RyW{color:var(--muted-foreground);font-size:var(--text-xs);left:0;margin-bottom:var(--p-1);pointer-events:none;position:absolute;right:0;text-align:center;top:calc(var(--p-12)*-1)}@media (max-width:768px){.ChatPrompt_notice__B-RyW{font-size:10px}}.ChatPrompt_input__QPKBV{border:none;border-radius:0!important;flex:1;max-height:200px;min-height:40px;min-width:0;overflow-y:auto;padding:var(--p-2) 0 0!important;resize:none}.ChatPrompt_input__QPKBV,.ChatPrompt_input__QPKBV:focus{box-shadow:none!important}.ChatPrompt_submitColumn__0rY1R{align-items:center;display:flex;flex-direction:column;flex-shrink:0;justify-content:flex-end}.ChatPrompt_submitColumn__0rY1R>button:focus{box-shadow:0 0 0 2px var(--brand-color-500)!important}.ChatPrompt_submitColumn__0rY1R>button:first-child{border:none;position:relative;transition:all .2s}.ChatPrompt_submitColumn__0rY1R>button:first-child:focus{transform:scale(1.2)}.ChatPrompt_submitColumn__0rY1R>button:first-child:before{bottom:-100%;content:\"\";left:-100%;position:absolute;right:-100%;top:-100%}.ChatPrompt_submitColumn__0rY1R .ChatPrompt_attachButton__gi-qF{background-color:var(--page-color);box-shadow:0 0 20px var(--background)}";
4
- var S = {"root":"ChatPrompt_root__5G5bq","composer":"ChatPrompt_composer__H3c3N","notice":"ChatPrompt_notice__B-RyW","input":"ChatPrompt_input__QPKBV","submitColumn":"ChatPrompt_submitColumn__0rY1R","attachButton":"ChatPrompt_attachButton__gi-qF"};
3
+ var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.ChatPrompt_root__5G5bq{align-items:stretch;display:flex;flex-direction:column;gap:var(--p-2);padding:var(--p-6);padding-top:var(--p-5);position:relative}.ChatPrompt_composer__H3c3N{align-items:flex-end;display:flex;flex-direction:row;gap:var(--p-3);position:relative;width:100%}.ChatPrompt_input__QPKBV{border:none;border-radius:0!important;flex:1;max-height:200px;min-height:40px;min-width:0;overflow-y:auto;padding:var(--p-2) 0 0!important;resize:none}.ChatPrompt_input__QPKBV,.ChatPrompt_input__QPKBV:focus{box-shadow:none!important}.ChatPrompt_submitColumn__0rY1R{align-items:center;display:flex;flex-direction:column;flex-shrink:0;justify-content:flex-end}.ChatPrompt_submitColumn__0rY1R>button:focus{box-shadow:0 0 0 2px var(--brand-color-500)!important}.ChatPrompt_submitColumn__0rY1R>button:first-child{border:none;position:relative;transition:all .2s}.ChatPrompt_submitColumn__0rY1R>button:first-child:focus{transform:scale(1.2)}.ChatPrompt_submitColumn__0rY1R>button:first-child:before{bottom:-100%;content:\"\";left:-100%;position:absolute;right:-100%;top:-100%}.ChatPrompt_submitColumn__0rY1R .ChatPrompt_attachButton__gi-qF{background-color:var(--page-color);box-shadow:0 0 20px var(--background)}.ChatPrompt_attachments__KG-fG{display:flex;flex-wrap:wrap;gap:var(--p-2);margin-bottom:var(--p-2)}.ChatPrompt_attachmentItem__QJk7J{flex:1 1 300px;max-width:300px;min-width:0}";
4
+ var S = {"root":"ChatPrompt_root__5G5bq","composer":"ChatPrompt_composer__H3c3N","input":"ChatPrompt_input__QPKBV","submitColumn":"ChatPrompt_submitColumn__0rY1R","attachButton":"ChatPrompt_attachButton__gi-qF","attachments":"ChatPrompt_attachments__KG-fG","attachmentItem":"ChatPrompt_attachmentItem__QJk7J"};
5
5
  styleInject(css_248z);
6
6
 
7
7
  export { S as default };
@@ -0,0 +1,11 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { FileChip } from '../../FileChip/FileChip.js';
3
+ import S from './ChatPrompt.styl.js';
4
+
5
+ function ChatPromptAttachments({ attachments, onRemove, disabled = false, }) {
6
+ if (attachments.length === 0)
7
+ return null;
8
+ return (jsx("div", { className: S.attachments, children: attachments.map((item, index) => (jsx(FileChip, { className: S.attachmentItem, name: item.file.name, format: item.kind === 'pdf' ? 'pdf' : 'text', hint: item.kind === 'pdf' ? 'PDF' : 'Text file', onRemove: () => onRemove(index), disabled: disabled }, `${item.file.name}-${index}`))) }));
9
+ }
10
+
11
+ export { ChatPromptAttachments };
@@ -34,7 +34,7 @@ function ChatSelector({ id, className, onChatDeleted, }) {
34
34
  }
35
35
  return 'New chat';
36
36
  };
37
- return (jsxs("div", { className: S.wrapper, children: [jsx("div", { className: S.selectGrow, children: jsxs(Select, { variant: "clear", value: currentChatId?.toString() ?? '', onValueChange: handleValueChange, children: [jsx(SelectTrigger, { size: "sm", className: className ? cn(S.selectTrigger, className) : S.selectTrigger, children: jsx(SelectValue, { placeholder: "Select chat" }) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "new", children: "+ New Chat" }), chats.map(chat => (jsx(SelectItem, { value: chat.session_id.toString(), selected: chat.session_id === currentChatId, children: getChatDisplayName(chat) }, chat.session_id)))] })] }) }), jsx(Button, { type: "button", variant: "ghost", size: "sm", className: S.deleteBtn, "aria-label": "Delete chat", disabled: !currentChatId || chats.length === 0, onClick: handleDeleteChat, children: jsx(Trash2Icon, { size: 16 }) })] }));
37
+ return (jsxs("div", { className: S.wrapper, children: [jsx("div", { className: S.selectGrow, children: jsxs(Select, { variant: "clear", value: currentChatId?.toString() ?? '', onValueChange: handleValueChange, children: [jsx(SelectTrigger, { size: "sm", className: className ? cn(S.selectTrigger, className) : S.selectTrigger, children: jsx(SelectValue, { placeholder: "Select chat" }) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "new", children: "+ New Chat" }), chats.map(chat => (jsx(SelectItem, { value: chat.session_id.toString(), selected: chat.session_id === currentChatId, children: getChatDisplayName(chat) }, chat.session_id)))] })] }) }), currentChatId && chats.length > 0 && (jsx(Button, { type: "button", variant: "ghost", size: "sm", className: S.deleteBtn, "aria-label": "Delete chat", onClick: handleDeleteChat, children: jsx(Trash2Icon, { size: 16 }) }))] }));
38
38
  }
39
39
 
40
40
  export { ChatSelector };
@@ -21,7 +21,7 @@ const CHAT_NAV_COLLAPSE_BREAKPOINT_PX = 1400;
21
21
  const CHAT_QUERY_PARAM = 'chat';
22
22
  const CHAT_OPEN_VALUE = 'open';
23
23
  const PROMPT_QUERY_PARAM = 'prompt';
24
- function useChatPanelChromeModel({ embedAsPage, presets, scopeId, onMessage, onScriptComplete, onGenerateDashboard, renderMessageChart, emptyState, }) {
24
+ function useChatPanelChromeModel({ embedAsPage, presets, scopeId, onMessage, onScriptComplete, onGenerateDashboard, renderMessageChart, emptyState, allowedAttachments, allowPdfAttachments, onAttachmentsDropped, }) {
25
25
  const effectiveScopeId = scopeId ?? NO_SCOPE_FALLBACK;
26
26
  const isMobile = useIsMobile();
27
27
  const { chatPanelContainer, isOpen: sidebarNavOpen, setOpen: setSidebarNavOpen, chatWidthPx, setChatWidthPx, getShellWidth, setChatPanelOpen, } = useSidebar();
@@ -762,6 +762,9 @@ function useChatPanelChromeModel({ embedAsPage, presets, scopeId, onMessage, onS
762
762
  onChatDeleted: endLocalDemoFlow,
763
763
  promptPrefill: promptLinkPrefill,
764
764
  emptyState,
765
+ allowedAttachments,
766
+ allowPdfAttachments,
767
+ onAttachmentsDropped,
765
768
  };
766
769
  const toggleOpen = () => onOpenChange(!isOpen);
767
770
  return {
@@ -0,0 +1,54 @@
1
+ /** MIME types and extensions accepted for chat text attachments. */
2
+ const TEXT_ATTACHMENT_ACCEPT_PARTS = [
3
+ 'text/plain',
4
+ '.txt',
5
+ 'text/csv',
6
+ '.csv',
7
+ 'text/markdown',
8
+ '.md',
9
+ '.markdown',
10
+ 'application/json',
11
+ '.json',
12
+ 'text/html',
13
+ '.html',
14
+ '.htm',
15
+ 'text/xml',
16
+ 'application/xml',
17
+ '.xml',
18
+ 'text/yaml',
19
+ 'application/yaml',
20
+ 'application/x-yaml',
21
+ '.yaml',
22
+ '.yml',
23
+ 'text/tab-separated-values',
24
+ '.tsv',
25
+ 'text/calendar',
26
+ '.ics',
27
+ ];
28
+ const PDF_ATTACHMENT_ACCEPT_PARTS = ['application/pdf', '.pdf'];
29
+ const TEXT_ATTACHMENT_ACCEPT_SET = new Set(TEXT_ATTACHMENT_ACCEPT_PARTS.map(part => part.toLowerCase()));
30
+ /** Keep only tokens from `parts` that appear in the text attachment allowlist. */
31
+ function filterToTextAttachments(parts) {
32
+ if (!parts?.length)
33
+ return [];
34
+ return parts.filter(part => TEXT_ATTACHMENT_ACCEPT_SET.has(part.trim().toLowerCase()));
35
+ }
36
+ function buildAcceptAttr(filteredTextParts, allowPdf) {
37
+ const parts = [...filteredTextParts];
38
+ if (allowPdf) {
39
+ parts.push(...PDF_ATTACHMENT_ACCEPT_PARTS);
40
+ }
41
+ return parts.join(',');
42
+ }
43
+ function isPdfFile(file) {
44
+ const type = file.type.toLowerCase();
45
+ if (type === 'application/pdf')
46
+ return true;
47
+ return file.name.toLowerCase().endsWith('.pdf');
48
+ }
49
+ function isAttachmentsDropzoneEnabled(allowedAttachments, allowPdfAttachments) {
50
+ return (filterToTextAttachments(allowedAttachments).length > 0 ||
51
+ Boolean(allowPdfAttachments));
52
+ }
53
+
54
+ export { PDF_ATTACHMENT_ACCEPT_PARTS, TEXT_ATTACHMENT_ACCEPT_PARTS, buildAcceptAttr, filterToTextAttachments, isAttachmentsDropzoneEnabled, isPdfFile };
@@ -0,0 +1,26 @@
1
+ import { isPdfFile } from './chatAttachmentAccept.js';
2
+ import { extractPdfFileToText } from './chatPdfExtract.js';
3
+
4
+ function readTextFile(file) {
5
+ return new Promise((resolve, reject) => {
6
+ const reader = new FileReader();
7
+ reader.onload = () => resolve(String(reader.result ?? ''));
8
+ reader.onerror = () => reject(reader.error ?? new Error(`Failed to read ${file.name}`));
9
+ reader.readAsText(file);
10
+ });
11
+ }
12
+ async function extractChatAttachmentItems(files, allowPdfAttachments) {
13
+ const items = await Promise.all(files.map(async (file) => {
14
+ if (isPdfFile(file)) {
15
+ if (!allowPdfAttachments)
16
+ return null;
17
+ const text = await extractPdfFileToText(file);
18
+ return { file, text, kind: 'pdf' };
19
+ }
20
+ const text = await readTextFile(file);
21
+ return { file, text, kind: 'text' };
22
+ }));
23
+ return items.filter((item) => item != null);
24
+ }
25
+
26
+ export { extractChatAttachmentItems };
@@ -0,0 +1,31 @@
1
+ let workerConfigured = false;
2
+ async function configurePdfWorker(pdfjs) {
3
+ if (workerConfigured)
4
+ return;
5
+ const version = pdfjs.version ?? '4.10.38';
6
+ pdfjs.GlobalWorkerOptions.workerSrc = `https://cdn.jsdelivr.net/npm/pdfjs-dist@${version}/legacy/build/pdf.worker.min.mjs`;
7
+ workerConfigured = true;
8
+ }
9
+ /** Best-effort plain text from PDF; pages separated with lightweight markdown headings. */
10
+ async function extractPdfFileToText(file) {
11
+ const pdfjs = await import('pdfjs-dist/legacy/build/pdf.mjs');
12
+ await configurePdfWorker(pdfjs);
13
+ const data = new Uint8Array(await file.arrayBuffer());
14
+ const doc = await pdfjs.getDocument({ data }).promise;
15
+ const pageTexts = [];
16
+ for (let pageNumber = 1; pageNumber <= doc.numPages; pageNumber += 1) {
17
+ const page = await doc.getPage(pageNumber);
18
+ const content = await page.getTextContent();
19
+ const pageText = content.items
20
+ .map(item => ('str' in item ? item.str : ''))
21
+ .join(' ')
22
+ .replace(/\s+/g, ' ')
23
+ .trim();
24
+ if (pageText) {
25
+ pageTexts.push(`## Page ${pageNumber}\n\n${pageText}`);
26
+ }
27
+ }
28
+ return pageTexts.join('\n\n');
29
+ }
30
+
31
+ export { extractPdfFileToText };
@@ -1,4 +1,5 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import cn from 'classnames';
2
3
  import { useState, useRef, useCallback, useEffect } from 'react';
3
4
  import S from './DropZone.styl.js';
4
5
 
@@ -32,28 +33,34 @@ function matchesAccept(file, accept) {
32
33
  return parts.some(part => matchesAcceptPart(file, part));
33
34
  }
34
35
  function DropZone(props) {
35
- const { accept, label, error, disabled = false, ghost = false, id, className, } = props;
36
+ const { accept, label, error, disabled = false, ghost = false, overlayScope = 'viewport', id, className, } = props;
36
37
  const [isDragging, setIsDragging] = useState(false);
38
+ const rootRef = useRef(null);
37
39
  const dropAreaRef = useRef(null);
38
40
  const inputId = id || `dropzone-file-input-${Math.random().toString(36).substr(2, 9)}`;
39
- const handleDrop = useCallback((e) => {
40
- e.preventDefault();
41
- setIsDragging(false);
42
- if (disabled)
41
+ const dropProcessedRef = useRef(false);
42
+ const emitDroppedFiles = useCallback((files) => {
43
+ if (disabled || dropProcessedRef.current || files.length === 0)
44
+ return;
45
+ const list = Array.from(files).filter(f => matchesAccept(f, accept));
46
+ if (list.length === 0)
43
47
  return;
44
- const list = Array.from(e.dataTransfer.files).filter(f => matchesAccept(f, accept));
48
+ dropProcessedRef.current = true;
45
49
  if (props.multiple === true) {
46
- if (list.length > 0) {
47
- props.onFiles(list);
48
- }
50
+ props.onFiles(list);
49
51
  }
50
52
  else {
51
- const file = list[0];
52
- if (file) {
53
- props.onFile(file);
54
- }
53
+ props.onFile(list[0]);
55
54
  }
56
55
  }, [accept, disabled, props]);
56
+ const handleDrop = useCallback((e) => {
57
+ e.preventDefault();
58
+ e.stopPropagation();
59
+ setIsDragging(false);
60
+ if (disabled)
61
+ return;
62
+ emitDroppedFiles(e.dataTransfer.files);
63
+ }, [disabled, emitDroppedFiles]);
57
64
  const handleFileInput = useCallback((e) => {
58
65
  if (disabled)
59
66
  return;
@@ -75,11 +82,18 @@ function DropZone(props) {
75
82
  e.target.value = '';
76
83
  }, [accept, disabled, props]);
77
84
  useEffect(() => {
78
- // Find closest dialog or fall back to body
79
- const dialog = dropAreaRef.current?.closest('[role="dialog"]');
80
- const targetElement = dialog || document.body;
85
+ const root = rootRef.current;
86
+ if (!root)
87
+ return;
88
+ const targetElement = overlayScope === 'container'
89
+ ? root.parentElement
90
+ : (root.closest('[role="dialog"]') ??
91
+ document.body);
92
+ if (!targetElement)
93
+ return;
81
94
  const handleGlobalDragOver = (e) => {
82
95
  e.preventDefault();
96
+ dropProcessedRef.current = false;
83
97
  setIsDragging(true);
84
98
  };
85
99
  const handleGlobalDragLeave = (e) => {
@@ -90,21 +104,36 @@ function DropZone(props) {
90
104
  setIsDragging(false);
91
105
  }
92
106
  };
93
- const handleGlobalDrop = () => {
107
+ const handleGlobalDropPrevent = (e) => {
108
+ e.preventDefault();
109
+ };
110
+ const handleGlobalDropFinalize = (e) => {
111
+ if (overlayScope === 'container' && e.dataTransfer?.files?.length) {
112
+ emitDroppedFiles(e.dataTransfer.files);
113
+ }
94
114
  setIsDragging(false);
95
115
  };
96
116
  targetElement.addEventListener('dragover', handleGlobalDragOver);
97
117
  targetElement.addEventListener('dragleave', handleGlobalDragLeave);
98
- targetElement.addEventListener('drop', handleGlobalDrop);
118
+ targetElement.addEventListener('drop', handleGlobalDropPrevent, true);
119
+ targetElement.addEventListener('drop', handleGlobalDropFinalize);
99
120
  return () => {
100
121
  targetElement.removeEventListener('dragover', handleGlobalDragOver);
101
122
  targetElement.removeEventListener('dragleave', handleGlobalDragLeave);
102
- targetElement.removeEventListener('drop', handleGlobalDrop);
123
+ targetElement.removeEventListener('drop', handleGlobalDropPrevent, true);
124
+ targetElement.removeEventListener('drop', handleGlobalDropFinalize);
103
125
  };
104
- }, []);
126
+ }, [emitDroppedFiles, overlayScope]);
105
127
  const shouldShowDropArea = !ghost || isDragging;
106
128
  const multiple = props.multiple === true;
107
- return (jsxs("div", { className: `${S.root} ${className || ''}`, children: [shouldShowDropArea && (jsxs("div", { ref: dropAreaRef, className: `${S.dropArea} ${isDragging ? S.isDragging : ''} ${disabled ? S.disabled : ''}`, onDrop: handleDrop, children: [jsx("input", { type: "file", accept: accept, multiple: multiple, onChange: handleFileInput, className: S.fileInput, id: inputId, disabled: disabled }), jsx("label", { htmlFor: inputId, className: S.label, style: {
129
+ const isContainerOverlay = overlayScope === 'container';
130
+ return (jsxs("div", { ref: rootRef, className: cn(S.root, isContainerOverlay && S.rootContained, isDragging && isContainerOverlay && S.rootDragging, className), style: isContainerOverlay
131
+ ? { pointerEvents: isDragging ? 'auto' : 'none' }
132
+ : undefined, children: [shouldShowDropArea && (jsxs("div", { ref: dropAreaRef, className: cn(S.dropArea, isDragging
133
+ ? isContainerOverlay
134
+ ? S.isDraggingContained
135
+ : S.isDragging
136
+ : '', disabled ? S.disabled : ''), onDrop: handleDrop, children: [jsx("input", { type: "file", accept: accept, multiple: multiple, onChange: handleFileInput, className: S.fileInput, id: inputId, disabled: disabled }), jsx("label", { htmlFor: inputId, className: S.label, style: {
108
137
  cursor: disabled ? 'not-allowed' : 'pointer',
109
138
  }, children: label })] })), error && jsx("div", { className: S.error, children: error })] }));
110
139
  }
@@ -1,7 +1,7 @@
1
1
  import styleInject from 'style-inject';
2
2
 
3
- var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.DropZone_root__ct0cl{display:flex;flex-direction:column;gap:var(--p-2)}.DropZone_dropArea__GIrZ-{background-color:var(--page-color);border:2px dashed var(--border);border-radius:var(--p-4);cursor:pointer;padding:var(--p-4);position:relative;text-align:center;transition:all .2s ease}.DropZone_dropArea__GIrZ- label:before{border-radius:var(--p-4);content:\"\";height:100%;left:0;position:absolute;top:0;width:100%}.DropZone_dropArea__GIrZ-.DropZone_isDragging__g7h0n,.DropZone_dropArea__GIrZ-:hover:not(.DropZone_disabled__nJAXj){background-color:var(--page-color-alpha-800);border-color:var(--primary-color)}.DropZone_dropArea__GIrZ-.DropZone_isDragging__g7h0n{align-items:center;display:flex;height:100%;justify-content:center;left:0;position:fixed;top:0;width:100%;z-index:9999}.DropZone_dropArea__GIrZ-.DropZone_isDragging__g7h0n,.DropZone_dropArea__GIrZ-:hover:not(.DropZone_disabled__nJAXj){border:2px dashed var(--muted-border)}.dark .DropZone_dropArea__GIrZ-.DropZone_isDragging__g7h0n,.dark .DropZone_dropArea__GIrZ-:hover:not(.DropZone_disabled__nJAXj){background-color:var(--background)}.DropZone_dropArea__GIrZ-.DropZone_disabled__nJAXj{cursor:not-allowed;opacity:.6}.DropZone_fileInput__K-7dx{display:none}.DropZone_label__FaOwC{color:var(--text-color-secondary);cursor:pointer}.DropZone_error__hwV4z{color:var(--error-color);font-size:.875rem;padding:var(--p-1) var(--p-2)}";
4
- var S = {"root":"DropZone_root__ct0cl","dropArea":"DropZone_dropArea__GIrZ-","disabled":"DropZone_disabled__nJAXj","isDragging":"DropZone_isDragging__g7h0n","fileInput":"DropZone_fileInput__K-7dx","label":"DropZone_label__FaOwC","error":"DropZone_error__hwV4z"};
3
+ var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.DropZone_root__ct0cl{display:flex;flex-direction:column;gap:var(--p-2)}.DropZone_rootContained__UhRMG{height:100%;position:relative;width:100%}.DropZone_rootDragging__37R3u{pointer-events:auto}.DropZone_dropArea__GIrZ-{background-color:var(--page-color);border:2px dashed var(--border);border-radius:var(--p-4);cursor:pointer;padding:var(--p-4);position:relative;text-align:center;transition:all .2s ease}.DropZone_dropArea__GIrZ- label:before{border-radius:var(--p-4);content:\"\";height:100%;left:0;position:absolute;top:0;width:100%}.DropZone_dropArea__GIrZ-:hover:not(.DropZone_disabled__nJAXj){background-color:var(--page-color-alpha-800);border-color:var(--primary-color)}.DropZone_dropArea__GIrZ-.DropZone_isDragging__g7h0n{border-color:var(--primary-color);position:fixed;z-index:9999}.DropZone_dropArea__GIrZ-.DropZone_isDraggingContained__M6ay8,.DropZone_dropArea__GIrZ-.DropZone_isDragging__g7h0n{align-items:center;background-color:var(--page-color-alpha-800);display:flex;height:100%;justify-content:center;left:0;top:0;width:100%}.DropZone_dropArea__GIrZ-.DropZone_isDraggingContained__M6ay8{border-color:var(--primary-color);border-radius:var(--p-4);position:absolute;z-index:1}.DropZone_dropArea__GIrZ-.DropZone_isDraggingContained__M6ay8,.DropZone_dropArea__GIrZ-.DropZone_isDragging__g7h0n,.DropZone_dropArea__GIrZ-:hover:not(.DropZone_disabled__nJAXj){border:2px dashed var(--muted-border)}.dark .DropZone_dropArea__GIrZ-.DropZone_isDraggingContained__M6ay8,.dark .DropZone_dropArea__GIrZ-.DropZone_isDragging__g7h0n,.dark .DropZone_dropArea__GIrZ-:hover:not(.DropZone_disabled__nJAXj){background-color:var(--background)}.DropZone_dropArea__GIrZ-.DropZone_disabled__nJAXj{cursor:not-allowed;opacity:.6}.DropZone_fileInput__K-7dx{display:none}.DropZone_label__FaOwC{color:var(--text-color-secondary);cursor:pointer}.DropZone_error__hwV4z{color:var(--error-color);font-size:.875rem;padding:var(--p-1) var(--p-2)}";
4
+ var S = {"root":"DropZone_root__ct0cl","rootContained":"DropZone_rootContained__UhRMG","rootDragging":"DropZone_rootDragging__37R3u","dropArea":"DropZone_dropArea__GIrZ-","disabled":"DropZone_disabled__nJAXj","isDragging":"DropZone_isDragging__g7h0n","isDraggingContained":"DropZone_isDraggingContained__M6ay8","fileInput":"DropZone_fileInput__K-7dx","label":"DropZone_label__FaOwC","error":"DropZone_error__hwV4z"};
5
5
  styleInject(css_248z);
6
6
 
7
7
  export { S as default };
@@ -0,0 +1,26 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import cn from 'classnames';
3
+ import { CsvIcon } from '../../icons/CsvIcon/CsvIcon.js';
4
+ import { CardHeader, CardAction } from '../Card/Card.js';
5
+ import { XIcon, FileTextIcon } from '@phosphor-icons/react';
6
+ import S from './FileChip.styl.js';
7
+
8
+ const FORMAT_ICON_SIZE = 32;
9
+ function FormatIcon({ format }) {
10
+ if (format === 'csv') {
11
+ return jsx(CsvIcon, { size: FORMAT_ICON_SIZE });
12
+ }
13
+ return (jsx(FileTextIcon, { size: FORMAT_ICON_SIZE, "aria-hidden": true, style: { color: 'var(--muted-foreground)' } }));
14
+ }
15
+ function FileChipHeader({ name, format, hint, onRemove, }) {
16
+ return (jsx(CardHeader, { className: S.header, icon: jsx(FormatIcon, { format: format }), title: name, description: hint, titleClassName: S.title, descriptionClassName: S.hint, tooltipProps: { maxWidth: 400 }, children: onRemove ? (jsx(CardAction, { children: jsx("button", { type: "button", className: S.remove, "aria-label": `Remove ${name}`, onClick: onRemove, children: jsx(XIcon, { size: 14, "aria-hidden": true }) }) })) : null }));
17
+ }
18
+ function FileChip({ name, format, hint, onClick, onRemove, className, }) {
19
+ const header = (jsx(FileChipHeader, { name: name, format: format, hint: hint, onRemove: onRemove }));
20
+ if (onClick) {
21
+ return (jsx("button", { type: "button", className: cn(S.root, S.interactive, className), "aria-label": `${hint}: ${name}`, onClick: onClick, children: header }));
22
+ }
23
+ return (jsx("div", { className: cn(S.root, className), role: "group", children: header }));
24
+ }
25
+
26
+ export { FileChip };
@@ -0,0 +1,7 @@
1
+ import styleInject from 'style-inject';
2
+
3
+ var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.FileChip_root__LkR-k{align-items:stretch;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--background);border:0;border-radius:var(--p-3);box-shadow:0 0 0 1px var(--border);color:inherit;display:flex;font:inherit;margin:0;max-width:100%;padding:var(--p-3);padding-right:var(--p-4);text-align:left;width:-moz-fit-content;width:fit-content}.dark .FileChip_root__LkR-k{background-color:var(--sb-gray-800)}.FileChip_header__pjZxs{align-items:center;display:flex;flex-direction:row;font-size:inherit;gap:var(--p-2);min-width:0;width:100%}.FileChip_header__pjZxs [data-slot=card-action]{align-self:center;flex-shrink:0;grid-column:auto;grid-row:auto;margin-left:auto;order:3}.FileChip_header__pjZxs>div:first-child{align-items:center;background:transparent;border-radius:0;box-shadow:none;display:flex;flex-shrink:0;height:32px;justify-content:center;min-width:32px;order:1;width:32px}.FileChip_header__pjZxs>div:first-child>svg{height:32px;width:32px}.FileChip_header__pjZxs>div:last-child{flex:1;min-width:0;order:2}.FileChip_interactive__g0-Hk{cursor:pointer;transition:background-color .15s}.FileChip_interactive__g0-Hk:hover{background-color:var(--sb-gray-50)}.FileChip_interactive__g0-Hk:focus-visible{outline:2px solid var(--ring);outline-offset:2px}.dark .FileChip_interactive__g0-Hk:hover{background-color:var(--sb-gray-900)}.FileChip_title__2sUIf{font-size:var(--text-sm);font-weight:500;line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.FileChip_hint__ftFdf{font-size:var(--text-xs);line-height:1.4}.FileChip_remove__IkREj{align-items:center;background:transparent;border:none;border-radius:var(--p-2);color:var(--muted-foreground);cursor:pointer;display:inline-flex;height:28px;justify-content:center;width:28px}.FileChip_remove__IkREj:hover:not(:disabled){background-color:var(--muted);color:var(--foreground)}.FileChip_remove__IkREj:disabled{cursor:not-allowed;opacity:.5}";
4
+ var S = {"root":"FileChip_root__LkR-k","header":"FileChip_header__pjZxs","interactive":"FileChip_interactive__g0-Hk","title":"FileChip_title__2sUIf","hint":"FileChip_hint__ftFdf","remove":"FileChip_remove__IkREj"};
5
+ styleInject(css_248z);
6
+
7
+ export { S as default };
package/dist/esm/index.js CHANGED
@@ -22,6 +22,7 @@ export { ChartAreaInteractive, chartConfig } from './components/ui/ChartAreaInte
22
22
  export { Chat } from './components/ui/Chat/Chat.js';
23
23
  export { usedPresetIdsFromMessages } from './components/ui/Chat/chat-preset-utils.js';
24
24
  export { ChatChrome } from './components/ui/Chat/ChatChrome/ChatChrome.js';
25
+ export { TEXT_ATTACHMENT_ACCEPT_PARTS, filterToTextAttachments } from './components/ui/Chat/chatAttachmentAccept.js';
25
26
  export { ChatSheet } from './components/ui/Chat/ChatSheet/ChatSheet.js';
26
27
  export { useChatPanelChromeModel } from './components/ui/Chat/ChatSheet/useChatPanelChromeModel.js';
27
28
  export { ChatMessage } from './components/ui/Chat/ChatMessage/ChatMessage.js';
@@ -35,6 +36,7 @@ export { Dialog } from './components/ui/Dialog/Dialog.js';
35
36
  export { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger } from './components/ui/Drawer/Drawer.js';
36
37
  export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from './components/ui/DropdownMenu/DropdownMenu.js';
37
38
  export { DropZone } from './components/ui/DropZone/DropZone.js';
39
+ export { FileChip } from './components/ui/FileChip/FileChip.js';
38
40
  export { FlickeringGrid } from './components/ui/FlickeringGrid/FlickeringGrid.js';
39
41
  export { Foldable } from './components/ui/Foldable/Foldable.js';
40
42
  export { Gap } from './components/ui/Gap/Gap.js';