@assistant-ui/react-markdown 0.2.22 → 0.2.24

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 (92) hide show
  1. package/dist/index.d.ts +6 -45
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +8 -307
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +7 -293
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/overrides/CodeBlock.d.ts +14 -0
  8. package/dist/overrides/CodeBlock.d.ts.map +1 -0
  9. package/dist/overrides/CodeBlock.js +50 -0
  10. package/dist/overrides/CodeBlock.js.map +1 -0
  11. package/dist/overrides/CodeBlock.mjs +26 -0
  12. package/dist/overrides/CodeBlock.mjs.map +1 -0
  13. package/dist/overrides/CodeOverride.d.ts +16 -0
  14. package/dist/overrides/CodeOverride.d.ts.map +1 -0
  15. package/dist/overrides/CodeOverride.js +85 -0
  16. package/dist/overrides/CodeOverride.js.map +1 -0
  17. package/dist/overrides/CodeOverride.mjs +61 -0
  18. package/dist/overrides/CodeOverride.mjs.map +1 -0
  19. package/dist/overrides/PreOverride.d.ts +6 -0
  20. package/dist/overrides/PreOverride.d.ts.map +1 -0
  21. package/dist/overrides/PreOverride.js +41 -0
  22. package/dist/overrides/PreOverride.js.map +1 -0
  23. package/dist/overrides/PreOverride.mjs +15 -0
  24. package/dist/overrides/PreOverride.mjs.map +1 -0
  25. package/dist/overrides/defaultComponents.d.ts +13 -0
  26. package/dist/overrides/defaultComponents.d.ts.map +1 -0
  27. package/dist/overrides/defaultComponents.js +39 -0
  28. package/dist/overrides/defaultComponents.js.map +1 -0
  29. package/dist/overrides/defaultComponents.mjs +12 -0
  30. package/dist/overrides/defaultComponents.mjs.map +1 -0
  31. package/dist/overrides/types.d.ts +16 -0
  32. package/dist/overrides/types.d.ts.map +1 -0
  33. package/dist/overrides/types.js +17 -0
  34. package/dist/overrides/types.js.map +1 -0
  35. package/dist/overrides/types.mjs +1 -0
  36. package/dist/overrides/types.mjs.map +1 -0
  37. package/dist/overrides/withDefaults.d.ts +4 -0
  38. package/dist/overrides/withDefaults.d.ts.map +1 -0
  39. package/dist/overrides/withDefaults.js +49 -0
  40. package/dist/overrides/withDefaults.js.map +1 -0
  41. package/dist/overrides/withDefaults.mjs +15 -0
  42. package/dist/overrides/withDefaults.mjs.map +1 -0
  43. package/dist/primitives/MarkdownText.d.ts +22 -0
  44. package/dist/primitives/MarkdownText.d.ts.map +1 -0
  45. package/dist/primitives/MarkdownText.js +96 -0
  46. package/dist/primitives/MarkdownText.js.map +1 -0
  47. package/dist/primitives/MarkdownText.mjs +69 -0
  48. package/dist/primitives/MarkdownText.mjs.map +1 -0
  49. package/dist/styles/markdown.css +1 -0
  50. package/dist/styles/markdown.css.map +1 -0
  51. package/dist/tailwindcss/index.d.ts +4 -6
  52. package/dist/tailwindcss/index.d.ts.map +1 -0
  53. package/dist/tailwindcss/index.js +3 -76
  54. package/dist/tailwindcss/index.js.map +1 -1
  55. package/dist/tailwindcss/index.mjs +3 -75
  56. package/dist/tailwindcss/index.mjs.map +1 -1
  57. package/dist/ui/code-header.d.ts +4 -0
  58. package/dist/ui/code-header.d.ts.map +1 -0
  59. package/dist/ui/code-header.js +52 -0
  60. package/dist/ui/code-header.js.map +1 -0
  61. package/dist/ui/code-header.mjs +28 -0
  62. package/dist/ui/code-header.mjs.map +1 -0
  63. package/dist/ui/markdown-text.d.ts +4 -0
  64. package/dist/ui/markdown-text.d.ts.map +1 -0
  65. package/dist/ui/markdown-text.js +112 -0
  66. package/dist/ui/markdown-text.js.map +1 -0
  67. package/dist/ui/markdown-text.mjs +80 -0
  68. package/dist/ui/markdown-text.mjs.map +1 -0
  69. package/dist/ui/useCopyToClipboard.d.ts +7 -0
  70. package/dist/ui/useCopyToClipboard.d.ts.map +1 -0
  71. package/dist/ui/useCopyToClipboard.js +42 -0
  72. package/dist/ui/useCopyToClipboard.js.map +1 -0
  73. package/dist/ui/useCopyToClipboard.mjs +18 -0
  74. package/dist/ui/useCopyToClipboard.mjs.map +1 -0
  75. package/package.json +15 -21
  76. package/src/index.ts +18 -0
  77. package/src/overrides/CodeBlock.tsx +41 -0
  78. package/src/overrides/CodeOverride.tsx +91 -0
  79. package/src/overrides/PreOverride.tsx +15 -0
  80. package/src/overrides/defaultComponents.tsx +21 -0
  81. package/src/overrides/types.ts +22 -0
  82. package/src/overrides/withDefaults.tsx +14 -0
  83. package/src/primitives/MarkdownText.tsx +110 -0
  84. package/src/styles/tailwindcss/markdown.css +106 -0
  85. package/src/tailwindcss/index.ts +8 -0
  86. package/src/ui/code-header.tsx +32 -0
  87. package/src/ui/markdown-text.tsx +114 -0
  88. package/src/ui/useCopyToClipboard.tsx +21 -0
  89. package/tailwindcss/README.md +1 -0
  90. package/tailwindcss/package.json +5 -0
  91. package/dist/index.d.mts +0 -45
  92. package/dist/tailwindcss/index.d.mts +0 -11
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/ui/useCopyToClipboard.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { UseActionBarCopyProps } from \"@assistant-ui/react\";\n\nexport type useCopyToClipboardProps = UseActionBarCopyProps;\n\nexport const useCopyToClipboard = ({\n copiedDuration = 3000,\n}: useCopyToClipboardProps = {}) => {\n const [isCopied, setIsCopied] = useState<boolean>(false);\n\n const copyToClipboard = (value: string) => {\n if (!value) return;\n\n navigator.clipboard.writeText(value).then(() => {\n setIsCopied(true);\n setTimeout(() => setIsCopied(false), copiedDuration);\n });\n };\n\n return { isCopied, copyToClipboard };\n};\n"],"mappings":"AAAA,SAAS,gBAAgB;AAKlB,MAAM,qBAAqB,CAAC;AAAA,EACjC,iBAAiB;AACnB,IAA6B,CAAC,MAAM;AAClC,QAAM,CAAC,UAAU,WAAW,IAAI,SAAkB,KAAK;AAEvD,QAAM,kBAAkB,CAAC,UAAkB;AACzC,QAAI,CAAC,MAAO;AAEZ,cAAU,UAAU,UAAU,KAAK,EAAE,KAAK,MAAM;AAC9C,kBAAY,IAAI;AAChB,iBAAW,MAAM,YAAY,KAAK,GAAG,cAAc;AAAA,IACrD,CAAC;AAAA,EACH;AAEA,SAAO,EAAE,UAAU,gBAAgB;AACrC;","names":[]}
package/package.json CHANGED
@@ -1,27 +1,17 @@
1
1
  {
2
2
  "name": "@assistant-ui/react-markdown",
3
- "version": "0.2.22",
3
+ "version": "0.2.24",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": {
7
- "import": {
8
- "types": "./dist/index.d.mts",
9
- "default": "./dist/index.mjs"
10
- },
11
- "require": {
12
- "types": "./dist/index.d.ts",
13
- "default": "./dist/index.js"
14
- }
7
+ "types": "./dist/index.d.ts",
8
+ "import": "./dist/index.mjs",
9
+ "require": "./dist/index.js"
15
10
  },
16
11
  "./tailwindcss": {
17
- "import": {
18
- "types": "./dist/tailwindcss/index.d.mts",
19
- "default": "./dist/tailwindcss/index.mjs"
20
- },
21
- "require": {
22
- "types": "./dist/tailwindcss/index.d.ts",
23
- "default": "./dist/tailwindcss/index.js"
24
- }
12
+ "types": "./dist/tailwindcss/index.d.ts",
13
+ "import": "./dist/tailwindcss/index.mjs",
14
+ "require": "./dist/tailwindcss/index.js"
25
15
  },
26
16
  "./styles/*": {
27
17
  "default": "./dist/styles/*"
@@ -33,6 +23,8 @@
33
23
  "types": "./dist/index.d.ts",
34
24
  "files": [
35
25
  "dist",
26
+ "tailwindcss",
27
+ "src",
36
28
  "README.md"
37
29
  ],
38
30
  "sideEffects": false,
@@ -44,7 +36,7 @@
44
36
  "react-markdown": "^9.0.1"
45
37
  },
46
38
  "peerDependencies": {
47
- "@assistant-ui/react": "^0.5.91",
39
+ "@assistant-ui/react": "^0.5.93",
48
40
  "@types/react": "*",
49
41
  "react": "^18 || ^19",
50
42
  "tailwindcss": "^3.4.4"
@@ -70,8 +62,9 @@
70
62
  "tailwindcss-animate": "^1.0.7",
71
63
  "tsup": "8.3.0",
72
64
  "tsx": "^4.19.1",
73
- "@assistant-ui/tailwindcss-transformer": "0.1.0",
74
- "@assistant-ui/tsconfig": "0.0.0"
65
+ "@assistant-ui/react": "0.5.93",
66
+ "@assistant-ui/tsconfig": "0.0.0",
67
+ "@assistant-ui/tailwindcss-transformer": "0.1.0"
75
68
  },
76
69
  "publishConfig": {
77
70
  "access": "public",
@@ -86,6 +79,7 @@
86
79
  "url": "https://github.com/Yonom/assistant-ui/issues"
87
80
  },
88
81
  "scripts": {
89
- "build": "tsx scripts/build.mts"
82
+ "build": "tsx scripts/build.mts && pnpm run build:declarations",
83
+ "build:declarations": "tsc -p tsconfig.declarations.json"
90
84
  }
91
85
  }
package/src/index.ts ADDED
@@ -0,0 +1,18 @@
1
+ export {
2
+ MarkdownTextPrimitive,
3
+ type MarkdownTextPrimitiveProps,
4
+ } from "./primitives/MarkdownText";
5
+
6
+ export type {
7
+ CodeHeaderProps,
8
+ SyntaxHighlighterProps,
9
+ } from "./overrides/types";
10
+
11
+ export { useIsMarkdownCodeBlock } from "./overrides/PreOverride";
12
+
13
+ export {
14
+ makeMarkdownText,
15
+ type MakeMarkdownTextProps,
16
+ } from "./ui/markdown-text";
17
+
18
+ export { CodeHeader } from "./ui/code-header";
@@ -0,0 +1,41 @@
1
+ import { ComponentType, FC, useMemo } from "react";
2
+
3
+ import {
4
+ CodeComponent,
5
+ CodeHeaderProps,
6
+ PreComponent,
7
+ SyntaxHighlighterProps,
8
+ } from "./types";
9
+ import { DefaultCodeBlockContent } from "./defaultComponents";
10
+
11
+ export type CodeBlockProps = {
12
+ language: string;
13
+ code: string;
14
+ components: {
15
+ Pre: PreComponent;
16
+ Code: CodeComponent;
17
+ CodeHeader: ComponentType<CodeHeaderProps>;
18
+ SyntaxHighlighter: ComponentType<SyntaxHighlighterProps>;
19
+ };
20
+ };
21
+
22
+ export const DefaultCodeBlock: FC<CodeBlockProps> = ({
23
+ components: { Pre, Code, SyntaxHighlighter, CodeHeader },
24
+ language,
25
+ code,
26
+ }) => {
27
+ const components = useMemo(() => ({ Pre, Code }), [Pre, Code]);
28
+
29
+ const SH = !!language ? SyntaxHighlighter : DefaultCodeBlockContent;
30
+
31
+ return (
32
+ <>
33
+ <CodeHeader language={language} code={code} />
34
+ <SH
35
+ components={components}
36
+ language={language ?? "unknown"}
37
+ code={code}
38
+ />
39
+ </>
40
+ );
41
+ };
@@ -0,0 +1,91 @@
1
+ import { ComponentPropsWithoutRef, ComponentType, FC, useContext } from "react";
2
+ import { PreContext } from "./PreOverride";
3
+ import {
4
+ CodeComponent,
5
+ CodeHeaderProps,
6
+ PreComponent,
7
+ SyntaxHighlighterProps,
8
+ } from "./types";
9
+ import { DefaultCodeBlock } from "./CodeBlock";
10
+ import { useCallbackRef } from "@radix-ui/react-use-callback-ref";
11
+ import { withDefaultProps } from "./withDefaults";
12
+ import { DefaultCodeBlockContent } from "./defaultComponents";
13
+
14
+ const CodeBlockOverride: FC<CodeOverrideProps> = ({
15
+ components: {
16
+ Pre,
17
+ Code,
18
+ SyntaxHighlighter: FallbackSyntaxHighlighter,
19
+ CodeHeader: FallbackCodeHeader,
20
+ by_language = {},
21
+ },
22
+ children,
23
+ ...codeProps
24
+ }) => {
25
+ const preProps = useContext(PreContext)!;
26
+ const getPreProps = withDefaultProps<any>(preProps);
27
+ const WrappedPre: PreComponent = useCallbackRef((props) => (
28
+ <Pre {...getPreProps(props)} />
29
+ ));
30
+
31
+ const getCodeProps = withDefaultProps<any>(codeProps);
32
+ const WrappedCode: CodeComponent = useCallbackRef((props) => (
33
+ <Code {...getCodeProps(props)} />
34
+ ));
35
+
36
+ const language = /language-(\w+)/.exec(codeProps.className || "")?.[1] ?? "";
37
+
38
+ // if the code content is not string (due to rehype plugins), return a default code block
39
+ if (typeof children !== "string") {
40
+ return (
41
+ <DefaultCodeBlockContent
42
+ components={{ Pre: WrappedPre, Code: WrappedCode }}
43
+ code={children}
44
+ />
45
+ );
46
+ }
47
+
48
+ const SyntaxHighlighter: ComponentType<SyntaxHighlighterProps> =
49
+ by_language[language]?.SyntaxHighlighter ?? FallbackSyntaxHighlighter;
50
+
51
+ const CodeHeader: ComponentType<CodeHeaderProps> =
52
+ by_language[language]?.CodeHeader ?? FallbackCodeHeader;
53
+
54
+ return (
55
+ <DefaultCodeBlock
56
+ components={{
57
+ Pre: WrappedPre,
58
+ Code: WrappedCode,
59
+ SyntaxHighlighter,
60
+ CodeHeader,
61
+ }}
62
+ language={language || "unknown"}
63
+ code={children}
64
+ />
65
+ );
66
+ };
67
+
68
+ export type CodeOverrideProps = ComponentPropsWithoutRef<CodeComponent> & {
69
+ components: {
70
+ Pre: PreComponent;
71
+ Code: CodeComponent;
72
+ CodeHeader: ComponentType<CodeHeaderProps>;
73
+ SyntaxHighlighter: ComponentType<SyntaxHighlighterProps>;
74
+ by_language?: Record<
75
+ string,
76
+ {
77
+ CodeHeader?: ComponentType<CodeHeaderProps>;
78
+ SyntaxHighlighter?: ComponentType<SyntaxHighlighterProps>;
79
+ }
80
+ >;
81
+ };
82
+ };
83
+
84
+ export const CodeOverride: FC<CodeOverrideProps> = ({
85
+ components,
86
+ ...props
87
+ }) => {
88
+ const preProps = useContext(PreContext);
89
+ if (!preProps) return <components.Code {...(props as any)} />;
90
+ return <CodeBlockOverride components={components} {...props} />;
91
+ };
@@ -0,0 +1,15 @@
1
+ import { createContext, ComponentPropsWithoutRef, useContext } from "react";
2
+ import { PreComponent } from "./types";
3
+
4
+ export const PreContext = createContext<Omit<
5
+ ComponentPropsWithoutRef<PreComponent>,
6
+ "children"
7
+ > | null>(null);
8
+
9
+ export const useIsMarkdownCodeBlock = () => {
10
+ return useContext(PreContext) !== null;
11
+ };
12
+
13
+ export const PreOverride: PreComponent = ({ children, ...rest }) => {
14
+ return <PreContext.Provider value={rest}>{children}</PreContext.Provider>;
15
+ };
@@ -0,0 +1,21 @@
1
+ import type { ComponentType, ReactNode } from "react";
2
+ import { PreComponent, CodeComponent, CodeHeaderProps } from "./types";
3
+
4
+ export const DefaultPre: PreComponent = ({ node, ...rest }) => (
5
+ <pre {...rest} />
6
+ );
7
+
8
+ export const DefaultCode: CodeComponent = ({ node, ...rest }) => (
9
+ <code {...rest} />
10
+ );
11
+
12
+ export const DefaultCodeBlockContent: ComponentType<{
13
+ components: { Pre: PreComponent; Code: CodeComponent };
14
+ code: string | ReactNode | undefined;
15
+ }> = ({ components: { Pre, Code }, code }) => (
16
+ <Pre>
17
+ <Code>{code}</Code>
18
+ </Pre>
19
+ );
20
+
21
+ export const DefaultCodeHeader: ComponentType<CodeHeaderProps> = () => null;
@@ -0,0 +1,22 @@
1
+ import { Options } from "react-markdown";
2
+
3
+ export type PreComponent = NonNullable<
4
+ NonNullable<Options["components"]>["pre"]
5
+ >;
6
+ export type CodeComponent = NonNullable<
7
+ NonNullable<Options["components"]>["code"]
8
+ >;
9
+
10
+ export type CodeHeaderProps = {
11
+ language: string | undefined;
12
+ code: string;
13
+ };
14
+
15
+ export type SyntaxHighlighterProps = {
16
+ components: {
17
+ Pre: PreComponent;
18
+ Code: CodeComponent;
19
+ };
20
+ language: string;
21
+ code: string;
22
+ };
@@ -0,0 +1,14 @@
1
+ import classNames from "classnames";
2
+
3
+ export const withDefaultProps =
4
+ <TProps extends { className?: string | undefined }>({
5
+ className,
6
+ ...defaultProps
7
+ }: Partial<TProps>) =>
8
+ ({ className: classNameProp, ...props }: TProps) => {
9
+ return {
10
+ className: classNames(className, classNameProp),
11
+ ...defaultProps,
12
+ ...props,
13
+ } as TProps;
14
+ };
@@ -0,0 +1,110 @@
1
+ "use client";
2
+
3
+ import { INTERNAL, useContentPartText } from "@assistant-ui/react";
4
+ import {
5
+ ElementRef,
6
+ ElementType,
7
+ forwardRef,
8
+ ForwardRefExoticComponent,
9
+ RefAttributes,
10
+ type ComponentPropsWithoutRef,
11
+ type ComponentType,
12
+ } from "react";
13
+ import ReactMarkdown, { type Options } from "react-markdown";
14
+ import { SyntaxHighlighterProps, CodeHeaderProps } from "../overrides/types";
15
+ import { PreOverride } from "../overrides/PreOverride";
16
+ import {
17
+ DefaultPre,
18
+ DefaultCode,
19
+ DefaultCodeBlockContent,
20
+ DefaultCodeHeader,
21
+ } from "../overrides/defaultComponents";
22
+ import { useCallbackRef } from "@radix-ui/react-use-callback-ref";
23
+ import { CodeOverride } from "../overrides/CodeOverride";
24
+ import { Primitive } from "@radix-ui/react-primitive";
25
+ import classNames from "classnames";
26
+
27
+ const { useSmooth } = INTERNAL;
28
+
29
+ type MarkdownTextPrimitiveElement = ElementRef<typeof Primitive.div>;
30
+ type PrimitiveDivProps = ComponentPropsWithoutRef<typeof Primitive.div>;
31
+
32
+ export type MarkdownTextPrimitiveProps = Omit<
33
+ Options,
34
+ "components" | "children"
35
+ > & {
36
+ containerProps?: Omit<PrimitiveDivProps, "children" | "asChild">;
37
+ containerComponent?: ElementType;
38
+ components?: NonNullable<Options["components"]> & {
39
+ SyntaxHighlighter?: ComponentType<SyntaxHighlighterProps>;
40
+ CodeHeader?: ComponentType<CodeHeaderProps>;
41
+ by_language?: Record<
42
+ string,
43
+ {
44
+ CodeHeader?: ComponentType<CodeHeaderProps>;
45
+ SyntaxHighlighter?: ComponentType<SyntaxHighlighterProps>;
46
+ }
47
+ >;
48
+ };
49
+ smooth?: boolean;
50
+ };
51
+
52
+ export const MarkdownTextPrimitive: ForwardRefExoticComponent<MarkdownTextPrimitiveProps> &
53
+ RefAttributes<MarkdownTextPrimitiveElement> = forwardRef<
54
+ MarkdownTextPrimitiveElement,
55
+ MarkdownTextPrimitiveProps
56
+ >(
57
+ (
58
+ {
59
+ components: userComponents,
60
+ className,
61
+ containerProps,
62
+ containerComponent: Container = "div",
63
+ ...rest
64
+ },
65
+ forwardedRef,
66
+ smooth = true,
67
+ ) => {
68
+ const { text, status } = useSmooth(useContentPartText(), smooth);
69
+
70
+ const {
71
+ pre = DefaultPre,
72
+ code = DefaultCode,
73
+ SyntaxHighlighter = DefaultCodeBlockContent,
74
+ CodeHeader = DefaultCodeHeader,
75
+ by_language,
76
+ ...componentsRest
77
+ } = userComponents ?? {};
78
+ const components: typeof userComponents = {
79
+ ...componentsRest,
80
+ pre: PreOverride,
81
+ code: useCallbackRef((props) => (
82
+ <CodeOverride
83
+ components={{
84
+ Pre: pre,
85
+ Code: code,
86
+ SyntaxHighlighter,
87
+ CodeHeader,
88
+ by_language,
89
+ }}
90
+ {...props}
91
+ />
92
+ )),
93
+ };
94
+
95
+ return (
96
+ <Container
97
+ data-status={status.type}
98
+ {...containerProps}
99
+ className={classNames(className, containerProps?.className)}
100
+ ref={forwardedRef}
101
+ >
102
+ <ReactMarkdown components={components} {...rest}>
103
+ {text}
104
+ </ReactMarkdown>
105
+ </Container>
106
+ );
107
+ },
108
+ );
109
+
110
+ MarkdownTextPrimitive.displayName = "MarkdownTextPrimitive";
@@ -0,0 +1,106 @@
1
+ /* running indicator */
2
+ :where(.aui-md-running):empty::after,
3
+ :where(.aui-md-running) > :where(:not(ol):not(ul):not(pre)):last-child::after,
4
+ :where(.aui-md-running) > pre:last-child code::after,
5
+ :where(.aui-md-running)
6
+ > :where(:is(ol, ul):last-child)
7
+ > :where(li:last-child:not(:has(* > li)))::after,
8
+ :where(.aui-md-running)
9
+ > :where(:is(ol, ul):last-child)
10
+ > :where(li:last-child)
11
+ > :where(:is(ol, ul):last-child)
12
+ > :where(li:last-child:not(:has(* > li)))::after,
13
+ :where(.aui-md-running)
14
+ > :where(:is(ol, ul):last-child)
15
+ > :where(li:last-child)
16
+ > :where(:is(ol, ul):last-child)
17
+ > :where(li:last-child)
18
+ > :where(:is(ol, ul):last-child)
19
+ > :where(li:last-child)::after {
20
+ @apply animate-pulse font-sans content-['\25CF'] ltr:ml-1 rtl:mr-1;
21
+ }
22
+
23
+ /* typography */
24
+ .aui-md-h1 {
25
+ @apply mb-8 scroll-m-20 text-4xl font-extrabold tracking-tight last:mb-0;
26
+ }
27
+
28
+ .aui-md-h2 {
29
+ @apply mb-4 mt-8 scroll-m-20 text-3xl font-semibold tracking-tight first:mt-0 last:mb-0;
30
+ }
31
+
32
+ .aui-md-h3 {
33
+ @apply mb-4 mt-6 scroll-m-20 text-2xl font-semibold tracking-tight first:mt-0 last:mb-0;
34
+ }
35
+
36
+ .aui-md-h4 {
37
+ @apply mb-4 mt-6 scroll-m-20 text-xl font-semibold tracking-tight first:mt-0 last:mb-0;
38
+ }
39
+
40
+ .aui-md-h5 {
41
+ @apply my-4 text-lg font-semibold first:mt-0 last:mb-0;
42
+ }
43
+
44
+ .aui-md-h6 {
45
+ @apply my-4 font-semibold first:mt-0 last:mb-0;
46
+ }
47
+
48
+ .aui-md-p {
49
+ @apply mb-5 mt-5 leading-7 first:mt-0 last:mb-0;
50
+ }
51
+
52
+ .aui-md-a {
53
+ @apply text-aui-primary font-medium underline underline-offset-4;
54
+ }
55
+
56
+ .aui-md-blockquote {
57
+ @apply border-l-2 pl-6 italic;
58
+ }
59
+
60
+ .aui-md-ul {
61
+ @apply my-5 ml-6 list-disc [&>li]:mt-2;
62
+ }
63
+
64
+ .aui-md-ol {
65
+ @apply my-5 ml-6 list-decimal [&>li]:mt-2;
66
+ }
67
+
68
+ .aui-md-hr {
69
+ @apply my-5 border-b;
70
+ }
71
+
72
+ .aui-md-table {
73
+ @apply my-5 w-full border-separate border-spacing-0 overflow-y-auto;
74
+ }
75
+
76
+ .aui-md-th {
77
+ @apply bg-aui-muted px-4 py-2 text-left font-bold first:rounded-tl-lg last:rounded-tr-lg [&[align=center]]:text-center [&[align=right]]:text-right;
78
+ }
79
+
80
+ .aui-md-td {
81
+ @apply border-b border-l px-4 py-2 text-left last:border-r [&[align=center]]:text-center [&[align=right]]:text-right;
82
+ }
83
+
84
+ .aui-md-tr {
85
+ @apply m-0 border-b p-0 first:border-t [&:last-child>td:first-child]:rounded-bl-lg [&:last-child>td:last-child]:rounded-br-lg;
86
+ }
87
+
88
+ .aui-md-sup {
89
+ @apply [&>a]:text-xs [&>a]:no-underline;
90
+ }
91
+
92
+ .aui-md-pre {
93
+ @apply overflow-x-auto rounded-b-lg bg-black p-4 text-white;
94
+ }
95
+
96
+ .aui-md-inline-code {
97
+ @apply bg-aui-muted rounded border font-semibold;
98
+ }
99
+
100
+ .aui-code-header-root {
101
+ @apply flex items-center justify-between gap-4 rounded-t-lg bg-zinc-900 px-4 py-2 text-sm font-semibold text-white;
102
+ }
103
+
104
+ .aui-code-header-language {
105
+ @apply lowercase [&>span]:text-xs;
106
+ }
@@ -0,0 +1,8 @@
1
+ import plugin from "tailwindcss/plugin.js";
2
+ import markdownCSS from "../../generated/markdown.css.json";
3
+
4
+ const auiPlugin = plugin.withOptions<{}>(() => ({ addComponents }) => {
5
+ addComponents(markdownCSS);
6
+ });
7
+
8
+ export default auiPlugin;
@@ -0,0 +1,32 @@
1
+ import { FC } from "react";
2
+ import { CheckIcon, CopyIcon } from "lucide-react";
3
+ import { INTERNAL, useThreadConfig } from "@assistant-ui/react";
4
+
5
+ import { CodeHeaderProps } from "../overrides/types";
6
+ import { useCopyToClipboard } from "./useCopyToClipboard";
7
+
8
+ const { TooltipIconButton } = INTERNAL;
9
+
10
+ export const CodeHeader: FC<CodeHeaderProps> = ({ language, code }) => {
11
+ const {
12
+ strings: {
13
+ code: { header: { copy: { tooltip = "Copy" } = {} } = {} } = {},
14
+ } = {},
15
+ } = useThreadConfig();
16
+
17
+ const { isCopied, copyToClipboard } = useCopyToClipboard();
18
+ const onCopy = () => {
19
+ if (!code || isCopied) return;
20
+ copyToClipboard(code);
21
+ };
22
+
23
+ return (
24
+ <div className="aui-code-header-root">
25
+ <span className="aui-code-header-language">{language}</span>
26
+ <TooltipIconButton tooltip={tooltip} onClick={onCopy}>
27
+ {!isCopied && <CopyIcon />}
28
+ {isCopied && <CheckIcon />}
29
+ </TooltipIconButton>
30
+ </div>
31
+ );
32
+ };
@@ -0,0 +1,114 @@
1
+ import { FC, memo } from "react";
2
+ import { CodeHeader } from "./code-header";
3
+ import classNames from "classnames";
4
+ import {
5
+ MarkdownTextPrimitive,
6
+ MarkdownTextPrimitiveProps,
7
+ } from "../primitives/MarkdownText";
8
+ import { INTERNAL } from "@assistant-ui/react";
9
+ import { useIsMarkdownCodeBlock } from "../overrides/PreOverride";
10
+
11
+ const { withSmoothContextProvider, useSmoothStatus } = INTERNAL;
12
+
13
+ export type MakeMarkdownTextProps = MarkdownTextPrimitiveProps;
14
+
15
+ const defaultComponents: MakeMarkdownTextProps["components"] = {
16
+ h1: ({ node, className, ...props }) => (
17
+ <h1 className={classNames("aui-md-h1", className)} {...props} />
18
+ ),
19
+ h2: ({ node, className, ...props }) => (
20
+ <h2 className={classNames("aui-md-h2", className)} {...props} />
21
+ ),
22
+ h3: ({ node, className, ...props }) => (
23
+ <h3 className={classNames("aui-md-h3", className)} {...props} />
24
+ ),
25
+ h4: ({ node, className, ...props }) => (
26
+ <h4 className={classNames("aui-md-h4", className)} {...props} />
27
+ ),
28
+ h5: ({ node, className, ...props }) => (
29
+ <h5 className={classNames("aui-md-h5", className)} {...props} />
30
+ ),
31
+ h6: ({ node, className, ...props }) => (
32
+ <h6 className={classNames("aui-md-h6", className)} {...props} />
33
+ ),
34
+ p: ({ node, className, ...props }) => (
35
+ <p className={classNames("aui-md-p", className)} {...props} />
36
+ ),
37
+ a: ({ node, className, ...props }) => (
38
+ <a className={classNames("aui-md-a", className)} {...props} />
39
+ ),
40
+ blockquote: ({ node, className, ...props }) => (
41
+ <blockquote
42
+ className={classNames("aui-md-blockquote", className)}
43
+ {...props}
44
+ />
45
+ ),
46
+ ul: ({ node, className, ...props }) => (
47
+ <ul className={classNames("aui-md-ul", className)} {...props} />
48
+ ),
49
+ ol: ({ node, className, ...props }) => (
50
+ <ol className={classNames("aui-md-ol", className)} {...props} />
51
+ ),
52
+ hr: ({ node, className, ...props }) => (
53
+ <hr className={classNames("aui-md-hr", className)} {...props} />
54
+ ),
55
+ table: ({ node, className, ...props }) => (
56
+ <table className={classNames("aui-md-table", className)} {...props} />
57
+ ),
58
+ th: ({ node, className, ...props }) => (
59
+ <th className={classNames("aui-md-th", className)} {...props} />
60
+ ),
61
+ td: ({ node, className, ...props }) => (
62
+ <td className={classNames("aui-md-td", className)} {...props} />
63
+ ),
64
+ tr: ({ node, className, ...props }) => (
65
+ <tr className={classNames("aui-md-tr", className)} {...props} />
66
+ ),
67
+ sup: ({ node, className, ...props }) => (
68
+ <sup className={classNames("aui-md-sup", className)} {...props} />
69
+ ),
70
+ pre: ({ node, className, ...props }) => (
71
+ <pre className={classNames("aui-md-pre", className)} {...props} />
72
+ ),
73
+ code: ({ node, className, ...props }) => {
74
+ const isCodeBlock = useIsMarkdownCodeBlock();
75
+ return (
76
+ <code
77
+ className={classNames(!isCodeBlock && "aui-md-inline-code", className)}
78
+ {...props}
79
+ />
80
+ );
81
+ },
82
+ CodeHeader,
83
+ };
84
+
85
+ export const makeMarkdownText = ({
86
+ className,
87
+ components: userComponents,
88
+ ...rest
89
+ }: MakeMarkdownTextProps = {}) => {
90
+ const components = {
91
+ ...defaultComponents,
92
+ ...Object.fromEntries(
93
+ // ignore undefined values, so undefined values do not override default components
94
+ Object.entries(userComponents ?? {}).filter(([_, v]) => v !== undefined),
95
+ ),
96
+ };
97
+
98
+ const MarkdownTextImpl: FC = () => {
99
+ const status = useSmoothStatus();
100
+ return (
101
+ <MarkdownTextPrimitive
102
+ components={components}
103
+ {...rest}
104
+ className={classNames(
105
+ status.type === "running" && "aui-md-running",
106
+ className,
107
+ )}
108
+ />
109
+ );
110
+ };
111
+ MarkdownTextImpl.displayName = "MarkdownText";
112
+
113
+ return memo(withSmoothContextProvider(MarkdownTextImpl), () => true);
114
+ };