@djangocfg/ui-tools 2.1.298 → 2.1.299

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 (28) hide show
  1. package/README.md +126 -2
  2. package/dist/{DocsLayout-74WIW7L3.mjs → DocsLayout-MWRKNFXR.mjs} +3 -3
  3. package/dist/{DocsLayout-74WIW7L3.mjs.map → DocsLayout-MWRKNFXR.mjs.map} +1 -1
  4. package/dist/{DocsLayout-IA55EXRN.cjs → DocsLayout-NWJUF42A.cjs} +48 -48
  5. package/dist/{DocsLayout-IA55EXRN.cjs.map → DocsLayout-NWJUF42A.cjs.map} +1 -1
  6. package/dist/{chunk-2BBXP3DH.mjs → chunk-CKD7GNE5.mjs} +220 -187
  7. package/dist/chunk-CKD7GNE5.mjs.map +1 -0
  8. package/dist/{chunk-Q6FNLXLZ.cjs → chunk-SEXWBCLX.cjs} +256 -222
  9. package/dist/chunk-SEXWBCLX.cjs.map +1 -0
  10. package/dist/index.cjs +13 -9
  11. package/dist/index.d.cts +82 -59
  12. package/dist/index.d.ts +82 -59
  13. package/dist/index.mjs +4 -4
  14. package/package.json +6 -6
  15. package/src/components/markdown/MarkdownMessage/CodeBlock.tsx +69 -0
  16. package/src/components/markdown/MarkdownMessage/CollapseToggle.tsx +60 -0
  17. package/src/components/markdown/MarkdownMessage/MarkdownMessage.story.tsx +171 -0
  18. package/src/components/markdown/MarkdownMessage/MarkdownMessage.tsx +202 -0
  19. package/src/components/markdown/MarkdownMessage/components.tsx +154 -0
  20. package/src/components/markdown/MarkdownMessage/index.ts +13 -0
  21. package/src/components/markdown/MarkdownMessage/linkRules.ts +83 -0
  22. package/src/components/markdown/MarkdownMessage/plainText.ts +50 -0
  23. package/src/components/markdown/MarkdownMessage/sanitize.ts +78 -0
  24. package/src/components/markdown/MarkdownMessage/types.ts +104 -0
  25. package/src/components/markdown/index.ts +6 -1
  26. package/dist/chunk-2BBXP3DH.mjs.map +0 -1
  27. package/dist/chunk-Q6FNLXLZ.cjs.map +0 -1
  28. package/src/components/markdown/MarkdownMessage.tsx +0 -721
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkWGEGR3DF_cjs = require('./chunk-WGEGR3DF.cjs');
4
- var React3 = require('react');
4
+ var React6 = require('react');
5
5
  require('@djangocfg/ui-core/styles/palette');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
7
  var ReactMarkdown = require('react-markdown');
@@ -15,28 +15,13 @@ var openapiSampler = require('openapi-sampler');
15
15
 
16
16
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
17
17
 
18
- var React3__default = /*#__PURE__*/_interopDefault(React3);
18
+ var React6__default = /*#__PURE__*/_interopDefault(React6);
19
19
  var ReactMarkdown__default = /*#__PURE__*/_interopDefault(ReactMarkdown);
20
20
  var rehypeRaw__default = /*#__PURE__*/_interopDefault(rehypeRaw);
21
21
  var rehypeSanitize__default = /*#__PURE__*/_interopDefault(rehypeSanitize);
22
22
  var remarkGfm__default = /*#__PURE__*/_interopDefault(remarkGfm);
23
23
  var consola2__default = /*#__PURE__*/_interopDefault(consola2);
24
24
 
25
- var MermaidClient = React3.lazy(() => import('./Mermaid.client-RSWUUHIL.cjs'));
26
- var LoadingFallback = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center items-center min-h-[100px]", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-6 w-6 border-b-2 border-primary" }) }), "LoadingFallback");
27
- var Mermaid = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((props) => {
28
- return /* @__PURE__ */ jsxRuntime.jsx(React3.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(LoadingFallback, {}), children: /* @__PURE__ */ jsxRuntime.jsx(MermaidClient, { ...props }) });
29
- }, "Mermaid");
30
- var Mermaid_default = Mermaid;
31
- var PrettyCodeClient = React3.lazy(() => import('./PrettyCode.client-RPDIE5CH.cjs'));
32
- var LoadingFallback2 = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative rounded-sm border border-border overflow-hidden bg-muted dark:bg-zinc-900", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
33
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-pulse h-4 w-4 rounded-full bg-muted-foreground/20" }),
34
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "Loading code..." })
35
- ] }) }) }), "LoadingFallback");
36
- var PrettyCode = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((props) => {
37
- return /* @__PURE__ */ jsxRuntime.jsx(React3.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(LoadingFallback2, {}), children: /* @__PURE__ */ jsxRuntime.jsx(PrettyCodeClient, { ...props }) });
38
- }, "PrettyCode");
39
- var PrettyCode_default = PrettyCode;
40
25
  function smartTruncate(content, maxLength) {
41
26
  if (content.length <= maxLength) {
42
27
  return content;
@@ -110,10 +95,10 @@ function fixUnclosedMarkdown(content) {
110
95
  chunkWGEGR3DF_cjs.__name(fixUnclosedMarkdown, "fixUnclosedMarkdown");
111
96
  function useCollapsibleContent(content, options = {}) {
112
97
  const { maxLength, maxLines, defaultExpanded = false } = options;
113
- const [isCollapsed, setIsCollapsed] = React3.useState(!defaultExpanded);
98
+ const [isCollapsed, setIsCollapsed] = React6.useState(!defaultExpanded);
114
99
  const originalLength = content.length;
115
100
  const originalLineCount = content.split("\n").length;
116
- const { shouldCollapse, truncatedContent } = React3.useMemo(() => {
101
+ const { shouldCollapse, truncatedContent } = React6.useMemo(() => {
117
102
  if (maxLength === void 0 && maxLines === void 0) {
118
103
  return { shouldCollapse: false, truncatedContent: content };
119
104
  }
@@ -129,16 +114,16 @@ function useCollapsibleContent(content, options = {}) {
129
114
  }
130
115
  return { shouldCollapse: needsCollapse, truncatedContent: result };
131
116
  }, [content, maxLength, maxLines, originalLineCount]);
132
- const displayContent = React3.useMemo(() => {
117
+ const displayContent = React6.useMemo(() => {
133
118
  if (!shouldCollapse || !isCollapsed) {
134
119
  return content;
135
120
  }
136
121
  return truncatedContent;
137
122
  }, [content, truncatedContent, shouldCollapse, isCollapsed]);
138
- const toggleCollapsed = React3.useCallback(() => {
123
+ const toggleCollapsed = React6.useCallback(() => {
139
124
  setIsCollapsed((prev) => !prev);
140
125
  }, []);
141
- const setCollapsed = React3.useCallback((collapsed) => {
126
+ const setCollapsed = React6.useCallback((collapsed) => {
142
127
  setIsCollapsed(collapsed);
143
128
  }, []);
144
129
  return {
@@ -152,6 +137,72 @@ function useCollapsibleContent(content, options = {}) {
152
137
  };
153
138
  }
154
139
  chunkWGEGR3DF_cjs.__name(useCollapsibleContent, "useCollapsibleContent");
140
+ function extractTextFromChildren(children) {
141
+ if (typeof children === "string") return children;
142
+ if (typeof children === "number") return String(children);
143
+ if (React6__default.default.isValidElement(children)) {
144
+ const props = children.props;
145
+ return extractTextFromChildren(props.children);
146
+ }
147
+ if (Array.isArray(children)) {
148
+ return children.map(extractTextFromChildren).join("");
149
+ }
150
+ return "";
151
+ }
152
+ chunkWGEGR3DF_cjs.__name(extractTextFromChildren, "extractTextFromChildren");
153
+ function hasMarkdownSyntax(text) {
154
+ if (text.trim().includes("\n")) return true;
155
+ if (/<\/?[a-zA-Z][a-zA-Z0-9-]*(\s[^>]*)?\/?>/.test(text)) return true;
156
+ const patterns = [
157
+ /^#{1,6}\s/m,
158
+ // Headers
159
+ /\*\*[^*]+\*\*/,
160
+ // Bold
161
+ /\*[^*]+\*/,
162
+ // Italic
163
+ /__[^_]+__/,
164
+ // Bold (underscore)
165
+ /_[^_]+_/,
166
+ // Italic (underscore)
167
+ /\[.+\]\(.+\)/,
168
+ // Links
169
+ /!\[.*\]\(.+\)/,
170
+ // Images
171
+ /```[\s\S]*```/,
172
+ // Code blocks
173
+ /`[^`]+`/,
174
+ // Inline code
175
+ /^\s*[-*+]\s/m,
176
+ // Unordered lists
177
+ /^\s*\d+\.\s/m,
178
+ // Ordered lists
179
+ /^\s*>/m,
180
+ // Blockquotes
181
+ /\|.+\|/,
182
+ // Tables
183
+ /^---+$/m,
184
+ // Horizontal rules
185
+ /~~[^~]+~~/
186
+ // Strikethrough
187
+ ];
188
+ return patterns.some((p) => p.test(text));
189
+ }
190
+ chunkWGEGR3DF_cjs.__name(hasMarkdownSyntax, "hasMarkdownSyntax");
191
+ var MermaidClient = React6.lazy(() => import('./Mermaid.client-RSWUUHIL.cjs'));
192
+ var LoadingFallback = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center items-center min-h-[100px]", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-6 w-6 border-b-2 border-primary" }) }), "LoadingFallback");
193
+ var Mermaid = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((props) => {
194
+ return /* @__PURE__ */ jsxRuntime.jsx(React6.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(LoadingFallback, {}), children: /* @__PURE__ */ jsxRuntime.jsx(MermaidClient, { ...props }) });
195
+ }, "Mermaid");
196
+ var Mermaid_default = Mermaid;
197
+ var PrettyCodeClient = React6.lazy(() => import('./PrettyCode.client-RPDIE5CH.cjs'));
198
+ var LoadingFallback2 = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative rounded-sm border border-border overflow-hidden bg-muted dark:bg-zinc-900", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
199
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-pulse h-4 w-4 rounded-full bg-muted-foreground/20" }),
200
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "Loading code..." })
201
+ ] }) }) }), "LoadingFallback");
202
+ var PrettyCode = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((props) => {
203
+ return /* @__PURE__ */ jsxRuntime.jsx(React6.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(LoadingFallback2, {}), children: /* @__PURE__ */ jsxRuntime.jsx(PrettyCodeClient, { ...props }) });
204
+ }, "PrettyCode");
205
+ var PrettyCode_default = PrettyCode;
155
206
  var HTML_SCHEMA_BASE = {
156
207
  ...rehypeSanitize.defaultSchema,
157
208
  tagNames: [
@@ -200,22 +251,6 @@ function buildUrlTransform(extraProtocols) {
200
251
  };
201
252
  }
202
253
  chunkWGEGR3DF_cjs.__name(buildUrlTransform, "buildUrlTransform");
203
- var extractTextFromChildren = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((children) => {
204
- if (typeof children === "string") {
205
- return children;
206
- }
207
- if (typeof children === "number") {
208
- return String(children);
209
- }
210
- if (React3__default.default.isValidElement(children)) {
211
- const props = children.props;
212
- return extractTextFromChildren(props.children);
213
- }
214
- if (Array.isArray(children)) {
215
- return children.map(extractTextFromChildren).join("");
216
- }
217
- return "";
218
- }, "extractTextFromChildren");
219
254
  var CodeBlock = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ code, language, isUser, isCompact = false }) => {
220
255
  const theme = hooks.useResolvedTheme();
221
256
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative group my-3", children: [
@@ -245,25 +280,40 @@ var CodeBlock = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ code, language, isUs
245
280
  )
246
281
  ] });
247
282
  }, "CodeBlock");
248
- var createMarkdownComponents = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((isUser = false, isCompact = false) => {
283
+ var CodeBlockFallback = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ code, isUser }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative group my-3", children: [
284
+ /* @__PURE__ */ jsxRuntime.jsx(
285
+ components.CopyButton,
286
+ {
287
+ value: code,
288
+ variant: "ghost",
289
+ className: `
290
+ absolute top-2 right-2 z-10 opacity-0 group-hover:opacity-100 transition-opacity
291
+ h-8 w-8
292
+ ${isUser ? "hover:bg-white/20 text-white" : "hover:bg-muted-foreground/20 text-muted-foreground hover:text-foreground"}
293
+ `,
294
+ title: "Copy code"
295
+ }
296
+ ),
297
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: `
298
+ p-3 rounded text-xs font-mono overflow-x-auto
299
+ ${isUser ? "bg-white/10 text-white" : "bg-muted text-foreground"}
300
+ `, children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: code }) })
301
+ ] }), "CodeBlockFallback");
302
+ function createMarkdownComponents(isUser = false, isCompact = false) {
249
303
  const textSize = isCompact ? "text-xs" : "text-sm";
250
304
  const headingBase = isCompact ? "text-sm" : "text-base";
251
305
  const headingSm = isCompact ? "text-xs" : "text-sm";
252
306
  return {
253
- // Headings - scaled for chat context
254
307
  h1: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => /* @__PURE__ */ jsxRuntime.jsx("h1", { className: `${headingBase} font-bold mb-2 mt-3 first:mt-0`, children }), "h1"),
255
308
  h2: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => /* @__PURE__ */ jsxRuntime.jsx("h2", { className: `${headingSm} font-bold mb-2 mt-3 first:mt-0`, children }), "h2"),
256
309
  h3: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => /* @__PURE__ */ jsxRuntime.jsx("h3", { className: `${headingSm} font-semibold mb-1 mt-2 first:mt-0`, children }), "h3"),
257
310
  h4: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => /* @__PURE__ */ jsxRuntime.jsx("h4", { className: `${headingSm} font-semibold mb-1 mt-2 first:mt-0`, children }), "h4"),
258
311
  h5: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => /* @__PURE__ */ jsxRuntime.jsx("h5", { className: `${headingSm} font-medium mb-1 mt-2 first:mt-0`, children }), "h5"),
259
312
  h6: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => /* @__PURE__ */ jsxRuntime.jsx("h6", { className: `${headingSm} font-medium mb-1 mt-2 first:mt-0`, children }), "h6"),
260
- // Paragraphs - optimized for chat readability
261
313
  p: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => /* @__PURE__ */ jsxRuntime.jsx("p", { className: `${textSize} mb-4 last:mb-0 leading-7 break-words font-light`, children }), "p"),
262
- // Lists - compact
263
314
  ul: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => /* @__PURE__ */ jsxRuntime.jsx("ul", { className: `list-disc list-inside mb-2 space-y-1 ${textSize}`, children }), "ul"),
264
315
  ol: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => /* @__PURE__ */ jsxRuntime.jsx("ol", { className: `list-decimal list-inside mb-2 space-y-1 ${textSize}`, children }), "ol"),
265
316
  li: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "break-words", children }), "li"),
266
- // Links - appropriate for chat context
267
317
  a: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ href, children }) => /* @__PURE__ */ jsxRuntime.jsx(
268
318
  "a",
269
319
  {
@@ -274,11 +324,10 @@ var createMarkdownComponents = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((isUser
274
324
  children
275
325
  }
276
326
  ), "a"),
277
- // Code blocks - using CodeBlock component with copy functionality
278
327
  pre: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => {
279
328
  let codeContent = "";
280
329
  let language = "plaintext";
281
- if (React3__default.default.isValidElement(children)) {
330
+ if (React6__default.default.isValidElement(children)) {
282
331
  const child = children;
283
332
  if (child.type === "code" || typeof child.type === "function" && child.type.name === "code") {
284
333
  const codeProps = child.props;
@@ -301,92 +350,28 @@ var createMarkdownComponents = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((isUser
301
350
  return /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { code: codeContent, language, isUser, isCompact });
302
351
  } catch (error) {
303
352
  console.warn("CodeBlock failed, using fallback:", error);
304
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative group my-3", children: [
305
- /* @__PURE__ */ jsxRuntime.jsx(
306
- components.CopyButton,
307
- {
308
- value: codeContent,
309
- variant: "ghost",
310
- className: `
311
- absolute top-2 right-2 z-10 opacity-0 group-hover:opacity-100 transition-opacity
312
- h-8 w-8
313
- ${isUser ? "hover:bg-white/20 text-white" : "hover:bg-muted-foreground/20 text-muted-foreground hover:text-foreground"}
314
- `,
315
- title: "Copy code"
316
- }
317
- ),
318
- /* @__PURE__ */ jsxRuntime.jsx("pre", { className: `
319
- p-3 rounded text-xs font-mono overflow-x-auto
320
- ${isUser ? "bg-white/10 text-white" : "bg-muted text-foreground"}
321
- `, children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: codeContent }) })
322
- ] });
353
+ return /* @__PURE__ */ jsxRuntime.jsx(CodeBlockFallback, { code: codeContent, language, isUser, isCompact });
323
354
  }
324
355
  }, "pre"),
325
- // Inline code
326
356
  code: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children, className }) => {
327
357
  if (className?.includes("language-")) {
328
358
  return /* @__PURE__ */ jsxRuntime.jsx("code", { className, children });
329
359
  }
330
- const codeContent = extractTextFromChildren(children);
331
- return /* @__PURE__ */ jsxRuntime.jsx("code", { className: "px-1.5 py-0.5 rounded text-xs font-mono bg-muted text-foreground break-all", children: codeContent });
360
+ return /* @__PURE__ */ jsxRuntime.jsx("code", { className: "px-1.5 py-0.5 rounded text-xs font-mono bg-muted text-foreground break-all", children: extractTextFromChildren(children) });
332
361
  }, "code"),
333
- // Blockquotes
334
362
  blockquote: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => /* @__PURE__ */ jsxRuntime.jsx("blockquote", { className: `${textSize} border-l-2 border-border pl-3 my-2 italic text-muted-foreground break-words`, children }), "blockquote"),
335
- // Tables - compact for chat
336
363
  table: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto my-3", children: /* @__PURE__ */ jsxRuntime.jsx("table", { className: `min-w-full ${textSize} border-collapse`, children }) }), "table"),
337
364
  thead: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-muted/50", children }), "thead"),
338
365
  tbody: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => /* @__PURE__ */ jsxRuntime.jsx("tbody", { children }), "tbody"),
339
366
  tr: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "border-b border-border/50", children }), "tr"),
340
367
  th: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-2 py-1 text-left font-medium break-words", children }), "th"),
341
368
  td: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-2 py-1 break-words", children }), "td"),
342
- // Horizontal rule
343
369
  hr: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => /* @__PURE__ */ jsxRuntime.jsx("hr", { className: "my-3 border-0 h-px bg-border" }), "hr"),
344
- // Strong and emphasis
345
370
  strong: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => /* @__PURE__ */ jsxRuntime.jsx("strong", { className: "font-semibold", children }), "strong"),
346
371
  em: /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children }) => /* @__PURE__ */ jsxRuntime.jsx("em", { className: "italic", children }), "em")
347
372
  };
348
- }, "createMarkdownComponents");
349
- var hasMarkdownSyntax = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((text) => {
350
- if (text.trim().includes("\n")) {
351
- return true;
352
- }
353
- if (/<\/?[a-zA-Z][a-zA-Z0-9-]*(\s[^>]*)?\/?>/.test(text)) {
354
- return true;
355
- }
356
- const markdownPatterns = [
357
- /^#{1,6}\s/m,
358
- // Headers
359
- /\*\*[^*]+\*\*/,
360
- // Bold
361
- /\*[^*]+\*/,
362
- // Italic
363
- /__[^_]+__/,
364
- // Bold (underscore)
365
- /_[^_]+_/,
366
- // Italic (underscore)
367
- /\[.+\]\(.+\)/,
368
- // Links
369
- /!\[.*\]\(.+\)/,
370
- // Images
371
- /```[\s\S]*```/,
372
- // Code blocks
373
- /`[^`]+`/,
374
- // Inline code
375
- /^\s*[-*+]\s/m,
376
- // Unordered lists
377
- /^\s*\d+\.\s/m,
378
- // Ordered lists
379
- /^\s*>/m,
380
- // Blockquotes
381
- /\|.+\|/,
382
- // Tables
383
- /^---+$/m,
384
- // Horizontal rules
385
- /~~[^~]+~~/
386
- // Strikethrough
387
- ];
388
- return markdownPatterns.some((pattern) => pattern.test(text));
389
- }, "hasMarkdownSyntax");
373
+ }
374
+ chunkWGEGR3DF_cjs.__name(createMarkdownComponents, "createMarkdownComponents");
390
375
  var CollapseToggle = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({
391
376
  isCollapsed,
392
377
  onClick,
@@ -410,48 +395,77 @@ var CollapseToggle = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({
410
395
  `,
411
396
  children: isCollapsed ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
412
397
  readMoreLabel,
413
- /* @__PURE__ */ jsxRuntime.jsx(
414
- "svg",
415
- {
416
- className: "w-3 h-3",
417
- fill: "none",
418
- stroke: "currentColor",
419
- viewBox: "0 0 24 24",
420
- children: /* @__PURE__ */ jsxRuntime.jsx(
421
- "path",
422
- {
423
- strokeLinecap: "round",
424
- strokeLinejoin: "round",
425
- strokeWidth: 2,
426
- d: "M19 9l-7 7-7-7"
427
- }
428
- )
429
- }
430
- )
398
+ /* @__PURE__ */ jsxRuntime.jsx(Chevron, { direction: "down" })
431
399
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
432
400
  showLessLabel,
433
- /* @__PURE__ */ jsxRuntime.jsx(
434
- "svg",
435
- {
436
- className: "w-3 h-3",
437
- fill: "none",
438
- stroke: "currentColor",
439
- viewBox: "0 0 24 24",
440
- children: /* @__PURE__ */ jsxRuntime.jsx(
441
- "path",
442
- {
443
- strokeLinecap: "round",
444
- strokeLinejoin: "round",
445
- strokeWidth: 2,
446
- d: "M5 15l7-7 7 7"
447
- }
448
- )
449
- }
450
- )
401
+ /* @__PURE__ */ jsxRuntime.jsx(Chevron, { direction: "up" })
451
402
  ] })
452
403
  }
453
404
  );
454
405
  }, "CollapseToggle");
406
+ function Chevron({ direction }) {
407
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx(
408
+ "path",
409
+ {
410
+ strokeLinecap: "round",
411
+ strokeLinejoin: "round",
412
+ strokeWidth: 2,
413
+ d: direction === "down" ? "M19 9l-7 7-7-7" : "M5 15l7-7 7 7"
414
+ }
415
+ ) });
416
+ }
417
+ chunkWGEGR3DF_cjs.__name(Chevron, "Chevron");
418
+ function applyPreprocess(source, rules) {
419
+ if (!rules || rules.length === 0) return source;
420
+ let s = source;
421
+ for (const rule of rules) {
422
+ if (!rule.preprocess) continue;
423
+ try {
424
+ s = rule.preprocess(s);
425
+ } catch (err) {
426
+ console.warn(
427
+ `[MarkdownMessage] linkRule "${rule.name ?? "(anonymous)"}" preprocess threw; skipping`,
428
+ err
429
+ );
430
+ }
431
+ }
432
+ return s;
433
+ }
434
+ chunkWGEGR3DF_cjs.__name(applyPreprocess, "applyPreprocess");
435
+ function collectProtocols(extraHrefProtocols, rules) {
436
+ const set = /* @__PURE__ */ new Set();
437
+ if (extraHrefProtocols) for (const p of extraHrefProtocols) set.add(p);
438
+ if (rules) {
439
+ for (const r of rules) {
440
+ if (r.protocols) for (const p of r.protocols) set.add(p);
441
+ }
442
+ }
443
+ return set.size === 0 ? void 0 : Array.from(set);
444
+ }
445
+ chunkWGEGR3DF_cjs.__name(collectProtocols, "collectProtocols");
446
+ function buildLinkRulesComponent(rules, isUser, callerA) {
447
+ const Renderer = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((props) => {
448
+ const { href, children } = props;
449
+ if (typeof href === "string") {
450
+ for (const rule of rules) {
451
+ if (rule.match(href)) {
452
+ return React6__default.default.createElement(
453
+ React6__default.default.Fragment,
454
+ null,
455
+ rule.render({ href, children, isUser })
456
+ );
457
+ }
458
+ }
459
+ }
460
+ if (callerA && typeof callerA === "function") {
461
+ const Caller = callerA;
462
+ return React6__default.default.createElement(Caller, props);
463
+ }
464
+ return React6__default.default.createElement("a", props, children);
465
+ }, "Renderer");
466
+ return Renderer;
467
+ }
468
+ chunkWGEGR3DF_cjs.__name(buildLinkRulesComponent, "buildLinkRulesComponent");
455
469
  var MarkdownMessage = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({
456
470
  content,
457
471
  className = "",
@@ -459,6 +473,7 @@ var MarkdownMessage = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({
459
473
  isCompact = false,
460
474
  customComponents,
461
475
  extraHrefProtocols,
476
+ linkRules,
462
477
  collapsible = false,
463
478
  maxLength,
464
479
  maxLines,
@@ -467,54 +482,71 @@ var MarkdownMessage = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({
467
482
  defaultExpanded = false,
468
483
  onCollapseChange
469
484
  }) => {
470
- const trimmedContent = content.trim();
471
- const collapsibleOptions = React3__default.default.useMemo(() => {
485
+ const preprocessed = React6__default.default.useMemo(
486
+ () => applyPreprocess(content, linkRules),
487
+ [content, linkRules]
488
+ );
489
+ const effectiveProtocols = React6__default.default.useMemo(
490
+ () => collectProtocols(extraHrefProtocols, linkRules),
491
+ [extraHrefProtocols, linkRules]
492
+ );
493
+ const effectiveCustomComponents = React6__default.default.useMemo(() => {
494
+ if (!linkRules || linkRules.length === 0) return customComponents;
495
+ const callerA = customComponents?.a;
496
+ const aRenderer = buildLinkRulesComponent(linkRules, isUser, callerA);
497
+ return { ...customComponents ?? {}, a: aRenderer };
498
+ }, [customComponents, linkRules, isUser]);
499
+ const trimmedContent = preprocessed.trim();
500
+ const collapsibleOptions = React6__default.default.useMemo(() => {
472
501
  if (!collapsible) return {};
473
- const effectiveMaxLength = maxLength ?? 1e3;
474
- const effectiveMaxLines = maxLines ?? 10;
475
- return { maxLength: effectiveMaxLength, maxLines: effectiveMaxLines, defaultExpanded };
502
+ return {
503
+ maxLength: maxLength ?? 1e3,
504
+ maxLines: maxLines ?? 10,
505
+ defaultExpanded
506
+ };
476
507
  }, [collapsible, maxLength, maxLines, defaultExpanded]);
477
- const {
478
- isCollapsed,
479
- toggleCollapsed,
480
- displayContent,
481
- shouldCollapse
482
- } = useCollapsibleContent(
483
- trimmedContent,
484
- collapsible ? collapsibleOptions : {}
485
- );
486
- React3__default.default.useEffect(() => {
508
+ const { isCollapsed, toggleCollapsed, displayContent, shouldCollapse } = useCollapsibleContent(trimmedContent, collapsible ? collapsibleOptions : {});
509
+ React6__default.default.useEffect(() => {
487
510
  if (collapsible && shouldCollapse && onCollapseChange) {
488
511
  onCollapseChange(isCollapsed);
489
512
  }
490
513
  }, [isCollapsed, collapsible, shouldCollapse, onCollapseChange]);
491
- const components = React3__default.default.useMemo(() => {
514
+ const components = React6__default.default.useMemo(() => {
492
515
  const base = createMarkdownComponents(isUser, isCompact);
493
- return customComponents ? { ...base, ...customComponents } : base;
494
- }, [isUser, isCompact, customComponents]);
495
- const schema = React3__default.default.useMemo(() => buildSchema(extraHrefProtocols), [extraHrefProtocols]);
496
- const urlTransform = React3__default.default.useMemo(() => buildUrlTransform(extraHrefProtocols), [extraHrefProtocols]);
516
+ return effectiveCustomComponents ? { ...base, ...effectiveCustomComponents } : base;
517
+ }, [isUser, isCompact, effectiveCustomComponents]);
518
+ const schema = React6__default.default.useMemo(() => buildSchema(effectiveProtocols), [effectiveProtocols]);
519
+ const urlTransform = React6__default.default.useMemo(
520
+ () => buildUrlTransform(effectiveProtocols),
521
+ [effectiveProtocols]
522
+ );
497
523
  const textSizeClass = isCompact ? "text-xs" : "text-sm";
498
524
  const proseClass = isCompact ? "prose-xs" : "prose-sm";
499
- const isPlainText = !customComponents && !hasMarkdownSyntax(displayContent);
525
+ const isPlainText = !effectiveCustomComponents && !hasMarkdownSyntax(displayContent);
500
526
  if (isPlainText) {
501
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `${textSizeClass} leading-7 break-words whitespace-pre-line font-light ${className}`, children: [
502
- displayContent,
503
- collapsible && shouldCollapse && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
504
- isCollapsed && "... ",
505
- /* @__PURE__ */ jsxRuntime.jsx(
506
- CollapseToggle,
507
- {
508
- isCollapsed,
509
- onClick: toggleCollapsed,
510
- readMoreLabel,
511
- showLessLabel,
512
- isUser,
513
- isCompact
514
- }
515
- )
516
- ] })
517
- ] });
527
+ return /* @__PURE__ */ jsxRuntime.jsxs(
528
+ "span",
529
+ {
530
+ className: `${textSizeClass} leading-7 break-words whitespace-pre-line font-light ${className}`,
531
+ children: [
532
+ displayContent,
533
+ collapsible && shouldCollapse && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
534
+ isCollapsed && "... ",
535
+ /* @__PURE__ */ jsxRuntime.jsx(
536
+ CollapseToggle,
537
+ {
538
+ isCollapsed,
539
+ onClick: toggleCollapsed,
540
+ readMoreLabel,
541
+ showLessLabel,
542
+ isUser,
543
+ isCompact
544
+ }
545
+ )
546
+ ] })
547
+ ]
548
+ }
549
+ );
518
550
  }
519
551
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
520
552
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -526,7 +558,8 @@ var MarkdownMessage = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({
526
558
  [&>*]:leading-7
527
559
  `,
528
560
  style: {
529
- // Inherit colors from parent - fixes issues with external CSS variables
561
+ // Inherit colors from parent fixes issues with external
562
+ // CSS variables overriding prose tokens.
530
563
  "--tw-prose-body": "inherit",
531
564
  "--tw-prose-headings": "inherit",
532
565
  "--tw-prose-bold": "inherit",
@@ -1303,16 +1336,16 @@ function reducer(state, action) {
1303
1336
  }
1304
1337
  }
1305
1338
  chunkWGEGR3DF_cjs.__name(reducer, "reducer");
1306
- var PlaygroundContext = React3.createContext(void 0);
1339
+ var PlaygroundContext = React6.createContext(void 0);
1307
1340
  var usePlaygroundContext = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => {
1308
- const context = React3.useContext(PlaygroundContext);
1341
+ const context = React6.useContext(PlaygroundContext);
1309
1342
  if (!context) throw new Error("usePlaygroundContext must be used within a PlaygroundProvider");
1310
1343
  return context;
1311
1344
  }, "usePlaygroundContext");
1312
1345
  var PlaygroundProvider = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children, config }) => {
1313
- const [state, dispatch] = React3.useReducer(reducer, void 0, createInitialState);
1314
- const abortControllerRef = React3.useRef(null);
1315
- const apiKeys = React3__default.default.useMemo(
1346
+ const [state, dispatch] = React6.useReducer(reducer, void 0, createInitialState);
1347
+ const abortControllerRef = React6.useRef(null);
1348
+ const apiKeys = React6__default.default.useMemo(
1316
1349
  () => config.apiKeys ?? [],
1317
1350
  [config.apiKeys]
1318
1351
  );
@@ -1325,28 +1358,28 @@ var PlaygroundProvider = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children, c
1325
1358
  AUTH_BEARER_STORAGE,
1326
1359
  ""
1327
1360
  );
1328
- const hasHydratedAuthRef = React3.useRef(false);
1329
- React3.useEffect(() => {
1361
+ const hasHydratedAuthRef = React6.useRef(false);
1362
+ React6.useEffect(() => {
1330
1363
  if (hasHydratedAuthRef.current) return;
1331
1364
  hasHydratedAuthRef.current = true;
1332
1365
  if (storedApiKeyId) dispatch({ type: "SET_API_KEY", apiKeyId: storedApiKeyId });
1333
1366
  if (storedBearer) dispatch({ type: "SET_MANUAL_TOKEN", token: storedBearer });
1334
1367
  }, []);
1335
- React3.useEffect(() => {
1368
+ React6.useEffect(() => {
1336
1369
  if (!hasHydratedAuthRef.current) return;
1337
1370
  setStoredApiKeyId(state.selectedApiKey);
1338
1371
  }, [state.selectedApiKey, setStoredApiKeyId]);
1339
- React3.useEffect(() => {
1372
+ React6.useEffect(() => {
1340
1373
  if (!hasHydratedAuthRef.current) return;
1341
1374
  setStoredBearer(state.manualApiToken);
1342
1375
  }, [state.manualApiToken, setStoredBearer]);
1343
- React3.useEffect(() => {
1376
+ React6.useEffect(() => {
1344
1377
  if (!hasHydratedAuthRef.current) return;
1345
1378
  if (!isLoadingApiKeys && apiKeys.length > 0 && !state.selectedApiKey && !storedApiKeyId) {
1346
1379
  dispatch({ type: "SET_API_KEY", apiKeyId: apiKeys[0]?.id || null });
1347
1380
  }
1348
1381
  }, [apiKeys, isLoadingApiKeys, state.selectedApiKey, storedApiKeyId]);
1349
- React3.useEffect(() => {
1382
+ React6.useEffect(() => {
1350
1383
  try {
1351
1384
  const headers = parseRequestHeaders(state.requestHeaders);
1352
1385
  if (state.selectedApiKey) {
@@ -1368,33 +1401,33 @@ var PlaygroundProvider = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ children, c
1368
1401
  consola2__default.default.error("Error updating headers:", error);
1369
1402
  }
1370
1403
  }, [state.selectedApiKey, apiKeys]);
1371
- React3.useEffect(() => {
1404
+ React6.useEffect(() => {
1372
1405
  if (!state.selectedEndpoint) return;
1373
1406
  const updated = new UrlBuilder(state.selectedEndpoint, state.parameters).build();
1374
1407
  if (updated !== state.requestUrl) {
1375
1408
  dispatch({ type: "SYNC_URL", url: updated });
1376
1409
  }
1377
1410
  }, [state.parameters, state.selectedEndpoint]);
1378
- const setCurrentStep = React3.useCallback((step) => dispatch({ type: "SET_STEP", step }), []);
1379
- const goToNextStep = React3.useCallback(() => dispatch({ type: "NEXT_STEP" }), []);
1380
- const goToPreviousStep = React3.useCallback(() => dispatch({ type: "PREV_STEP" }), []);
1381
- const setSelectedEndpoint = React3.useCallback((endpoint) => dispatch({ type: "SELECT_ENDPOINT", endpoint }), []);
1382
- const setSelectedCategory = React3.useCallback((category) => dispatch({ type: "SET_CATEGORY", category }), []);
1383
- const setSearchTerm = React3.useCallback((term) => dispatch({ type: "SET_SEARCH", term }), []);
1384
- const setSelectedVersion = React3.useCallback((version) => dispatch({ type: "SET_VERSION", version }), []);
1385
- const setRequestUrl = React3.useCallback((url) => dispatch({ type: "SET_REQUEST_URL", url }), []);
1386
- const setRequestMethod = React3.useCallback((method) => dispatch({ type: "SET_REQUEST_METHOD", method }), []);
1387
- const setRequestHeaders = React3.useCallback((headers) => dispatch({ type: "SET_REQUEST_HEADERS", headers }), []);
1388
- const setRequestBody = React3.useCallback((body) => dispatch({ type: "SET_REQUEST_BODY", body }), []);
1389
- const setSelectedApiKey = React3.useCallback((apiKeyId) => dispatch({ type: "SET_API_KEY", apiKeyId }), []);
1390
- const setManualApiToken = React3.useCallback((token) => dispatch({ type: "SET_MANUAL_TOKEN", token }), []);
1391
- const setParameters = React3.useCallback((parameters) => dispatch({ type: "SET_PARAMETERS", parameters }), []);
1392
- const setResponse = React3.useCallback((response) => dispatch({ type: "SET_RESPONSE", response }), []);
1393
- const setLoading = React3.useCallback((loading) => dispatch({ type: "SET_LOADING", loading }), []);
1394
- const setSidebarOpen = React3.useCallback((open) => dispatch({ type: "SET_SIDEBAR", open }), []);
1395
- const setActiveSchemaId = React3.useCallback((id) => dispatch({ type: "SET_ACTIVE_SCHEMA_ID", id }), []);
1396
- const clearAll = React3.useCallback(() => dispatch({ type: "RESET" }), []);
1397
- const sendRequest = React3.useCallback(async () => {
1411
+ const setCurrentStep = React6.useCallback((step) => dispatch({ type: "SET_STEP", step }), []);
1412
+ const goToNextStep = React6.useCallback(() => dispatch({ type: "NEXT_STEP" }), []);
1413
+ const goToPreviousStep = React6.useCallback(() => dispatch({ type: "PREV_STEP" }), []);
1414
+ const setSelectedEndpoint = React6.useCallback((endpoint) => dispatch({ type: "SELECT_ENDPOINT", endpoint }), []);
1415
+ const setSelectedCategory = React6.useCallback((category) => dispatch({ type: "SET_CATEGORY", category }), []);
1416
+ const setSearchTerm = React6.useCallback((term) => dispatch({ type: "SET_SEARCH", term }), []);
1417
+ const setSelectedVersion = React6.useCallback((version) => dispatch({ type: "SET_VERSION", version }), []);
1418
+ const setRequestUrl = React6.useCallback((url) => dispatch({ type: "SET_REQUEST_URL", url }), []);
1419
+ const setRequestMethod = React6.useCallback((method) => dispatch({ type: "SET_REQUEST_METHOD", method }), []);
1420
+ const setRequestHeaders = React6.useCallback((headers) => dispatch({ type: "SET_REQUEST_HEADERS", headers }), []);
1421
+ const setRequestBody = React6.useCallback((body) => dispatch({ type: "SET_REQUEST_BODY", body }), []);
1422
+ const setSelectedApiKey = React6.useCallback((apiKeyId) => dispatch({ type: "SET_API_KEY", apiKeyId }), []);
1423
+ const setManualApiToken = React6.useCallback((token) => dispatch({ type: "SET_MANUAL_TOKEN", token }), []);
1424
+ const setParameters = React6.useCallback((parameters) => dispatch({ type: "SET_PARAMETERS", parameters }), []);
1425
+ const setResponse = React6.useCallback((response) => dispatch({ type: "SET_RESPONSE", response }), []);
1426
+ const setLoading = React6.useCallback((loading) => dispatch({ type: "SET_LOADING", loading }), []);
1427
+ const setSidebarOpen = React6.useCallback((open) => dispatch({ type: "SET_SIDEBAR", open }), []);
1428
+ const setActiveSchemaId = React6.useCallback((id) => dispatch({ type: "SET_ACTIVE_SCHEMA_ID", id }), []);
1429
+ const clearAll = React6.useCallback(() => dispatch({ type: "RESET" }), []);
1430
+ const sendRequest = React6.useCallback(async () => {
1398
1431
  if (!state.requestUrl) {
1399
1432
  consola2__default.default.error("No URL provided");
1400
1433
  return;
@@ -1492,6 +1525,7 @@ exports.buildHarRequest = buildHarRequest;
1492
1525
  exports.deduplicateEndpoints = deduplicateEndpoints;
1493
1526
  exports.dereferenceSchema = dereferenceSchema;
1494
1527
  exports.endpointToMarkdown = endpointToMarkdown;
1528
+ exports.extractTextFromChildren = extractTextFromChildren;
1495
1529
  exports.findApiKeyById = findApiKeyById;
1496
1530
  exports.formatBytes = formatBytes;
1497
1531
  exports.isValidJson = isValidJson;
@@ -1507,5 +1541,5 @@ exports.toMarkdown = toMarkdown;
1507
1541
  exports.toRawJson = toRawJson;
1508
1542
  exports.useCollapsibleContent = useCollapsibleContent;
1509
1543
  exports.usePlaygroundContext = usePlaygroundContext;
1510
- //# sourceMappingURL=chunk-Q6FNLXLZ.cjs.map
1511
- //# sourceMappingURL=chunk-Q6FNLXLZ.cjs.map
1544
+ //# sourceMappingURL=chunk-SEXWBCLX.cjs.map
1545
+ //# sourceMappingURL=chunk-SEXWBCLX.cjs.map