@firstlovecenter/ai-chat 0.9.3 → 0.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/ui/index.cjs +42 -6
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.js +40 -6
- package/dist/ui/index.js.map +1 -1
- package/package.json +12 -12
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,18 @@ All notable changes to `@firstlovecenter/ai-chat` are documented here.
|
|
|
5
5
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.9.4] — 2026-05-09
|
|
9
|
+
|
|
10
|
+
Markdown in assistant answers now actually renders as markdown.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **Literal `**bold**` / `*italic*` showing in chat output.** `paragraph_brief` prose, `list` items, and `callout` text were rendered as plain text inside `<p>{block.prose}</p>`, so markdown emitted by the model leaked through verbatim. The renderer now pipes those three block types through `react-markdown` (with `remark-gfm`) and a small components map that keeps the existing `text-sm leading-6` look. Errors and the user's own messages are still rendered as plain text — only model-authored content is parsed.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **`react-markdown` + `remark-gfm` dependencies.** Required by the change above. The `ui` bundle grows by ~30 KB gzipped — small enough that no lazy-load gymnastics are warranted.
|
|
19
|
+
|
|
8
20
|
## [0.9.3] — 2026-05-09
|
|
9
21
|
|
|
10
22
|
Fixes the actual root cause of the "messages persisted but reload shows empty thread" bug — turns out it was at the data layer, not the navigation layer.
|
package/dist/ui/index.cjs
CHANGED
|
@@ -7,6 +7,8 @@ var Link = require('next/link');
|
|
|
7
7
|
var lucideReact = require('lucide-react');
|
|
8
8
|
var radixUi = require('radix-ui');
|
|
9
9
|
var jsxRuntime = require('react/jsx-runtime');
|
|
10
|
+
var ReactMarkdown = require('react-markdown');
|
|
11
|
+
var remarkGfm = require('remark-gfm');
|
|
10
12
|
var RechartsPrimitive = require('recharts');
|
|
11
13
|
var react = require('@ai-sdk/react');
|
|
12
14
|
|
|
@@ -32,6 +34,8 @@ function _interopNamespace(e) {
|
|
|
32
34
|
|
|
33
35
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
34
36
|
var Link__default = /*#__PURE__*/_interopDefault(Link);
|
|
37
|
+
var ReactMarkdown__default = /*#__PURE__*/_interopDefault(ReactMarkdown);
|
|
38
|
+
var remarkGfm__default = /*#__PURE__*/_interopDefault(remarkGfm);
|
|
35
39
|
var RechartsPrimitive__namespace = /*#__PURE__*/_interopNamespace(RechartsPrimitive);
|
|
36
40
|
|
|
37
41
|
// src/ui/_shared/cn.ts
|
|
@@ -512,22 +516,54 @@ function isBlockEmpty(b) {
|
|
|
512
516
|
if (b.kind === "table") return !Array.isArray(b.rows) || b.rows.length === 0;
|
|
513
517
|
return false;
|
|
514
518
|
}
|
|
519
|
+
var PROSE_MD_COMPONENTS = {
|
|
520
|
+
p: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 last:mb-0", children }),
|
|
521
|
+
ul: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "my-1 list-disc pl-6", children }),
|
|
522
|
+
ol: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "my-1 list-decimal pl-6", children }),
|
|
523
|
+
li: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "leading-6", children }),
|
|
524
|
+
strong: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("strong", { className: "font-semibold", children }),
|
|
525
|
+
em: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("em", { className: "italic", children }),
|
|
526
|
+
code: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("code", { className: "rounded bg-muted px-1 py-0.5 font-mono text-[0.85em]", children }),
|
|
527
|
+
a: ({ children, href }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
528
|
+
"a",
|
|
529
|
+
{
|
|
530
|
+
href,
|
|
531
|
+
target: "_blank",
|
|
532
|
+
rel: "noreferrer noopener",
|
|
533
|
+
className: "underline underline-offset-2",
|
|
534
|
+
children
|
|
535
|
+
}
|
|
536
|
+
)
|
|
537
|
+
};
|
|
538
|
+
var INLINE_MD_COMPONENTS = {
|
|
539
|
+
...PROSE_MD_COMPONENTS,
|
|
540
|
+
p: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children })
|
|
541
|
+
};
|
|
542
|
+
function ProseMarkdown({ children }) {
|
|
543
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ReactMarkdown__default.default, { remarkPlugins: [remarkGfm__default.default], components: PROSE_MD_COMPONENTS, children });
|
|
544
|
+
}
|
|
545
|
+
function InlineMarkdown({ children }) {
|
|
546
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ReactMarkdown__default.default, { remarkPlugins: [remarkGfm__default.default], components: INLINE_MD_COMPONENTS, children });
|
|
547
|
+
}
|
|
515
548
|
function AnswerBlocks({ blocks }) {
|
|
516
549
|
const visible = blocks.filter((b) => !isBlockEmpty(b));
|
|
517
550
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-3", children: visible.map((b, i) => /* @__PURE__ */ jsxRuntime.jsx(BlockView, { block: b }, i)) });
|
|
518
551
|
}
|
|
519
552
|
function BlockView({ block }) {
|
|
520
553
|
if (block.kind === "paragraph_brief") {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
554
|
+
if (!block.prose) {
|
|
555
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm leading-6 text-muted-foreground", children: [
|
|
556
|
+
block.key_facts.join(". "),
|
|
557
|
+
"\u2026"
|
|
558
|
+
] });
|
|
559
|
+
}
|
|
560
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm leading-6 text-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(ProseMarkdown, { children: block.prose }) });
|
|
525
561
|
}
|
|
526
562
|
if (block.kind === "list") {
|
|
527
563
|
const Tag = block.style === "numbered" ? "ol" : "ul";
|
|
528
564
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
529
565
|
block.title && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-1 text-sm font-medium", children: block.title }),
|
|
530
|
-
/* @__PURE__ */ jsxRuntime.jsx(Tag, { className: block.style === "numbered" ? "list-decimal pl-6" : "list-disc pl-6", children: block.items.map((it, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "text-sm leading-6", children: it }, i)) })
|
|
566
|
+
/* @__PURE__ */ jsxRuntime.jsx(Tag, { className: block.style === "numbered" ? "list-decimal pl-6" : "list-disc pl-6", children: block.items.map((it, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "text-sm leading-6", children: /* @__PURE__ */ jsxRuntime.jsx(InlineMarkdown, { children: it }) }, i)) })
|
|
531
567
|
] });
|
|
532
568
|
}
|
|
533
569
|
if (block.kind === "chart") {
|
|
@@ -544,7 +580,7 @@ function BlockView({ block }) {
|
|
|
544
580
|
}
|
|
545
581
|
if (block.kind === "callout") {
|
|
546
582
|
const cls = block.tone === "warn" ? "border-amber-300 dark:border-amber-800 bg-amber-50 dark:bg-amber-950/30 text-amber-900 dark:text-amber-100" : block.tone === "success" ? "border-emerald-300 dark:border-emerald-800 bg-emerald-50 dark:bg-emerald-950/30 text-emerald-900 dark:text-emerald-100" : "border-sky-300 bg-sky-50 text-sky-900";
|
|
547
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `rounded border p-3 text-sm ${cls}`, children: block.text });
|
|
583
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `rounded border p-3 text-sm leading-6 ${cls}`, children: /* @__PURE__ */ jsxRuntime.jsx(ProseMarkdown, { children: block.text }) });
|
|
548
584
|
}
|
|
549
585
|
return null;
|
|
550
586
|
}
|