@codearcade/markdown 1.0.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.
- package/README.md +113 -0
- package/dist/components/markdown.d.ts +12 -0
- package/dist/index.css +181 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +195 -0
- package/dist/index.js.map +10 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# @codearcade/mdx
|
|
2
|
+
|
|
3
|
+
A modern, feature-rich Markdown renderer for React applications. Built for **speed**, **customizability**, and **developer experience**.
|
|
4
|
+
|
|
5
|
+
Packed with **syntax highlighting**, **copy-to-clipboard** functionality, and seamless **dark mode** support out of the box.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## ✨ Features
|
|
10
|
+
|
|
11
|
+
- ⚡ **Powered by React Markdown**: Robust and reliable rendering.
|
|
12
|
+
- 🎨 **Theming Support**: First-class support for Light and Dark modes.
|
|
13
|
+
- 💅 **Syntax Highlighting**: Integrated Prism syntax highlighting with **50+ themes** (Dracula, Atom Dark, Night Owl, etc.).
|
|
14
|
+
- 📋 **Copy Code**: Automatic "Copy to Clipboard" button for all code blocks.
|
|
15
|
+
- 🍭 **GFM Support**: GitHub Flavored Markdown (tables, autolinks, strikethrough) enabled by default.
|
|
16
|
+
- 🔌 **Plug & Play**: Works instantly with minimal configuration.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
Install the package via your preferred package manager:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install @codearcade/mdx
|
|
26
|
+
# or
|
|
27
|
+
yarn add @codearcade/mdx
|
|
28
|
+
# or
|
|
29
|
+
pnpm add @codearcade/mdx
|
|
30
|
+
# or
|
|
31
|
+
bun add @codearcade/mdx
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
Using `@codearcade/mdx` is simple. Import the component and pass your markdown string.
|
|
37
|
+
|
|
38
|
+
### Basic Usage
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { MarkdownComponent } from "@codearcade/mdx";
|
|
42
|
+
|
|
43
|
+
const markdown = `
|
|
44
|
+
# Hello World
|
|
45
|
+
|
|
46
|
+
This is a **markdown** component.
|
|
47
|
+
|
|
48
|
+
\`\`\`javascript
|
|
49
|
+
console.log("Hello from CodeArcade!");
|
|
50
|
+
\`\`\`
|
|
51
|
+
`;
|
|
52
|
+
|
|
53
|
+
export default function App() {
|
|
54
|
+
return (
|
|
55
|
+
<div style={{ padding: 20 }}>
|
|
56
|
+
<MarkdownComponent markdownText={markdown} />
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Dark Mode & Custom Themes
|
|
63
|
+
|
|
64
|
+
Easily switch between light and dark modes, and customize the syntax highlighting theme for each mode.
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import { useState } from "react";
|
|
68
|
+
import { MarkdownComponent } from "@codearcade/mdx";
|
|
69
|
+
|
|
70
|
+
export default function BlogPost() {
|
|
71
|
+
const [isDarkMode, setIsDarkMode] = useState(false);
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<div className={isDarkMode ? "dark-theme" : "light-theme"}>
|
|
75
|
+
<button onClick={() => setIsDarkMode(!isDarkMode)}>Toggle Theme</button>
|
|
76
|
+
|
|
77
|
+
<MarkdownComponent
|
|
78
|
+
markdownText={content}
|
|
79
|
+
theme={isDarkMode ? "dark" : "light"}
|
|
80
|
+
// Customize syntax highlighting themes
|
|
81
|
+
defaultMarkdownThemeLight="atomDark"
|
|
82
|
+
defaultMarkdownThemeDark="dracula"
|
|
83
|
+
/>
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## API Reference
|
|
90
|
+
|
|
91
|
+
### `<MarkdownComponent />`
|
|
92
|
+
|
|
93
|
+
| Prop | Type | Default | Description |
|
|
94
|
+
|Text | | | |
|
|
95
|
+
| `markdownText` | `string` | **Required** | The raw markdown string to render. |
|
|
96
|
+
| `theme` | `"light" \| "dark"` | `"light"` | Controls the rendering mode of the component. |
|
|
97
|
+
| `defaultMarkdownThemeLight` | `MarkdownTheme` | `"a11yDark"` | Syntax highlighting theme to use when `theme` is `"light"`. |
|
|
98
|
+
| `defaultMarkdownThemeDark` | `MarkdownTheme` | `"twilight"` | Syntax highlighting theme to use when `theme` is `"dark"`. |
|
|
99
|
+
|
|
100
|
+
### Available Themes
|
|
101
|
+
|
|
102
|
+
We support a wide range of Prism themes. You can import `prismStyleNames` to see the full list or use it to build a theme selector.
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
import { prismStyleNames } from "@codearcade/mdx";
|
|
106
|
+
|
|
107
|
+
console.log(prismStyleNames);
|
|
108
|
+
// ["dracula", "atomDark", "nightOwl", "vs", "monokai", ...]
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## License
|
|
112
|
+
|
|
113
|
+
MIT © [CodeArcade](https://github.com/codearcade-io)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
declare const prismStyleNames: readonly ["a11yDark", "atomDark", "base16AteliersulphurpoolLight", "cb", "coldarkCold", "coldarkDark", "coyWithoutShadows", "coy", "darcula", "dark", "dracula", "duotoneDark", "duotoneEarth", "duotoneForest", "duotoneLight", "duotoneSea", "duotoneSpace", "funky", "ghcolors", "gruvboxDark", "gruvboxLight", "holiTheme", "hopscotch", "lucario", "materialDark", "materialLight", "materialOceanic", "nightOwl", "nord", "okaidia", "oneDark", "oneLight", "pojoaque", "prism", "shadesOfPurple", "solarizedDarkAtom", "solarizedlight", "synthwave84", "tomorrow", "twilight", "vs", "vscDarkPlus", "xonokai", "zTouch"];
|
|
3
|
+
type MarkdownTheme = (typeof prismStyleNames)[number];
|
|
4
|
+
type Theme = "dark" | "light";
|
|
5
|
+
interface MarkdownComponentProps {
|
|
6
|
+
markdownText: string;
|
|
7
|
+
theme?: Theme;
|
|
8
|
+
defaultMarkdownThemeLight?: MarkdownTheme;
|
|
9
|
+
defaultMarkdownThemeDark?: MarkdownTheme;
|
|
10
|
+
}
|
|
11
|
+
declare const MarkdownComponent: React.FC<MarkdownComponentProps>;
|
|
12
|
+
export { MarkdownComponent, prismStyleNames };
|
package/dist/index.css
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/* src/components/markdown.module.css */
|
|
2
|
+
.markdownBody_A8U9fw {
|
|
3
|
+
border-radius: .5rem;
|
|
4
|
+
max-width: 850px;
|
|
5
|
+
padding: 1.5rem;
|
|
6
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Noto Sans, Ubuntu, Cantarell, Helvetica Neue, Helvetica, Arial, sans-serif;
|
|
7
|
+
font-size: 1rem;
|
|
8
|
+
line-height: 1.75;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.markdownBody_A8U9fw h1 {
|
|
12
|
+
font-size: 1.875rem;
|
|
13
|
+
line-height: 2.25rem;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.markdownBody_A8U9fw h2 {
|
|
17
|
+
font-size: 1.5rem;
|
|
18
|
+
line-height: 2rem;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.markdownBody_A8U9fw h3 {
|
|
22
|
+
font-size: 1.25rem;
|
|
23
|
+
line-height: 1.75rem;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.markdownBody_A8U9fw h1, .markdownBody_A8U9fw h2, .markdownBody_A8U9fw h3 {
|
|
27
|
+
margin-bottom: 1rem;
|
|
28
|
+
font-weight: 600;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.markdownBody_A8U9fw p {
|
|
32
|
+
margin-bottom: 1rem;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.markdownBody_A8U9fw a {
|
|
36
|
+
text-decoration: none;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.markdownBody_A8U9fw a:hover {
|
|
40
|
+
text-decoration: underline;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.markdownBody_A8U9fw ul, .markdownBody_A8U9fw ol {
|
|
44
|
+
margin-bottom: 1rem;
|
|
45
|
+
padding-left: 1.5rem;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.markdownBody_A8U9fw ul {
|
|
49
|
+
list-style-type: disc;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.markdownBody_A8U9fw ol {
|
|
53
|
+
list-style-type: decimal;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.markdownBody_A8U9fw li {
|
|
57
|
+
margin-bottom: .5rem;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.markdownBody_A8U9fw code, .markdownBody_A8U9fw pre {
|
|
61
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, monospace;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.markdownBody_A8U9fw code {
|
|
65
|
+
border-radius: .25rem;
|
|
66
|
+
padding: .25rem;
|
|
67
|
+
font-size: .875rem;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.markdownBody_A8U9fw pre {
|
|
71
|
+
overflow-x: auto;
|
|
72
|
+
border-radius: .5rem;
|
|
73
|
+
margin-bottom: 1rem;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.markdownBody_A8U9fw blockquote {
|
|
77
|
+
border-left: 4px solid;
|
|
78
|
+
margin-bottom: 1rem;
|
|
79
|
+
margin-left: 0;
|
|
80
|
+
padding-left: 1rem;
|
|
81
|
+
font-style: italic;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.markdownBody_A8U9fw strong {
|
|
85
|
+
font-weight: 700;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.markdownBody_A8U9fw em {
|
|
89
|
+
font-style: italic;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.markdownBody_A8U9fw del {
|
|
93
|
+
text-decoration: line-through;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.markdownBody_A8U9fw hr {
|
|
97
|
+
border: none;
|
|
98
|
+
border-top: 2px solid;
|
|
99
|
+
margin: 1.5rem 0;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.markdownBody_A8U9fw table {
|
|
103
|
+
border-collapse: collapse;
|
|
104
|
+
overflow-x: auto;
|
|
105
|
+
width: 100%;
|
|
106
|
+
margin-bottom: 1rem;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.markdownBody_A8U9fw th, .markdownBody_A8U9fw td {
|
|
110
|
+
text-align: left;
|
|
111
|
+
border: 1px solid;
|
|
112
|
+
padding: .5rem;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.markdownBody_A8U9fw th {
|
|
116
|
+
font-weight: 600;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.markdownBody_A8U9fw tr:nth-child(2n) {
|
|
120
|
+
background: none;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.markdownBody_A8U9fw > * + * {
|
|
124
|
+
margin-top: 1rem;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.markdownBody_A8U9fw h1, .markdownBody_A8U9fw h2, .markdownBody_A8U9fw h3 {
|
|
128
|
+
margin-top: 2rem;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.markdownBody_A8U9fw h1:first-child, .markdownBody_A8U9fw h2:first-child, .markdownBody_A8U9fw h3:first-child {
|
|
132
|
+
margin-top: 0;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.markdownBody_A8U9fw li > ul, .markdownBody_A8U9fw li > ol {
|
|
136
|
+
margin-top: .5rem;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.markdownBody_A8U9fw img {
|
|
140
|
+
display: block;
|
|
141
|
+
max-width: 100%;
|
|
142
|
+
height: auto;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.markdownBody_A8U9fw pre {
|
|
146
|
+
margin-top: 1.25rem;
|
|
147
|
+
margin-bottom: 1.25rem;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.markdownAction_A8U9fw {
|
|
151
|
+
position: absolute;
|
|
152
|
+
display: flex;
|
|
153
|
+
cursor: pointer;
|
|
154
|
+
opacity: .75;
|
|
155
|
+
color: var(--color-foreground, #171717);
|
|
156
|
+
background-color: #e5e7eb;
|
|
157
|
+
border: none;
|
|
158
|
+
border-radius: .5rem;
|
|
159
|
+
align-items: center;
|
|
160
|
+
gap: .25rem;
|
|
161
|
+
padding: .25rem .5rem;
|
|
162
|
+
transition: opacity .15s ease-in-out;
|
|
163
|
+
font-size: .875rem;
|
|
164
|
+
top: .5rem;
|
|
165
|
+
right: .5rem;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.markdownAction_A8U9fw:hover {
|
|
169
|
+
opacity: 1;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.markdownAction_A8U9fw svg {
|
|
173
|
+
flex: none;
|
|
174
|
+
width: .85rem;
|
|
175
|
+
height: .85rem;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.dark_A8U9fw .markdownAction_A8U9fw {
|
|
179
|
+
color: var(--color-foreground, #fff);
|
|
180
|
+
background-color: #3f3f46;
|
|
181
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./components/markdown";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import "./index.css";
|
|
3
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
4
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
5
|
+
}) : x)(function(x) {
|
|
6
|
+
if (typeof require !== "undefined")
|
|
7
|
+
return require.apply(this, arguments);
|
|
8
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
// src/components/markdown.tsx
|
|
12
|
+
import { useCallback, useEffect, useState } from "react";
|
|
13
|
+
import ReactMarkdown from "react-markdown";
|
|
14
|
+
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
|
15
|
+
import remarkGfm from "remark-gfm";
|
|
16
|
+
|
|
17
|
+
// src/components/markdown.module.css
|
|
18
|
+
var markdown_module_default = {
|
|
19
|
+
markdownBody: "markdownBody_A8U9fw",
|
|
20
|
+
markdownAction: "markdownAction_A8U9fw",
|
|
21
|
+
dark: "dark_A8U9fw"
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// src/components/markdown.tsx
|
|
25
|
+
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
26
|
+
"use client";
|
|
27
|
+
var prismStyleNames = [
|
|
28
|
+
"a11yDark",
|
|
29
|
+
"atomDark",
|
|
30
|
+
"base16AteliersulphurpoolLight",
|
|
31
|
+
"cb",
|
|
32
|
+
"coldarkCold",
|
|
33
|
+
"coldarkDark",
|
|
34
|
+
"coyWithoutShadows",
|
|
35
|
+
"coy",
|
|
36
|
+
"darcula",
|
|
37
|
+
"dark",
|
|
38
|
+
"dracula",
|
|
39
|
+
"duotoneDark",
|
|
40
|
+
"duotoneEarth",
|
|
41
|
+
"duotoneForest",
|
|
42
|
+
"duotoneLight",
|
|
43
|
+
"duotoneSea",
|
|
44
|
+
"duotoneSpace",
|
|
45
|
+
"funky",
|
|
46
|
+
"ghcolors",
|
|
47
|
+
"gruvboxDark",
|
|
48
|
+
"gruvboxLight",
|
|
49
|
+
"holiTheme",
|
|
50
|
+
"hopscotch",
|
|
51
|
+
"lucario",
|
|
52
|
+
"materialDark",
|
|
53
|
+
"materialLight",
|
|
54
|
+
"materialOceanic",
|
|
55
|
+
"nightOwl",
|
|
56
|
+
"nord",
|
|
57
|
+
"okaidia",
|
|
58
|
+
"oneDark",
|
|
59
|
+
"oneLight",
|
|
60
|
+
"pojoaque",
|
|
61
|
+
"prism",
|
|
62
|
+
"shadesOfPurple",
|
|
63
|
+
"solarizedDarkAtom",
|
|
64
|
+
"solarizedlight",
|
|
65
|
+
"synthwave84",
|
|
66
|
+
"tomorrow",
|
|
67
|
+
"twilight",
|
|
68
|
+
"vs",
|
|
69
|
+
"vscDarkPlus",
|
|
70
|
+
"xonokai",
|
|
71
|
+
"zTouch"
|
|
72
|
+
];
|
|
73
|
+
var CheckMarkIcon = () => {
|
|
74
|
+
return /* @__PURE__ */ jsxDEV("svg", {
|
|
75
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
76
|
+
viewBox: "0 0 512 512",
|
|
77
|
+
children: /* @__PURE__ */ jsxDEV("path", {
|
|
78
|
+
fill: "none",
|
|
79
|
+
stroke: "currentColor",
|
|
80
|
+
"stroke-linecap": "round",
|
|
81
|
+
"stroke-linejoin": "round",
|
|
82
|
+
"stroke-width": "24",
|
|
83
|
+
d: "M416 128L192 384l-96-96"
|
|
84
|
+
}, undefined, false, undefined, this)
|
|
85
|
+
}, undefined, false, undefined, this);
|
|
86
|
+
};
|
|
87
|
+
var CopyIcon = () => {
|
|
88
|
+
return /* @__PURE__ */ jsxDEV("svg", {
|
|
89
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
90
|
+
viewBox: "0 0 512 512",
|
|
91
|
+
children: [
|
|
92
|
+
/* @__PURE__ */ jsxDEV("rect", {
|
|
93
|
+
x: "128",
|
|
94
|
+
y: "128",
|
|
95
|
+
width: "336",
|
|
96
|
+
height: "336",
|
|
97
|
+
rx: "57",
|
|
98
|
+
ry: "57",
|
|
99
|
+
fill: "none",
|
|
100
|
+
stroke: "currentColor",
|
|
101
|
+
"stroke-linejoin": "round",
|
|
102
|
+
"stroke-width": "24"
|
|
103
|
+
}, undefined, false, undefined, this),
|
|
104
|
+
/* @__PURE__ */ jsxDEV("path", {
|
|
105
|
+
d: "M383.5 128l.5-24a56.16 56.16 0 00-56-56H112a64.19 64.19 0 00-64 64v216a56.16 56.16 0 0056 56h24",
|
|
106
|
+
fill: "none",
|
|
107
|
+
stroke: "currentColor",
|
|
108
|
+
"stroke-linecap": "round",
|
|
109
|
+
"stroke-linejoin": "round",
|
|
110
|
+
"stroke-width": "24"
|
|
111
|
+
}, undefined, false, undefined, this)
|
|
112
|
+
]
|
|
113
|
+
}, undefined, true, undefined, this);
|
|
114
|
+
};
|
|
115
|
+
var CopyToClipboard = ({ text }) => {
|
|
116
|
+
const [isCopied, setIsCopied] = useState(false);
|
|
117
|
+
const copyToClipboard = useCallback(async () => {
|
|
118
|
+
if (isCopied)
|
|
119
|
+
return;
|
|
120
|
+
try {
|
|
121
|
+
await navigator.clipboard.writeText(text);
|
|
122
|
+
setIsCopied(true);
|
|
123
|
+
} catch (err) {
|
|
124
|
+
console.error("Failed to copy text: ", err);
|
|
125
|
+
} finally {
|
|
126
|
+
setTimeout(() => {
|
|
127
|
+
setIsCopied(false);
|
|
128
|
+
}, 2000);
|
|
129
|
+
}
|
|
130
|
+
}, [text, isCopied]);
|
|
131
|
+
return /* @__PURE__ */ jsxDEV("button", {
|
|
132
|
+
onClick: copyToClipboard,
|
|
133
|
+
className: markdown_module_default.markdownAction,
|
|
134
|
+
"aria-label": isCopied ? "Copied to clipboard" : "Copy to clipboard",
|
|
135
|
+
children: [
|
|
136
|
+
isCopied ? /* @__PURE__ */ jsxDEV(CheckMarkIcon, {}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV(CopyIcon, {}, undefined, false, undefined, this),
|
|
137
|
+
" ",
|
|
138
|
+
isCopied ? "Copied" : "Copy"
|
|
139
|
+
]
|
|
140
|
+
}, undefined, true, undefined, this);
|
|
141
|
+
};
|
|
142
|
+
var MarkdownComponent = ({
|
|
143
|
+
markdownText,
|
|
144
|
+
theme = "light",
|
|
145
|
+
defaultMarkdownThemeLight = "a11yDark",
|
|
146
|
+
defaultMarkdownThemeDark = "twilight"
|
|
147
|
+
}) => {
|
|
148
|
+
const [markdownTheme, setMarkdownTheme] = useState();
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
import("react-syntax-highlighter/dist/esm/styles/prism").then((module) => {
|
|
151
|
+
setMarkdownTheme(module[theme === "dark" ? defaultMarkdownThemeDark : defaultMarkdownThemeLight]);
|
|
152
|
+
});
|
|
153
|
+
}, [defaultMarkdownThemeLight, defaultMarkdownThemeDark, theme]);
|
|
154
|
+
return /* @__PURE__ */ jsxDEV("section", {
|
|
155
|
+
className: `${markdown_module_default.markdownBody} ${theme}`,
|
|
156
|
+
children: /* @__PURE__ */ jsxDEV(ReactMarkdown, {
|
|
157
|
+
remarkPlugins: [remarkGfm],
|
|
158
|
+
components: {
|
|
159
|
+
code(props) {
|
|
160
|
+
const { className, children, ref, ...rest } = props;
|
|
161
|
+
const match = /language-(\w+)/.exec(className || "");
|
|
162
|
+
const codeText = String(children).replace(/\n$/, "");
|
|
163
|
+
return match ? /* @__PURE__ */ jsxDEV("div", {
|
|
164
|
+
style: { position: "relative" },
|
|
165
|
+
children: [
|
|
166
|
+
/* @__PURE__ */ jsxDEV(SyntaxHighlighter, {
|
|
167
|
+
...rest,
|
|
168
|
+
PreTag: "div",
|
|
169
|
+
ref,
|
|
170
|
+
customStyle: { borderRadius: "1rem" },
|
|
171
|
+
language: match[1],
|
|
172
|
+
style: markdownTheme,
|
|
173
|
+
children: codeText
|
|
174
|
+
}, undefined, false, undefined, this),
|
|
175
|
+
/* @__PURE__ */ jsxDEV(CopyToClipboard, {
|
|
176
|
+
text: codeText
|
|
177
|
+
}, undefined, false, undefined, this)
|
|
178
|
+
]
|
|
179
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV("code", {
|
|
180
|
+
...rest,
|
|
181
|
+
className,
|
|
182
|
+
children
|
|
183
|
+
}, undefined, false, undefined, this);
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
children: markdownText
|
|
187
|
+
}, undefined, false, undefined, this)
|
|
188
|
+
}, undefined, false, undefined, this);
|
|
189
|
+
};
|
|
190
|
+
export {
|
|
191
|
+
prismStyleNames,
|
|
192
|
+
MarkdownComponent
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
//# debugId=06022BF521D3780764756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["..\\src\\components\\markdown.tsx"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"\"use client\";\r\n\r\nimport type { Ref } from \"react\";\r\nimport React, { useCallback, useEffect, useState } from \"react\";\r\nimport ReactMarkdown from \"react-markdown\";\r\nimport { Prism as SyntaxHighlighter } from \"react-syntax-highlighter\";\r\nimport remarkGfm from \"remark-gfm\";\r\n\r\n// @ts-ignore\r\nimport styles from \"./markdown.module.css\";\r\n\r\nconst prismStyleNames = [\r\n \"a11yDark\",\r\n \"atomDark\",\r\n \"base16AteliersulphurpoolLight\",\r\n \"cb\",\r\n \"coldarkCold\",\r\n \"coldarkDark\",\r\n \"coyWithoutShadows\",\r\n \"coy\",\r\n \"darcula\",\r\n \"dark\",\r\n \"dracula\",\r\n \"duotoneDark\",\r\n \"duotoneEarth\",\r\n \"duotoneForest\",\r\n \"duotoneLight\",\r\n \"duotoneSea\",\r\n \"duotoneSpace\",\r\n \"funky\",\r\n \"ghcolors\",\r\n \"gruvboxDark\",\r\n \"gruvboxLight\",\r\n \"holiTheme\",\r\n \"hopscotch\",\r\n \"lucario\",\r\n \"materialDark\",\r\n \"materialLight\",\r\n \"materialOceanic\",\r\n \"nightOwl\",\r\n \"nord\",\r\n \"okaidia\",\r\n \"oneDark\",\r\n \"oneLight\",\r\n \"pojoaque\",\r\n \"prism\",\r\n \"shadesOfPurple\",\r\n \"solarizedDarkAtom\",\r\n \"solarizedlight\",\r\n \"synthwave84\",\r\n \"tomorrow\",\r\n \"twilight\",\r\n \"vs\",\r\n \"vscDarkPlus\",\r\n \"xonokai\",\r\n \"zTouch\",\r\n] as const;\r\n\r\ntype MarkdownTheme = (typeof prismStyleNames)[number];\r\n\r\nconst CheckMarkIcon = () => {\r\n return (\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\">\r\n <path\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n stroke-width=\"24\"\r\n d=\"M416 128L192 384l-96-96\"\r\n />\r\n </svg>\r\n );\r\n};\r\n\r\nconst CopyIcon = () => {\r\n return (\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\">\r\n <rect\r\n x=\"128\"\r\n y=\"128\"\r\n width=\"336\"\r\n height=\"336\"\r\n rx=\"57\"\r\n ry=\"57\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-linejoin=\"round\"\r\n stroke-width=\"24\"\r\n />\r\n <path\r\n d=\"M383.5 128l.5-24a56.16 56.16 0 00-56-56H112a64.19 64.19 0 00-64 64v216a56.16 56.16 0 0056 56h24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n stroke-width=\"24\"\r\n />\r\n </svg>\r\n );\r\n};\r\n\r\nconst CopyToClipboard = ({ text }: { text: string }) => {\r\n const [isCopied, setIsCopied] = useState(false);\r\n\r\n const copyToClipboard = useCallback(async () => {\r\n if (isCopied) return;\r\n\r\n try {\r\n await navigator.clipboard.writeText(text);\r\n setIsCopied(true);\r\n } catch (err) {\r\n console.error(\"Failed to copy text: \", err);\r\n // Optionally, show a user-friendly error message\r\n } finally {\r\n setTimeout(() => {\r\n setIsCopied(false);\r\n }, 2000);\r\n }\r\n }, [text, isCopied]);\r\n\r\n return (\r\n <button\r\n onClick={copyToClipboard}\r\n className={styles.markdownAction}\r\n aria-label={isCopied ? \"Copied to clipboard\" : \"Copy to clipboard\"}\r\n >\r\n {isCopied ? <CheckMarkIcon /> : <CopyIcon />}{\" \"}\r\n {isCopied ? \"Copied\" : \"Copy\"}\r\n </button>\r\n );\r\n};\r\n\r\ntype Theme = \"dark\" | \"light\";\r\n\r\ninterface MarkdownComponentProps {\r\n markdownText: string;\r\n theme?: Theme;\r\n defaultMarkdownThemeLight?: MarkdownTheme;\r\n defaultMarkdownThemeDark?: MarkdownTheme;\r\n}\r\n\r\ntype SyntaxHighlighterStyle = { [key: string]: React.CSSProperties };\r\n\r\nconst MarkdownComponent: React.FC<MarkdownComponentProps> = ({\r\n markdownText,\r\n theme = \"light\",\r\n defaultMarkdownThemeLight = \"a11yDark\",\r\n defaultMarkdownThemeDark = \"twilight\",\r\n}) => {\r\n const [markdownTheme, setMarkdownTheme] = useState<SyntaxHighlighterStyle>();\r\n\r\n useEffect(() => {\r\n import(\"react-syntax-highlighter/dist/esm/styles/prism\").then((module) => {\r\n setMarkdownTheme(\r\n module[\r\n theme === \"dark\"\r\n ? defaultMarkdownThemeDark\r\n : defaultMarkdownThemeLight\r\n ],\r\n );\r\n });\r\n }, [defaultMarkdownThemeLight, defaultMarkdownThemeDark, theme]);\r\n\r\n return (\r\n <section className={`${styles.markdownBody} ${theme}`}>\r\n <ReactMarkdown\r\n remarkPlugins={[remarkGfm]}\r\n components={{\r\n code(props) {\r\n const { className, children, ref, ...rest } = props;\r\n const match = /language-(\\w+)/.exec(className || \"\");\r\n const codeText = String(children).replace(/\\n$/, \"\");\r\n return match ? (\r\n <div style={{ position: \"relative\" }}>\r\n <SyntaxHighlighter\r\n {...rest}\r\n PreTag=\"div\"\r\n ref={ref as Ref<SyntaxHighlighter>}\r\n customStyle={{ borderRadius: \"1rem\" }}\r\n language={match[1]}\r\n style={markdownTheme}\r\n >\r\n {codeText}\r\n </SyntaxHighlighter>\r\n <CopyToClipboard text={codeText} />\r\n </div>\r\n ) : (\r\n <code {...rest} className={className}>\r\n {children}\r\n </code>\r\n );\r\n },\r\n }}\r\n >\r\n {markdownText}\r\n </ReactMarkdown>\r\n </section>\r\n );\r\n};\r\n\r\nexport { MarkdownComponent, prismStyleNames };\r\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "06022BF521D3780764756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@codearcade/markdown",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"module": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"sideEffects": [
|
|
15
|
+
"dist/*.css"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "bun ./builder.ts && bun run generate-types",
|
|
19
|
+
"prepublishOnly": "bun run build",
|
|
20
|
+
"generate-types": "bunx tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
21
|
+
"clear": "rm -rf dist"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"homepage": "https://github.com/codearcade-io/markdown.git#readme",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/codearcade-io/markdown.git"
|
|
33
|
+
},
|
|
34
|
+
"bugs": "https://github.com/codearcade-io/markdown/issues",
|
|
35
|
+
"author": "Abhishek Singh <official.6packprogrammer@gmail.com>",
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/bun": "^1.2.20",
|
|
38
|
+
"@types/react-syntax-highlighter": "^15.5.13",
|
|
39
|
+
"tslib": "^2.8.1",
|
|
40
|
+
"typedoc": "^0.28.10"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"react": ">=18",
|
|
44
|
+
"react-dom": ">=18"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"react-markdown": "^10.1.0",
|
|
48
|
+
"react-syntax-highlighter": "^16.1.0",
|
|
49
|
+
"remark-gfm": "^4.0.1"
|
|
50
|
+
}
|
|
51
|
+
}
|