pixelon 0.1.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.
Files changed (66) hide show
  1. package/README.md +54 -0
  2. package/dist/App.d.ts +3 -0
  3. package/dist/App.js +6 -0
  4. package/dist/assets/output-BpGRJPjR.css +1 -0
  5. package/dist/assets/output-DGLCW84k.css +1 -0
  6. package/dist/components/atoms/AttachmentPreview/AttachmentPreview.d.ts +8 -0
  7. package/dist/components/atoms/AttachmentPreview/AttachmentPreview.js +44 -0
  8. package/dist/components/atoms/Avatar/Avatar.d.ts +10 -0
  9. package/dist/components/atoms/Avatar/Avatar.js +28 -0
  10. package/dist/components/atoms/Button/Button.d.ts +10 -0
  11. package/dist/components/atoms/Button/Button.js +137 -0
  12. package/dist/components/atoms/DateDivider/DateDivider.d.ts +7 -0
  13. package/dist/components/atoms/DateDivider/DateDivider.js +40 -0
  14. package/dist/components/atoms/DateDivider/index.d.ts +2 -0
  15. package/dist/components/atoms/DateDivider/index.js +1 -0
  16. package/dist/components/atoms/Input/Input.d.ts +10 -0
  17. package/dist/components/atoms/Input/Input.js +111 -0
  18. package/dist/components/atoms/Link/Link.d.ts +14 -0
  19. package/dist/components/atoms/Link/Link.js +16 -0
  20. package/dist/components/atoms/SelectMenu/SelectMenu.d.ts +9 -0
  21. package/dist/components/atoms/SelectMenu/SelectMenu.js +23 -0
  22. package/dist/components/atoms/Text/Text.d.ts +11 -0
  23. package/dist/components/atoms/Text/Text.js +93 -0
  24. package/dist/components/atoms/Textarea/Textarea.d.ts +6 -0
  25. package/dist/components/atoms/Textarea/Textarea.js +5 -0
  26. package/dist/components/atoms/logo/Logo.d.ts +6 -0
  27. package/dist/components/atoms/logo/Logo.js +5 -0
  28. package/dist/components/molecules/chat/AssistantMessage/AssistantMessage.d.ts +7 -0
  29. package/dist/components/molecules/chat/AssistantMessage/AssistantMessage.js +10 -0
  30. package/dist/components/molecules/chat/AssistantThinkingIndicator/AssistantThinkingIndicator.d.ts +3 -0
  31. package/dist/components/molecules/chat/AssistantThinkingIndicator/AssistantThinkingIndicator.js +36 -0
  32. package/dist/components/molecules/chat/ChatHeader/ChatHeader.d.ts +6 -0
  33. package/dist/components/molecules/chat/ChatHeader/ChatHeader.js +6 -0
  34. package/dist/components/molecules/chat/ChatInput/ChatInput.d.ts +17 -0
  35. package/dist/components/molecules/chat/ChatInput/ChatInput.js +56 -0
  36. package/dist/components/molecules/chat/FileViewer/FileViewer.d.ts +7 -0
  37. package/dist/components/molecules/chat/FileViewer/FileViewer.js +41 -0
  38. package/dist/components/molecules/chat/FullscreenViewer/FullscreenViewer.d.ts +10 -0
  39. package/dist/components/molecules/chat/FullscreenViewer/FullscreenViewer.js +65 -0
  40. package/dist/components/molecules/chat/MessageStatus/MessageStatus.d.ts +9 -0
  41. package/dist/components/molecules/chat/MessageStatus/MessageStatus.js +14 -0
  42. package/dist/components/molecules/chat/Modal/Modal.d.ts +12 -0
  43. package/dist/components/molecules/chat/Modal/Modal.js +29 -0
  44. package/dist/components/molecules/chat/UserAttachments/UserAttachments.d.ts +6 -0
  45. package/dist/components/molecules/chat/UserAttachments/UserAttachments.js +8 -0
  46. package/dist/components/molecules/chat/UserMessage/UserMessage.d.ts +11 -0
  47. package/dist/components/molecules/chat/UserMessage/UserMessage.js +8 -0
  48. package/dist/components/organisms/chat/Chat.d.ts +21 -0
  49. package/dist/components/organisms/chat/Chat.js +278 -0
  50. package/dist/components/organisms/chat/index.d.ts +1 -0
  51. package/dist/components/organisms/chat/index.js +1 -0
  52. package/dist/index.d.ts +171 -0
  53. package/dist/index.esm.js +21664 -0
  54. package/dist/index.esm.js.map +1 -0
  55. package/dist/index.js +21666 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/main.d.ts +1 -0
  58. package/dist/main.js +6 -0
  59. package/dist/styles.css +1 -0
  60. package/dist/styles.css.map +1 -0
  61. package/dist/test/setup.d.ts +1 -0
  62. package/dist/test/setup.js +20 -0
  63. package/package.json +95 -0
  64. package/src/styles/_variables.scss +84 -0
  65. package/src/styles/global.scss +58 -0
  66. package/src/styles/index.scss +30 -0
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Text } from '../../../atoms/Text/Text';
3
+ const statusText = {
4
+ sending: 'Enviando...',
5
+ sent: 'Enviado',
6
+ };
7
+ export const MessageStatus = ({ status, className = '', onRetry }) => {
8
+ const statusClassName = `message-status ${status === 'failed' ? 'message-status--failed' : ''} ${className}`;
9
+ if (status === 'failed') {
10
+ return (_jsxs(Text, { variant: "caption", className: statusClassName, children: ["No enviado.", ' ', _jsx("span", { className: "message-status__retry", onClick: onRetry, role: "button", tabIndex: 0, children: "Reintentar" })] }));
11
+ }
12
+ return (_jsx(Text, { variant: "caption", color: "secondary", className: statusClassName, children: statusText[status] }));
13
+ };
14
+ export default MessageStatus;
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ export interface ModalProps {
3
+ isOpen: boolean;
4
+ onClose: () => void;
5
+ children: React.ReactNode;
6
+ title?: string;
7
+ showCloseButton?: boolean;
8
+ closeOnOverlayClick?: boolean;
9
+ closeOnEscape?: boolean;
10
+ }
11
+ export declare const Modal: React.FC<ModalProps>;
12
+ export default Modal;
@@ -0,0 +1,29 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect } from 'react';
3
+ import { Button } from '../../../atoms/Button/Button';
4
+ export const Modal = ({ isOpen, onClose, children, title, showCloseButton = true, closeOnOverlayClick = true, closeOnEscape = true, }) => {
5
+ useEffect(() => {
6
+ if (!isOpen)
7
+ return;
8
+ const handleEscape = (e) => {
9
+ if (e.key === 'Escape' && closeOnEscape) {
10
+ onClose();
11
+ }
12
+ };
13
+ document.addEventListener('keydown', handleEscape);
14
+ document.body.style.overflow = 'hidden';
15
+ return () => {
16
+ document.removeEventListener('keydown', handleEscape);
17
+ document.body.style.overflow = 'unset';
18
+ };
19
+ }, [isOpen, onClose, closeOnEscape]);
20
+ if (!isOpen)
21
+ return null;
22
+ const handleOverlayClick = (e) => {
23
+ if (e.target === e.currentTarget && closeOnOverlayClick) {
24
+ onClose();
25
+ }
26
+ };
27
+ return (_jsx("div", { className: "modal-overlay", onClick: handleOverlayClick, children: _jsxs("div", { className: "modal", children: [(title || showCloseButton) && (_jsxs("div", { className: "modal__header", children: [title && _jsx("h2", { className: "modal__title", children: title }), showCloseButton && (_jsx(Button, { type: "button", className: "modal__close-btn", onClick: onClose, "aria-label": "Cerrar", icon: _jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), _jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) }))] })), _jsx("div", { className: "modal__content", children: children })] }) }));
28
+ };
29
+ export default Modal;
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ export interface UserAttachmentsProps {
3
+ files: File[];
4
+ }
5
+ export declare const UserAttachments: React.FC<UserAttachmentsProps>;
6
+ export default UserAttachments;
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { FileViewer } from '../FileViewer/FileViewer';
3
+ export const UserAttachments = ({ files }) => {
4
+ if (!files || files.length === 0)
5
+ return null;
6
+ return (_jsx("div", { className: "user-attachments", children: _jsx(FileViewer, { files: files }) }));
7
+ };
8
+ export default UserAttachments;
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import type { MessageStatusType } from '../MessageStatus/MessageStatus';
3
+ export interface UserMessageProps {
4
+ content: string;
5
+ timestamp: string;
6
+ status?: MessageStatusType;
7
+ onRetry?: () => void;
8
+ files?: File[];
9
+ }
10
+ export declare const UserMessage: React.FC<UserMessageProps>;
11
+ export default UserMessage;
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Text } from '../../../atoms/Text/Text';
3
+ import { MessageStatus } from '../MessageStatus/MessageStatus';
4
+ import { UserAttachments } from '../UserAttachments/UserAttachments';
5
+ export const UserMessage = ({ content, timestamp, status, onRetry, files = [], }) => {
6
+ return (_jsx("div", { className: "user-message", children: _jsxs("div", { className: "user-message__content", children: [_jsxs("div", { className: "user-message__bubble", children: [_jsx(Text, { variant: "caption", color: "secondary", className: "user-message__role", children: "User" }), files.length > 0 && _jsx(UserAttachments, { files: files }), _jsx(Text, { variant: "body", children: content })] }), _jsxs("div", { className: "user-message__meta", children: [status && _jsx(MessageStatus, { status: status, onRetry: onRetry }), (status !== 'sending' && status !== 'failed') && (_jsx(Text, { variant: "caption", color: "secondary", className: "user-message__timestamp", children: timestamp }))] })] }) }));
7
+ };
8
+ export default UserMessage;
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import type { MessageStatusType } from '../../molecules/chat/MessageStatus/MessageStatus';
3
+ export interface ChatMessage {
4
+ role: 'user' | 'assistant';
5
+ content: string;
6
+ timestamp: string;
7
+ date: Date;
8
+ status?: MessageStatusType;
9
+ files?: File[];
10
+ }
11
+ export interface ChatProps {
12
+ messages: ChatMessage[];
13
+ onSend: (message: string) => void;
14
+ onSendWithFiles?: (content: string, files: File[]) => void;
15
+ isAssistantThinking: boolean;
16
+ inputValue: string;
17
+ onInputChange: (value: string) => void;
18
+ onRetry: (message: ChatMessage) => void;
19
+ }
20
+ export declare const Chat: React.FC<ChatProps>;
21
+ export default Chat;
@@ -0,0 +1,278 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React, { useRef, useEffect, useState } from 'react';
3
+ import { UserMessage } from '../../molecules/chat/UserMessage/UserMessage';
4
+ import { AssistantMessage } from '../../molecules/chat/AssistantMessage/AssistantMessage';
5
+ import { AssistantThinkingIndicator } from '../../molecules/chat/AssistantThinkingIndicator/AssistantThinkingIndicator';
6
+ import { Button } from '../../atoms/Button/Button';
7
+ import { DateDivider } from '../../atoms/DateDivider/DateDivider';
8
+ import { ChatInput } from '../../molecules/chat/ChatInput/ChatInput';
9
+ import { ChatHeader } from '../../molecules/chat/ChatHeader/ChatHeader';
10
+ const groupMessagesByDate = (messages) => {
11
+ const groups = [];
12
+ messages.forEach(message => {
13
+ const messageDate = new Date(message.date.getFullYear(), message.date.getMonth(), message.date.getDate());
14
+ const existingGroup = groups.find(group => {
15
+ const groupDate = new Date(group.date.getFullYear(), group.date.getMonth(), group.date.getDate());
16
+ return groupDate.getTime() === messageDate.getTime();
17
+ });
18
+ if (existingGroup) {
19
+ existingGroup.messages.push(message);
20
+ }
21
+ else {
22
+ groups.push({ date: messageDate, messages: [message] });
23
+ }
24
+ });
25
+ return groups.sort((a, b) => a.date.getTime() - b.date.getTime());
26
+ };
27
+ export const Chat = ({ messages, onSend, onSendWithFiles, isAssistantThinking, inputValue, onInputChange, onRetry, }) => {
28
+ const [showScrollToBottom, setShowScrollToBottom] = useState(false);
29
+ const [attachments, setAttachments] = useState([]);
30
+ const messagesEndRef = useRef(null);
31
+ const messagesContainerRef = useRef(null);
32
+ const layoutRef = useRef(null);
33
+ const initialHeightRef = useRef(null);
34
+ const isKeyboardOpenRef = useRef(false);
35
+ const textareaRef = useRef(null);
36
+ // Configurar altura de la aplicación
37
+ useEffect(() => {
38
+ const setAppHeight = () => {
39
+ const height = window.visualViewport
40
+ ? window.visualViewport.height
41
+ : window.innerHeight;
42
+ document.documentElement.style.setProperty('--app-height', `${height}px`);
43
+ };
44
+ setAppHeight();
45
+ window.addEventListener('resize', setAppHeight);
46
+ if (window.visualViewport) {
47
+ window.visualViewport.addEventListener('resize', setAppHeight);
48
+ window.visualViewport.addEventListener('scroll', setAppHeight);
49
+ }
50
+ return () => {
51
+ window.removeEventListener('resize', setAppHeight);
52
+ if (window.visualViewport) {
53
+ window.visualViewport.removeEventListener('resize', setAppHeight);
54
+ window.visualViewport.removeEventListener('scroll', setAppHeight);
55
+ }
56
+ };
57
+ }, []);
58
+ // Manejar el teclado virtual
59
+ useEffect(() => {
60
+ const layout = layoutRef.current;
61
+ if (!layout)
62
+ return;
63
+ let originalPosition = '';
64
+ let originalTop = '';
65
+ const threshold = 100; // px, para detectar si el teclado salió
66
+ const setInitialHeight = () => {
67
+ initialHeightRef.current = window.visualViewport
68
+ ? window.visualViewport.height
69
+ : window.innerHeight;
70
+ };
71
+ setInitialHeight();
72
+ const onViewportResize = () => {
73
+ const currentHeight = window.visualViewport
74
+ ? window.visualViewport.height
75
+ : window.innerHeight;
76
+ const initialHeight = initialHeightRef.current;
77
+ if (initialHeight && !isKeyboardOpenRef.current && initialHeight - currentHeight > threshold) {
78
+ // El teclado salió
79
+ isKeyboardOpenRef.current = true;
80
+ originalPosition = layout.style.position;
81
+ originalTop = layout.style.top;
82
+ layout.style.position = 'absolute';
83
+ layout.style.top = '0';
84
+ window.scrollTo({ top: 0, behavior: 'smooth' });
85
+ }
86
+ else if (initialHeight && isKeyboardOpenRef.current && initialHeight - currentHeight <= threshold) {
87
+ // El teclado se ocultó
88
+ isKeyboardOpenRef.current = false;
89
+ layout.style.position = originalPosition;
90
+ layout.style.top = originalTop;
91
+ }
92
+ };
93
+ if (window.visualViewport) {
94
+ window.visualViewport.addEventListener('resize', onViewportResize);
95
+ }
96
+ else {
97
+ window.addEventListener('resize', onViewportResize);
98
+ }
99
+ return () => {
100
+ if (window.visualViewport) {
101
+ window.visualViewport.removeEventListener('resize', onViewportResize);
102
+ }
103
+ else {
104
+ window.removeEventListener('resize', onViewportResize);
105
+ }
106
+ };
107
+ }, []);
108
+ // Restaurar foco cuando el teclado virtual se oculta
109
+ useEffect(() => {
110
+ const handleViewportChange = () => {
111
+ if (!isKeyboardOpenRef.current && textareaRef.current) {
112
+ // El teclado se ocultó, restaurar foco
113
+ setTimeout(() => {
114
+ textareaRef.current?.focus();
115
+ }, 100);
116
+ }
117
+ };
118
+ if (window.visualViewport) {
119
+ window.visualViewport.addEventListener('resize', handleViewportChange);
120
+ }
121
+ return () => {
122
+ if (window.visualViewport) {
123
+ window.visualViewport.removeEventListener('resize', handleViewportChange);
124
+ }
125
+ };
126
+ }, []);
127
+ // Mantener scroll en la parte superior cuando el teclado está abierto
128
+ useEffect(() => {
129
+ const handleScroll = () => {
130
+ if (isKeyboardOpenRef.current) {
131
+ window.scrollTo(0, 0);
132
+ }
133
+ };
134
+ window.addEventListener('scroll', handleScroll);
135
+ return () => {
136
+ window.removeEventListener('scroll', handleScroll);
137
+ };
138
+ }, []);
139
+ // Scroll automático siempre al fondo cuando cambian los mensajes o el estado de "pensando"
140
+ useEffect(() => {
141
+ requestAnimationFrame(() => {
142
+ messagesEndRef.current?.scrollIntoView({
143
+ behavior: 'smooth',
144
+ block: 'end'
145
+ });
146
+ });
147
+ }, [messages, isAssistantThinking]);
148
+ // Mostrar botón de scroll manual solo si el usuario no está al fondo
149
+ useEffect(() => {
150
+ let timeout = null;
151
+ const handleScroll = () => {
152
+ if (!messagesContainerRef.current)
153
+ return;
154
+ const { scrollTop, scrollHeight, clientHeight } = messagesContainerRef.current;
155
+ const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
156
+ const isAtBottom = distanceFromBottom < 30;
157
+ if (isAtBottom) {
158
+ setShowScrollToBottom(false);
159
+ if (timeout)
160
+ clearTimeout(timeout);
161
+ }
162
+ else {
163
+ setShowScrollToBottom(false);
164
+ if (timeout)
165
+ clearTimeout(timeout);
166
+ timeout = setTimeout(() => {
167
+ if (messagesContainerRef.current) {
168
+ const { scrollTop, scrollHeight, clientHeight } = messagesContainerRef.current;
169
+ const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
170
+ if (distanceFromBottom >= 30) {
171
+ setShowScrollToBottom(true);
172
+ }
173
+ }
174
+ }, 500);
175
+ }
176
+ };
177
+ const container = messagesContainerRef.current;
178
+ if (container) {
179
+ container.addEventListener('scroll', handleScroll, { passive: true });
180
+ handleScroll();
181
+ }
182
+ return () => {
183
+ if (container) {
184
+ container.removeEventListener('scroll', handleScroll);
185
+ }
186
+ if (timeout)
187
+ clearTimeout(timeout);
188
+ };
189
+ }, [messages, isAssistantThinking]);
190
+ // Mantener foco en el input automáticamente
191
+ useEffect(() => {
192
+ const timer = setTimeout(() => {
193
+ if (textareaRef.current) {
194
+ textareaRef.current.focus();
195
+ }
196
+ }, 100);
197
+ return () => clearTimeout(timer);
198
+ }, []);
199
+ // Mantener foco después de que cambien los mensajes
200
+ useEffect(() => {
201
+ if (!isAssistantThinking && textareaRef.current) {
202
+ const timer = setTimeout(() => {
203
+ textareaRef.current?.focus();
204
+ }, 50);
205
+ return () => clearTimeout(timer);
206
+ }
207
+ }, [messages, isAssistantThinking]);
208
+ const handleAttachmentsChange = (files) => {
209
+ setAttachments(files);
210
+ };
211
+ const handleInputKeyDown = (e) => {
212
+ if (e.key === 'Enter' && !e.shiftKey) {
213
+ e.preventDefault();
214
+ handleSendWithFiles(inputValue, attachments);
215
+ }
216
+ };
217
+ const handleSendWithFiles = (content, files) => {
218
+ if (!content.trim() && files.length === 0)
219
+ return;
220
+ if (files.length > 0 && onSendWithFiles) {
221
+ onSendWithFiles(content, files);
222
+ }
223
+ else {
224
+ onSend(content);
225
+ }
226
+ onInputChange && onInputChange('');
227
+ setAttachments([]);
228
+ // Mantener el foco en el input para que el teclado no se oculte
229
+ requestAnimationFrame(() => {
230
+ if (textareaRef.current) {
231
+ textareaRef.current.focus();
232
+ }
233
+ });
234
+ };
235
+ const handleSubmit = () => {
236
+ handleSendWithFiles(inputValue, attachments);
237
+ };
238
+ const handleScrollToBottom = () => {
239
+ requestAnimationFrame(() => {
240
+ messagesEndRef.current?.scrollIntoView({
241
+ behavior: 'smooth',
242
+ block: 'end'
243
+ });
244
+ });
245
+ };
246
+ // Mantener foco en el input siempre que sea posible
247
+ const handleMainClick = (e) => {
248
+ // Solo quitar el foco si se hace clic en el área principal (no en botones o elementos interactivos)
249
+ if (e.target === e.currentTarget) {
250
+ if (textareaRef.current) {
251
+ textareaRef.current.blur();
252
+ }
253
+ }
254
+ };
255
+ // Restaurar foco cuando se hace clic en el input
256
+ const handleInputFocus = () => {
257
+ if (textareaRef.current) {
258
+ textareaRef.current.focus();
259
+ }
260
+ };
261
+ // Restaurar foco cuando se hace clic en cualquier parte del footer
262
+ const handleFooterClick = (e) => {
263
+ // Si se hace clic en el botón de scroll, mantener el foco actual
264
+ if (e.target instanceof Element && e.target.closest('.chat__scroll-to-bottom')) {
265
+ // Si el teclado está abierto, mantener el foco para que no se cierre
266
+ if (isKeyboardOpenRef.current && textareaRef.current) {
267
+ textareaRef.current.focus();
268
+ }
269
+ return;
270
+ }
271
+ if (textareaRef.current) {
272
+ textareaRef.current.focus();
273
+ }
274
+ };
275
+ const messageGroups = groupMessagesByDate(messages);
276
+ return (_jsxs("div", { className: "chat-layout", ref: layoutRef, children: [_jsx("header", { className: "chat-header", children: _jsx(ChatHeader, {}) }), _jsxs("main", { className: "chat-main", ref: messagesContainerRef, onClick: handleMainClick, children: [messageGroups.map((group, groupIndex) => (_jsxs(React.Fragment, { children: [_jsx(DateDivider, { date: group.date }), group.messages.map((msg, msgIndex) => (msg.role === 'user' ? (_jsx(UserMessage, { content: msg.content, timestamp: msg.timestamp, status: msg.status, onRetry: msg.status === 'failed' ? () => onRetry(msg) : undefined, files: msg.files }, `${groupIndex}-${msgIndex}`)) : (_jsx(AssistantMessage, { content: msg.content, timestamp: msg.timestamp }, `${groupIndex}-${msgIndex}`))))] }, `${group.date.getTime()}-${groupIndex}`))), isAssistantThinking && _jsx(AssistantThinkingIndicator, {}), _jsx("div", { ref: messagesEndRef })] }), _jsxs("footer", { className: "chat-footer", onClick: handleFooterClick, children: [_jsx(ChatInput, { value: inputValue, onChange: e => onInputChange(e.target.value), onSend: handleSubmit, onSendWithFiles: onSendWithFiles, onInputKeyDown: handleInputKeyDown, attachments: attachments, onAttachmentsChange: handleAttachmentsChange, textareaRef: textareaRef, onInputFocus: handleInputFocus }), showScrollToBottom && (_jsx(Button, { className: "chat__scroll-to-bottom", variant: "circle", onClick: handleScrollToBottom, "aria-label": "Ir al final", icon: _jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { d: "M12 8v8", stroke: "#fff", strokeWidth: "2", strokeLinecap: "round" }), _jsx("path", { d: "M8 12l4-4 4 4", stroke: "#fff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })] }) }))] })] }));
277
+ };
278
+ export default Chat;
@@ -0,0 +1 @@
1
+ export { Chat } from './Chat';
@@ -0,0 +1 @@
1
+ export { Chat } from './Chat';
@@ -0,0 +1,171 @@
1
+ import * as React from 'react';
2
+ import React__default from 'react';
3
+
4
+ declare const Button: any;
5
+
6
+ interface InputProps extends React__default.InputHTMLAttributes<HTMLInputElement> {
7
+ label?: string;
8
+ error?: string;
9
+ icon?: React__default.ReactNode;
10
+ fullWidth?: boolean;
11
+ variant?: 'default' | 'chat';
12
+ }
13
+ declare const Input: React__default.FC<InputProps>;
14
+
15
+ interface TextProps {
16
+ variant?: 'h1' | 'h2' | 'h3' | 'h4' | 'body' | 'small' | 'caption';
17
+ weight?: 'normal' | 'medium' | 'semibold' | 'bold';
18
+ color?: 'primary' | 'secondary' | 'inherit';
19
+ align?: 'left' | 'center' | 'right';
20
+ className?: string;
21
+ children: React__default.ReactNode;
22
+ }
23
+ declare const Text: React__default.FC<TextProps>;
24
+
25
+ declare const Textarea: any;
26
+
27
+ interface LinkProps {
28
+ href: string;
29
+ children: React__default.ReactNode;
30
+ variant?: 'primary' | 'secondary' | 'accent';
31
+ size?: 'small' | 'medium' | 'large';
32
+ weight?: 'normal' | 'medium' | 'semibold' | 'bold';
33
+ underline?: boolean;
34
+ external?: boolean;
35
+ className?: string;
36
+ onClick?: (e: React__default.MouseEvent<HTMLAnchorElement>) => void;
37
+ }
38
+ declare const Link: React__default.FC<LinkProps>;
39
+
40
+ interface AvatarProps {
41
+ src?: string;
42
+ alt?: string;
43
+ size?: 'small' | 'medium' | 'large';
44
+ variant?: 'user' | 'assistant';
45
+ className?: string;
46
+ }
47
+ declare const Avatar: React__default.FC<AvatarProps>;
48
+
49
+ interface AttachmentPreviewProps {
50
+ file: File;
51
+ onRemove?: () => void;
52
+ onClick?: () => void;
53
+ }
54
+ declare const AttachmentPreview: React__default.FC<AttachmentPreviewProps>;
55
+
56
+ interface SelectMenuProps {
57
+ open: boolean;
58
+ anchorRef: React__default.RefObject<HTMLElement>;
59
+ onSelect: (option: string) => void;
60
+ onClose: () => void;
61
+ }
62
+ declare const SelectMenu: React__default.FC<SelectMenuProps>;
63
+
64
+ interface DateDividerProps {
65
+ date: Date;
66
+ className?: string;
67
+ }
68
+ declare const DateDivider: React__default.FC<DateDividerProps>;
69
+
70
+ interface LogoProps {
71
+ className?: string;
72
+ }
73
+ declare const Logo: React__default.FC<LogoProps>;
74
+
75
+ interface AssistantMessageProps {
76
+ content: string;
77
+ timestamp: string;
78
+ }
79
+ declare const AssistantMessage: React__default.FC<AssistantMessageProps>;
80
+
81
+ declare const AssistantThinkingIndicator: React__default.FC;
82
+
83
+ interface ChatHeaderProps {
84
+ title?: string;
85
+ }
86
+ declare const ChatHeader: React__default.FC<ChatHeaderProps>;
87
+
88
+ interface ChatInputProps {
89
+ value: string;
90
+ onChange: (e: React__default.ChangeEvent<HTMLTextAreaElement>) => void;
91
+ onSend: () => void;
92
+ onSendWithFiles?: (content: string, files: File[]) => void;
93
+ onInputKeyDown?: (e: React__default.KeyboardEvent<HTMLTextAreaElement>) => void;
94
+ onInputFocus?: () => void;
95
+ disabled?: boolean;
96
+ maxFiles?: number;
97
+ accept?: string;
98
+ attachments?: File[];
99
+ onAttachmentsChange?: (files: File[]) => void;
100
+ textareaRef?: React__default.RefObject<HTMLTextAreaElement>;
101
+ }
102
+ declare const ChatInput: React.ForwardRefExoticComponent<ChatInputProps & React.RefAttributes<HTMLFormElement>>;
103
+
104
+ interface FileViewerProps {
105
+ files: File[];
106
+ onClose?: () => void;
107
+ }
108
+ declare const FileViewer: React__default.FC<FileViewerProps>;
109
+
110
+ interface FullscreenViewerProps {
111
+ isOpen: boolean;
112
+ onClose: () => void;
113
+ files: File[];
114
+ currentIndex: number;
115
+ onChangeIndex: (newIndex: number) => void;
116
+ }
117
+ declare const FullscreenViewer: React__default.FC<FullscreenViewerProps>;
118
+
119
+ type MessageStatusType = 'sending' | 'sent' | 'failed';
120
+ interface MessageStatusProps {
121
+ status: MessageStatusType;
122
+ className?: string;
123
+ onRetry?: () => void;
124
+ }
125
+ declare const MessageStatus: React__default.FC<MessageStatusProps>;
126
+
127
+ interface ModalProps {
128
+ isOpen: boolean;
129
+ onClose: () => void;
130
+ children: React__default.ReactNode;
131
+ title?: string;
132
+ showCloseButton?: boolean;
133
+ closeOnOverlayClick?: boolean;
134
+ closeOnEscape?: boolean;
135
+ }
136
+ declare const Modal: React__default.FC<ModalProps>;
137
+
138
+ interface UserAttachmentsProps {
139
+ files: File[];
140
+ }
141
+ declare const UserAttachments: React__default.FC<UserAttachmentsProps>;
142
+
143
+ interface UserMessageProps {
144
+ content: string;
145
+ timestamp: string;
146
+ status?: MessageStatusType;
147
+ onRetry?: () => void;
148
+ files?: File[];
149
+ }
150
+ declare const UserMessage: React__default.FC<UserMessageProps>;
151
+
152
+ interface ChatMessage {
153
+ role: 'user' | 'assistant';
154
+ content: string;
155
+ timestamp: string;
156
+ date: Date;
157
+ status?: MessageStatusType;
158
+ files?: File[];
159
+ }
160
+ interface ChatProps {
161
+ messages: ChatMessage[];
162
+ onSend: (message: string) => void;
163
+ onSendWithFiles?: (content: string, files: File[]) => void;
164
+ isAssistantThinking: boolean;
165
+ inputValue: string;
166
+ onInputChange: (value: string) => void;
167
+ onRetry: (message: ChatMessage) => void;
168
+ }
169
+ declare const Chat: React__default.FC<ChatProps>;
170
+
171
+ export { AssistantMessage, AssistantThinkingIndicator, AttachmentPreview, Avatar, Button, Chat, ChatHeader, ChatInput, DateDivider, FileViewer, FullscreenViewer, Input, Link, Logo, MessageStatus, Modal, SelectMenu, Text, Textarea, UserAttachments, UserMessage };