@extrachill/chat 0.3.0 → 0.3.1
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.
|
@@ -7,7 +7,6 @@ export interface ChatMessageProps {
|
|
|
7
7
|
contentFormat?: ContentFormat;
|
|
8
8
|
/**
|
|
9
9
|
* Custom content renderer. When provided, overrides contentFormat.
|
|
10
|
-
* Use this to plug in your own markdown renderer (react-markdown, etc.).
|
|
11
10
|
*/
|
|
12
11
|
renderContent?: (content: string, role: ChatMessageType['role']) => ReactNode;
|
|
13
12
|
/** Additional CSS class name on the outer wrapper. */
|
|
@@ -17,7 +16,7 @@ export interface ChatMessageProps {
|
|
|
17
16
|
* Renders a single chat message bubble.
|
|
18
17
|
*
|
|
19
18
|
* User messages align right, assistant messages align left.
|
|
20
|
-
*
|
|
19
|
+
* Markdown content is rendered via react-markdown (lazy-loaded).
|
|
21
20
|
*/
|
|
22
21
|
export declare function ChatMessage({ message, contentFormat, renderContent, className, }: ChatMessageProps): import("react/jsx-runtime").JSX.Element;
|
|
23
22
|
//# sourceMappingURL=ChatMessage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatMessage.d.ts","sourceRoot":"","sources":["../../src/components/ChatMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"ChatMessage.d.ts","sourceRoot":"","sources":["../../src/components/ChatMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAkB,MAAM,OAAO,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,IAAI,eAAe,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAKvF,MAAM,WAAW,gBAAgB;IAChC,6BAA6B;IAC7B,OAAO,EAAE,eAAe,CAAC;IACzB,6DAA6D;IAC7D,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,KAAK,SAAS,CAAC;IAC9E,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EAC3B,OAAO,EACP,aAA0B,EAC1B,aAAa,EACb,SAAS,GACT,EAAE,gBAAgB,2CAyBlB"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { lazy, Suspense } from 'react';
|
|
3
3
|
import { markdownToHtml } from "../markdown.js";
|
|
4
|
+
const ReactMarkdown = lazy(() => import('react-markdown'));
|
|
4
5
|
/**
|
|
5
6
|
* Renders a single chat message bubble.
|
|
6
7
|
*
|
|
7
8
|
* User messages align right, assistant messages align left.
|
|
8
|
-
*
|
|
9
|
+
* Markdown content is rendered via react-markdown (lazy-loaded).
|
|
9
10
|
*/
|
|
10
11
|
export function ChatMessage({ message, contentFormat = 'markdown', renderContent, className, }) {
|
|
11
12
|
const isUser = message.role === 'user';
|
|
@@ -16,16 +17,19 @@ export function ChatMessage({ message, contentFormat = 'markdown', renderContent
|
|
|
16
17
|
? renderContent(message.content, message.role)
|
|
17
18
|
: _jsx(DefaultContent, { content: message.content, format: contentFormat }) }), message.timestamp && (_jsx("time", { className: `${baseClass}__timestamp`, dateTime: message.timestamp, title: new Date(message.timestamp).toLocaleString(), children: formatTime(message.timestamp) }))] }));
|
|
18
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Markdown rendered via lazy-loaded react-markdown.
|
|
22
|
+
* Falls back to the built-in lightweight parser while loading.
|
|
23
|
+
*/
|
|
24
|
+
function MarkdownContent({ content }) {
|
|
25
|
+
return (_jsx(Suspense, { fallback: _jsx("div", { dangerouslySetInnerHTML: { __html: markdownToHtml(content) } }), children: _jsx(ReactMarkdown, { children: content }) }));
|
|
26
|
+
}
|
|
19
27
|
function DefaultContent({ content, format }) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return null;
|
|
26
|
-
}, [content, format]);
|
|
27
|
-
if (html !== null) {
|
|
28
|
-
return _jsx("div", { dangerouslySetInnerHTML: { __html: html } });
|
|
28
|
+
if (format === 'html') {
|
|
29
|
+
return _jsx("div", { dangerouslySetInnerHTML: { __html: content } });
|
|
30
|
+
}
|
|
31
|
+
if (format === 'markdown') {
|
|
32
|
+
return _jsx(MarkdownContent, { content: content });
|
|
29
33
|
}
|
|
30
34
|
// Plain text — split on double newlines for paragraphs.
|
|
31
35
|
return (_jsx(_Fragment, { children: content.split('\n\n').map((paragraph, i) => (_jsx("p", { children: paragraph }, i))) }));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@extrachill/chat",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Chat UI components with built-in REST API client. Speaks the standard chat message format natively.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -52,10 +52,13 @@
|
|
|
52
52
|
"react-dom": ">=18.0.0"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"typescript": "^5.7.0",
|
|
56
55
|
"@types/react": "^18.0.0",
|
|
57
56
|
"@types/react-dom": "^18.0.0",
|
|
58
57
|
"react": "^18.0.0",
|
|
59
|
-
"react-dom": "^18.0.0"
|
|
58
|
+
"react-dom": "^18.0.0",
|
|
59
|
+
"typescript": "^5.7.0"
|
|
60
|
+
},
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"react-markdown": "^10.1.0"
|
|
60
63
|
}
|
|
61
64
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { type ReactNode,
|
|
1
|
+
import { type ReactNode, lazy, Suspense } from 'react';
|
|
2
2
|
import type { ChatMessage as ChatMessageType, ContentFormat } from '../types/index.ts';
|
|
3
3
|
import { markdownToHtml } from '../markdown.ts';
|
|
4
4
|
|
|
5
|
+
const ReactMarkdown = lazy(() => import('react-markdown'));
|
|
6
|
+
|
|
5
7
|
export interface ChatMessageProps {
|
|
6
8
|
/** The message to render. */
|
|
7
9
|
message: ChatMessageType;
|
|
@@ -9,7 +11,6 @@ export interface ChatMessageProps {
|
|
|
9
11
|
contentFormat?: ContentFormat;
|
|
10
12
|
/**
|
|
11
13
|
* Custom content renderer. When provided, overrides contentFormat.
|
|
12
|
-
* Use this to plug in your own markdown renderer (react-markdown, etc.).
|
|
13
14
|
*/
|
|
14
15
|
renderContent?: (content: string, role: ChatMessageType['role']) => ReactNode;
|
|
15
16
|
/** Additional CSS class name on the outer wrapper. */
|
|
@@ -20,7 +21,7 @@ export interface ChatMessageProps {
|
|
|
20
21
|
* Renders a single chat message bubble.
|
|
21
22
|
*
|
|
22
23
|
* User messages align right, assistant messages align left.
|
|
23
|
-
*
|
|
24
|
+
* Markdown content is rendered via react-markdown (lazy-loaded).
|
|
24
25
|
*/
|
|
25
26
|
export function ChatMessage({
|
|
26
27
|
message,
|
|
@@ -59,15 +60,29 @@ interface DefaultContentProps {
|
|
|
59
60
|
format: ContentFormat;
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Markdown rendered via lazy-loaded react-markdown.
|
|
65
|
+
* Falls back to the built-in lightweight parser while loading.
|
|
66
|
+
*/
|
|
67
|
+
function MarkdownContent({ content }: { content: string }) {
|
|
68
|
+
return (
|
|
69
|
+
<Suspense
|
|
70
|
+
fallback={
|
|
71
|
+
<div dangerouslySetInnerHTML={{ __html: markdownToHtml(content) }} />
|
|
72
|
+
}
|
|
73
|
+
>
|
|
74
|
+
<ReactMarkdown>{content}</ReactMarkdown>
|
|
75
|
+
</Suspense>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
62
79
|
function DefaultContent({ content, format }: DefaultContentProps) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
return null;
|
|
67
|
-
}, [content, format]);
|
|
80
|
+
if (format === 'html') {
|
|
81
|
+
return <div dangerouslySetInnerHTML={{ __html: content }} />;
|
|
82
|
+
}
|
|
68
83
|
|
|
69
|
-
if (
|
|
70
|
-
return <
|
|
84
|
+
if (format === 'markdown') {
|
|
85
|
+
return <MarkdownContent content={content} />;
|
|
71
86
|
}
|
|
72
87
|
|
|
73
88
|
// Plain text — split on double newlines for paragraphs.
|