diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0270853..5315892 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,13 @@
+## 0.5.0 (2022-12-18)
+
+### ✨ Features
+
+ * Add autolinker plugins
+
+Credits
+
+* [@Bunlong](https://github.com/Bunlong)
+
## 0.4.0 (2022-12-17)
### ✨ Features
diff --git a/README.md b/README.md
index 5a179e0..7c47358 100644
--- a/README.md
+++ b/README.md
@@ -38,13 +38,11 @@ export default function App() {
const { Code } = usePrism()
return (
- <>
-
+
{`
{Math.random()}
`}
-
- >
+
)
}
```
@@ -68,13 +66,9 @@ function App() {
return (
<>
-
+
You clicked {count} times
-
- {`You clicked ${count} times
`}
-
+ {`You clicked ${count} times
`}
>
)
}
@@ -777,13 +771,11 @@ export default function App() {
const { Code } = usePrism()
return (
- <>
-
+
{`
{Math.random()}
`}
-
- >
+
)
}
```
@@ -807,22 +799,48 @@ export default function App() {
const { Code } = usePrism()
return (
- <>
-
+
{`
- {Math.random()}
+{Math.random()}
`}
-
- >
+
)
}
```
+### Autolinker
+
+Converts URLs and emails in code to clickable links. Parses Markdown links in comments.
+
+```javascript
+import { usePrism } from 'next-prism'
+
+// Import a theme.css
+import 'next-prism/themes/tomorrow.css'
+
+// Import autolinker source
+import 'next-prism/plugins/autolinker/autolinker'
+// Import autolinker.css
+import 'next-prism/plugins/autolinker/autolinker.css'
+
+function App() {
+ const { Code } = usePrism()
+
+ return (
+
+ {``}
+
+ );
+}
+```
+
## 📜 Changelog
-Latest version 0.4.0 (2022-12-17):
+Latest version 0.5.0 (2022-12-18):
- * Add show-invisibles plugins
+ * Add autolinker plugins
Details changes for each release are documented in the [CHANGELOG.md](https://github.com/Bunlong/next-prism/blob/master/CHANGELOG.md).
diff --git a/package.json b/package.json
index 29a71bc..c9219ef 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "next-prism",
- "version": "0.4.1",
+ "version": "0.5.0",
"description": "A lightweight, robust, and elegant syntax highlighting component for your next React apps.",
"author": "Bunlong ",
"license": "MIT",
diff --git a/plugins/autolinker/autolinker.css b/plugins/autolinker/autolinker.css
new file mode 100644
index 0000000..8ef93a0
--- /dev/null
+++ b/plugins/autolinker/autolinker.css
@@ -0,0 +1,3 @@
+.token a {
+ color: inherit;
+}
diff --git a/plugins/autolinker/autolinker.js b/plugins/autolinker/autolinker.js
new file mode 100644
index 0000000..532e11b
--- /dev/null
+++ b/plugins/autolinker/autolinker.js
@@ -0,0 +1,76 @@
+(function () {
+
+ if (typeof Prism === 'undefined') {
+ return;
+ }
+
+ var url = /\b([a-z]{3,7}:\/\/|tel:)[\w\-+%~/.:=&!$'()*,;@]+(?:\?[\w\-+%~/.:=?&!$'()*,;@]*)?(?:#[\w\-+%~/.:#=?&!$'()*,;@]*)?/;
+ var email = /\b\S+@[\w.]+[a-z]{2}/;
+ var linkMd = /\[([^\]]+)\]\(([^)]+)\)/;
+
+ // Tokens that may contain URLs and emails
+ var candidates = ['comment', 'url', 'attr-value', 'string'];
+
+ Prism.plugins.autolinker = {
+ processGrammar: function (grammar) {
+ // Abort if grammar has already been processed
+ if (!grammar || grammar['url-link']) {
+ return;
+ }
+ Prism.languages.DFS(grammar, function (key, def, type) {
+ if (candidates.indexOf(type) > -1 && !Array.isArray(def)) {
+ if (!def.pattern) {
+ def = this[key] = {
+ pattern: def
+ };
+ }
+
+ def.inside = def.inside || {};
+
+ if (type == 'comment') {
+ def.inside['md-link'] = linkMd;
+ }
+ if (type == 'attr-value') {
+ Prism.languages.insertBefore('inside', 'punctuation', { 'url-link': url }, def);
+ } else {
+ def.inside['url-link'] = url;
+ }
+
+ def.inside['email-link'] = email;
+ }
+ });
+ grammar['url-link'] = url;
+ grammar['email-link'] = email;
+ }
+ };
+
+ Prism.hooks.add('before-highlight', function (env) {
+ Prism.plugins.autolinker.processGrammar(env.grammar);
+ });
+
+ Prism.hooks.add('wrap', function (env) {
+ if (/-link$/.test(env.type)) {
+ env.tag = 'a';
+
+ var href = env.content;
+
+ if (env.type == 'email-link' && href.indexOf('mailto:') != 0) {
+ href = 'mailto:' + href;
+ } else if (env.type == 'md-link') {
+ // Markdown
+ var match = env.content.match(linkMd);
+
+ href = match[2];
+ env.content = match[1];
+ }
+
+ env.attributes.href = href;
+
+ // Silently catch any error thrown by decodeURIComponent (#1186)
+ try {
+ env.content = decodeURIComponent(env.content);
+ } catch (e) { /* noop */ }
+ }
+ });
+
+}());
diff --git a/supports/create-react-app/src/App.js b/supports/create-react-app/src/App.js
index 38b376b..60392c5 100644
--- a/supports/create-react-app/src/App.js
+++ b/supports/create-react-app/src/App.js
@@ -1,29 +1,19 @@
-import { useState, useEffect } from 'react';
import { usePrism } from 'next-prism';
import 'next-prism/themes/tomorrow.css';
-import 'next-prism/plugins/show-invisibles/show-invisibles.css';
-import 'next-prism/plugins/show-invisibles/show-invisibles';
+import 'next-prism/plugins/autolinker/autolinker';
+import 'next-prism/plugins/autolinker/autolinker.css';
function App() {
- const [count, setCount] = useState(0);
- const { Code, highlightAll } = usePrism();
-
- useEffect(() => {
- highlightAll();
- }, [count]);
+ const { Code } = usePrism();
return (
- <>
-
- You clicked {count} times
-
- {`You clicked ${count} times
`}
-
- >
+
+ {``}
+
);
}