@codearcade/markdown 1.0.2 → 1.3.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 +38 -24
- package/dist/components/markdown.d.ts +2 -0
- package/dist/constants/theme.d.ts +2 -2
- package/dist/index.css +39 -0
- package/dist/index.js +24 -18
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
# @codearcade/
|
|
1
|
+
# @codearcade/markdown
|
|
2
2
|
|
|
3
3
|
A modern, feature-rich Markdown renderer for React applications. Built for **speed**, **customizability**, and **developer experience**.
|
|
4
4
|
|
|
5
|
-
Packed with **syntax highlighting
|
|
5
|
+
Packed with **dynamic syntax highlighting** (lazy-loaded for zero bloat), **copy-to-clipboard** functionality, and seamless **dark mode** support out of the box.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
## ✨ Features
|
|
10
10
|
|
|
11
11
|
- ⚡ **Powered by React Markdown**: Robust and reliable rendering.
|
|
12
|
+
- 🚀 **Zero Initial Bloat**: Syntax highlighters and themes are dynamically lazy-loaded only when needed!
|
|
12
13
|
- 🎨 **Theming Support**: First-class support for Light and Dark modes.
|
|
13
|
-
- 💅 **Syntax Highlighting**:
|
|
14
|
+
- 💅 **Dual Engine Syntax Highlighting**: Choose between **Prism** or **Highlight.js** under the hood, with access to over 100+ combined themes.
|
|
14
15
|
- 📋 **Copy Code**: Automatic "Copy to Clipboard" button for all code blocks.
|
|
15
16
|
- 🍭 **GFM Support**: GitHub Flavored Markdown (tables, autolinks, strikethrough) enabled by default.
|
|
16
|
-
- 🔌 **Plug & Play**: Works instantly with minimal configuration.
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
@@ -22,38 +22,39 @@ Packed with **syntax highlighting**, **copy-to-clipboard** functionality, and se
|
|
|
22
22
|
Install the package via your preferred package manager:
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
npm install @codearcade/
|
|
25
|
+
npm install @codearcade/markdown
|
|
26
26
|
# or
|
|
27
|
-
yarn add @codearcade/
|
|
27
|
+
yarn add @codearcade/markdown
|
|
28
28
|
# or
|
|
29
|
-
pnpm add @codearcade/
|
|
29
|
+
pnpm add @codearcade/markdown
|
|
30
30
|
# or
|
|
31
|
-
bun add @codearcade/
|
|
31
|
+
bun add @codearcade/markdown
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
## Usage
|
|
35
35
|
|
|
36
|
-
Using `@codearcade/
|
|
36
|
+
Using `@codearcade/markdown` is simple. Import the component, select your engine (`prism` or `hljs`), and pass your markdown string.
|
|
37
37
|
|
|
38
38
|
### Basic Usage
|
|
39
39
|
|
|
40
40
|
```tsx
|
|
41
|
-
import { MarkdownComponent } from "@codearcade/
|
|
41
|
+
import { MarkdownComponent } from "@codearcade/markdown";
|
|
42
42
|
|
|
43
43
|
const markdown = `
|
|
44
44
|
# Hello World
|
|
45
45
|
|
|
46
46
|
This is a **markdown** component.
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
```javascript
|
|
49
49
|
console.log("Hello from CodeArcade!");
|
|
50
|
-
|
|
50
|
+
```
|
|
51
51
|
`;
|
|
52
52
|
|
|
53
53
|
export default function App() {
|
|
54
54
|
return (
|
|
55
55
|
<div style={{ padding: 20 }}>
|
|
56
|
-
|
|
56
|
+
{/* The engine prop is required! Choose "prism" or "hljs" */}
|
|
57
|
+
<MarkdownComponent engine="prism" markdownText={markdown} />
|
|
57
58
|
</div>
|
|
58
59
|
);
|
|
59
60
|
}
|
|
@@ -61,11 +62,11 @@ export default function App() {
|
|
|
61
62
|
|
|
62
63
|
### Dark Mode & Custom Themes
|
|
63
64
|
|
|
64
|
-
Easily switch between light and dark modes, and customize the syntax highlighting theme
|
|
65
|
+
Easily switch between light and dark modes, and customize the syntax highlighting theme. Because this component is fully strongly-typed, your IDE will auto-complete the available themes based on the engine you select!
|
|
65
66
|
|
|
66
67
|
```tsx
|
|
67
68
|
import { useState } from "react";
|
|
68
|
-
import { MarkdownComponent } from "@codearcade/
|
|
69
|
+
import { MarkdownComponent } from "@codearcade/markdown";
|
|
69
70
|
|
|
70
71
|
export default function BlogPost() {
|
|
71
72
|
const [isDarkMode, setIsDarkMode] = useState(false);
|
|
@@ -75,9 +76,10 @@ export default function BlogPost() {
|
|
|
75
76
|
<button onClick={() => setIsDarkMode(!isDarkMode)}>Toggle Theme</button>
|
|
76
77
|
|
|
77
78
|
<MarkdownComponent
|
|
78
|
-
|
|
79
|
+
engine="prism"
|
|
80
|
+
markdownText={`console.log('test')`}
|
|
79
81
|
theme={isDarkMode ? "dark" : "light"}
|
|
80
|
-
//
|
|
82
|
+
// These will auto-complete to valid Prism themes!
|
|
81
83
|
defaultMarkdownThemeLight="atomDark"
|
|
82
84
|
defaultMarkdownThemeDark="dracula"
|
|
83
85
|
/>
|
|
@@ -91,23 +93,35 @@ export default function BlogPost() {
|
|
|
91
93
|
### `<MarkdownComponent />`
|
|
92
94
|
|
|
93
95
|
| Prop | Type | Default | Description |
|
|
94
|
-
|
|
96
|
+
|---|---|---|---|
|
|
97
|
+
| `engine` | `"prism" \| "hljs"` | **Required** | The syntax highlighting engine to power the code blocks. |
|
|
95
98
|
| `markdownText` | `string` | **Required** | The raw markdown string to render. |
|
|
96
|
-
| `theme` | `"light" \| "dark"` | `"light"` | Controls the rendering mode of the component. |
|
|
97
|
-
| `defaultMarkdownThemeLight` | `
|
|
98
|
-
| `defaultMarkdownThemeDark` | `
|
|
99
|
+
| `theme` | `"light" \| "dark"` | `"light"` | Controls the rendering mode of the surrounding component. |
|
|
100
|
+
| `defaultMarkdownThemeLight` | `string` | `"a11yDark"` | Syntax highlighting theme to use when `theme` is `"light"`. Allowed strings change based on the `engine`. |
|
|
101
|
+
| `defaultMarkdownThemeDark` | `string` | `"twilight"` (Prism) / `"vs2015"` (HLJS) | Syntax highlighting theme to use when `theme` is `"dark"`. Allowed strings change based on the `engine`. |
|
|
99
102
|
|
|
100
103
|
### Available Themes
|
|
101
104
|
|
|
102
|
-
We support a wide range of
|
|
105
|
+
We support a wide range of syntax highlighting themes. You can import the arrays directly if you want to build a theme-selector UI in your app!
|
|
106
|
+
|
|
107
|
+
#### Prism Themes
|
|
103
108
|
|
|
104
109
|
```tsx
|
|
105
|
-
import { prismStyleNames } from "@codearcade/
|
|
110
|
+
import { prismStyleNames } from "@codearcade/markdown";
|
|
106
111
|
|
|
107
112
|
console.log(prismStyleNames);
|
|
108
113
|
// ["dracula", "atomDark", "nightOwl", "vs", "monokai", ...]
|
|
109
114
|
```
|
|
110
115
|
|
|
116
|
+
#### Highlight.js Themes
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
import { hljsStyleNames } from "@codearcade/markdown";
|
|
120
|
+
|
|
121
|
+
console.log(hljsStyleNames);
|
|
122
|
+
// ["atom-one-dark", "atom-one-light", "base16/darcula", "github-dark", "nord", ...]
|
|
123
|
+
```
|
|
124
|
+
|
|
111
125
|
## License
|
|
112
126
|
|
|
113
|
-
MIT © [CodeArcade](https://github.com/codearcade-io)
|
|
127
|
+
MIT © [CodeArcade](https://github.com/codearcade-io)
|
|
@@ -7,12 +7,14 @@ type MarkdownComponentProps = {
|
|
|
7
7
|
theme?: Theme;
|
|
8
8
|
markdownText: string;
|
|
9
9
|
defaultMarkdownThemeDark?: PrismTheme;
|
|
10
|
+
compact?: boolean;
|
|
10
11
|
} | {
|
|
11
12
|
engine: "hljs";
|
|
12
13
|
defaultMarkdownThemeLight?: HljsTheme;
|
|
13
14
|
markdownText: string;
|
|
14
15
|
theme?: Theme;
|
|
15
16
|
defaultMarkdownThemeDark?: HljsTheme;
|
|
17
|
+
compact?: boolean;
|
|
16
18
|
};
|
|
17
19
|
declare const MarkdownComponent: React.FC<MarkdownComponentProps>;
|
|
18
20
|
export { MarkdownComponent };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
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"];
|
|
2
|
-
|
|
2
|
+
declare const hljsStyleNames: readonly ["a11yDark", "a11yLight", "agate", "anOldHope", "androidstudio", "arduinoLight", "arta", "ascetic", "atelierCaveDark", "atelierCaveLight", "atelierDuneDark", "atelierDuneLight", "atelierEstuaryDark", "atelierEstuaryLight", "atelierForestDark", "atelierForestLight", "atelierHeathDark", "atelierHeathLight", "atelierLakesideDark", "atelierLakesideLight", "atelierPlateauDark", "atelierPlateauLight", "atelierSavannaDark", "atelierSavannaLight", "atelierSeasideDark", "atelierSeasideLight", "atelierSulphurpoolDark", "atelierSulphurpoolLight", "atomOneDarkReasonable", "atomOneDark", "atomOneLight", "brownPaper", "codepenEmbed", "colorBrewer", "darcula", "dark", "defaultStyle", "docco", "dracula", "far", "foundation", "githubGist", "github", "gml", "googlecode", "gradientDark", "grayscale", "gruvboxDark", "gruvboxLight", "hopscotch", "hybrid", "idea", "irBlack", "isblEditorDark", "isblEditorLight", "kimbieDark", "kimbieLight", "lightfair", "lioshi", "magula", "monoBlue", "monokaiSublime", "monokai", "nightOwl", "nnfxDark", "nnfx", "nord", "obsidian", "ocean", "paraisoDark", "paraisoLight", "pojoaque", "purebasic", "qtcreatorDark", "qtcreatorLight", "railscasts", "rainbow", "routeros", "schoolBook", "shadesOfPurple", "solarizedDark", "solarizedLight", "srcery", "stackoverflowDark", "stackoverflowLight", "sunburst", "tomorrowNightBlue", "tomorrowNightBright", "tomorrowNightEighties", "tomorrowNight", "tomorrow", "vs", "vs2015", "xcode", "xt256", "zenburn"];
|
|
3
3
|
type PrismTheme = (typeof prismStyleNames)[number];
|
|
4
4
|
type HljsTheme = (typeof hljsStyleNames)[number];
|
|
5
|
-
export { prismStyleNames };
|
|
5
|
+
export { prismStyleNames, hljsStyleNames };
|
|
6
6
|
export type { PrismTheme, HljsTheme };
|
package/dist/index.css
CHANGED
|
@@ -179,3 +179,42 @@
|
|
|
179
179
|
color: var(--color-foreground, #fff);
|
|
180
180
|
background-color: #3f3f46;
|
|
181
181
|
}
|
|
182
|
+
|
|
183
|
+
.compactMode_A8U9fw {
|
|
184
|
+
padding: 0;
|
|
185
|
+
font-size: 13px;
|
|
186
|
+
line-height: 1.5;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.compactMode_A8U9fw > * + * {
|
|
190
|
+
margin-top: .25rem;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.compactMode_A8U9fw p {
|
|
194
|
+
margin-bottom: 0;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.compactMode_A8U9fw h1, .compactMode_A8U9fw h2, .compactMode_A8U9fw h3 {
|
|
198
|
+
margin-top: .5rem;
|
|
199
|
+
margin-bottom: .25rem;
|
|
200
|
+
font-size: 1.1rem;
|
|
201
|
+
line-height: 1.4;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.compactMode_A8U9fw h1:first-child, .compactMode_A8U9fw h2:first-child, .compactMode_A8U9fw h3:first-child, .compactMode_A8U9fw p:first-child {
|
|
205
|
+
margin-top: 0;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.compactMode_A8U9fw pre {
|
|
209
|
+
margin-top: .5rem;
|
|
210
|
+
margin-bottom: .5rem;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.compactMode_A8U9fw ul, .compactMode_A8U9fw ol {
|
|
214
|
+
margin-bottom: .25rem;
|
|
215
|
+
padding-left: 1.25rem;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.compactMode_A8U9fw li {
|
|
219
|
+
margin-bottom: 0;
|
|
220
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -17,16 +17,17 @@ import remarkGfm from "remark-gfm";
|
|
|
17
17
|
var markdown_module_default = {
|
|
18
18
|
markdownBody: "markdownBody_A8U9fw",
|
|
19
19
|
markdownAction: "markdownAction_A8U9fw",
|
|
20
|
-
dark: "dark_A8U9fw"
|
|
20
|
+
dark: "dark_A8U9fw",
|
|
21
|
+
compactMode: "compactMode_A8U9fw"
|
|
21
22
|
};
|
|
22
23
|
|
|
23
24
|
// src/components/icons.tsx
|
|
24
|
-
import {
|
|
25
|
+
import { jsx } from "react/jsx-runtime";
|
|
25
26
|
var CheckMarkIcon = () => {
|
|
26
|
-
return /* @__PURE__ */
|
|
27
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
27
28
|
xmlns: "http://www.w3.org/2000/svg",
|
|
28
29
|
viewBox: "0 0 512 512",
|
|
29
|
-
children: /* @__PURE__ */
|
|
30
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
30
31
|
fill: "none",
|
|
31
32
|
stroke: "currentColor",
|
|
32
33
|
"stroke-linecap": "round",
|
|
@@ -37,11 +38,11 @@ var CheckMarkIcon = () => {
|
|
|
37
38
|
}, undefined, false, undefined, this);
|
|
38
39
|
};
|
|
39
40
|
var CopyIcon = () => {
|
|
40
|
-
return /* @__PURE__ */
|
|
41
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
41
42
|
xmlns: "http://www.w3.org/2000/svg",
|
|
42
43
|
viewBox: "0 0 512 512",
|
|
43
44
|
children: [
|
|
44
|
-
/* @__PURE__ */
|
|
45
|
+
/* @__PURE__ */ jsx("rect", {
|
|
45
46
|
x: "128",
|
|
46
47
|
y: "128",
|
|
47
48
|
width: "336",
|
|
@@ -53,7 +54,7 @@ var CopyIcon = () => {
|
|
|
53
54
|
"stroke-linejoin": "round",
|
|
54
55
|
"stroke-width": "24"
|
|
55
56
|
}, undefined, false, undefined, this),
|
|
56
|
-
/* @__PURE__ */
|
|
57
|
+
/* @__PURE__ */ jsx("path", {
|
|
57
58
|
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",
|
|
58
59
|
fill: "none",
|
|
59
60
|
stroke: "currentColor",
|
|
@@ -66,7 +67,7 @@ var CopyIcon = () => {
|
|
|
66
67
|
};
|
|
67
68
|
|
|
68
69
|
// src/components/markdown.tsx
|
|
69
|
-
import {
|
|
70
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
70
71
|
"use client";
|
|
71
72
|
var CopyToClipboard = ({ text }) => {
|
|
72
73
|
const [isCopied, setIsCopied] = useState(false);
|
|
@@ -84,19 +85,24 @@ var CopyToClipboard = ({ text }) => {
|
|
|
84
85
|
}, 2000);
|
|
85
86
|
}
|
|
86
87
|
}, [text, isCopied]);
|
|
87
|
-
return /* @__PURE__ */
|
|
88
|
+
return /* @__PURE__ */ jsx2("button", {
|
|
88
89
|
onClick: copyToClipboard,
|
|
89
90
|
className: markdown_module_default.markdownAction,
|
|
90
91
|
"aria-label": isCopied ? "Copied to clipboard" : "Copy to clipboard",
|
|
91
92
|
children: [
|
|
92
|
-
isCopied ? /* @__PURE__ */
|
|
93
|
+
isCopied ? /* @__PURE__ */ jsx2(CheckMarkIcon, {}, undefined, false, undefined, this) : /* @__PURE__ */ jsx2(CopyIcon, {}, undefined, false, undefined, this),
|
|
93
94
|
" ",
|
|
94
95
|
isCopied ? "Copied" : "Copy"
|
|
95
96
|
]
|
|
96
97
|
}, undefined, true, undefined, this);
|
|
97
98
|
};
|
|
98
99
|
var MarkdownComponent = (props) => {
|
|
99
|
-
const {
|
|
100
|
+
const {
|
|
101
|
+
markdownText,
|
|
102
|
+
theme = "light",
|
|
103
|
+
engine = "prism",
|
|
104
|
+
compact = false
|
|
105
|
+
} = props;
|
|
100
106
|
const [markdownTheme, setMarkdownTheme] = useState();
|
|
101
107
|
const [Highlighter, setHighlighter] = useState();
|
|
102
108
|
useEffect(() => {
|
|
@@ -134,19 +140,19 @@ var MarkdownComponent = (props) => {
|
|
|
134
140
|
isMounted = false;
|
|
135
141
|
};
|
|
136
142
|
}, [engine, theme]);
|
|
137
|
-
return /* @__PURE__ */
|
|
138
|
-
className: `${markdown_module_default.markdownBody} ${theme}`,
|
|
139
|
-
children: /* @__PURE__ */
|
|
143
|
+
return /* @__PURE__ */ jsx2("section", {
|
|
144
|
+
className: `${markdown_module_default.markdownBody} ${theme} ${compact ? markdown_module_default.compactMode : ""}`,
|
|
145
|
+
children: /* @__PURE__ */ jsx2(ReactMarkdown, {
|
|
140
146
|
remarkPlugins: [remarkGfm],
|
|
141
147
|
components: {
|
|
142
148
|
code(props2) {
|
|
143
149
|
const { className, children, ref, ...rest } = props2;
|
|
144
150
|
const match = /language-(\w+)/.exec(className || "");
|
|
145
151
|
const codeText = String(children).replace(/\n$/, "");
|
|
146
|
-
return match && Highlighter ? /* @__PURE__ */
|
|
152
|
+
return match && Highlighter ? /* @__PURE__ */ jsx2("div", {
|
|
147
153
|
style: { position: "relative" },
|
|
148
154
|
children: [
|
|
149
|
-
/* @__PURE__ */
|
|
155
|
+
/* @__PURE__ */ jsx2(Highlighter, {
|
|
150
156
|
...rest,
|
|
151
157
|
PreTag: "div",
|
|
152
158
|
ref,
|
|
@@ -155,11 +161,11 @@ var MarkdownComponent = (props) => {
|
|
|
155
161
|
style: markdownTheme,
|
|
156
162
|
children: codeText
|
|
157
163
|
}, undefined, false, undefined, this),
|
|
158
|
-
/* @__PURE__ */
|
|
164
|
+
/* @__PURE__ */ jsx2(CopyToClipboard, {
|
|
159
165
|
text: codeText
|
|
160
166
|
}, undefined, false, undefined, this)
|
|
161
167
|
]
|
|
162
|
-
}, undefined, true, undefined, this) : /* @__PURE__ */
|
|
168
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ jsx2("code", {
|
|
163
169
|
...rest,
|
|
164
170
|
className,
|
|
165
171
|
children
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codearcade/markdown",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0
|
|
4
|
+
"version": "1.3.0",
|
|
5
5
|
"module": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"license": "MIT",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"dist/*.css"
|
|
25
25
|
],
|
|
26
26
|
"scripts": {
|
|
27
|
-
"build": "bun ./builder.ts && bun run generate-types",
|
|
27
|
+
"build": "NODE_ENV=production && bun ./builder.ts && bun run generate-types",
|
|
28
28
|
"prepublishOnly": "bun run build",
|
|
29
29
|
"generate-types": "bunx tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
30
30
|
"clear": "rm -rf dist"
|