Skip to content

Commit 95f6021

Browse files
committed
feat: add hyper-link extensions.
1 parent 08bc13a commit 95f6021

File tree

12 files changed

+320
-21
lines changed

12 files changed

+320
-21
lines changed

.github/workflows/ci.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,12 @@ jobs:
176176
token: ${{ secrets.NPM_TOKEN }}
177177
package: ./extensions/color/package.json
178178

179+
- name: 📦 @uiw/codemirror-extensions-hyper-link to NPM
180+
uses: JS-DevTools/npm-publish@v1
181+
with:
182+
token: ${{ secrets.NPM_TOKEN }}
183+
package: ./extensions/hyper-link/package.json
184+
179185
- name: 📦 @uiw/codemirror-extensions-line-numbers-relative to NPM
180186
uses: JS-DevTools/npm-publish@v1
181187
with:
@@ -424,5 +430,19 @@ jobs:
424430
- run: npm publish
425431
working-directory: extensions/line-numbers-relative
426432
if: success() || failure()
433+
env:
434+
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
435+
436+
- name: Modify @uiw/codemirror-extensions-hyper-link => @uiwjs/codemirror-extensions-hyper-link
437+
uses: jaywcjlove/github-action-package@main
438+
if: success() || failure()
439+
with:
440+
path: extensions/hyper-link/package.json
441+
data: |
442+
{ "name": "@uiwjs/codemirror-extensions-hyper-link" }
443+
444+
- run: npm publish
445+
working-directory: extensions/hyper-link
446+
if: success() || failure()
427447
env:
428448
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}

core/README.md

Lines changed: 18 additions & 17 deletions
Large diffs are not rendered by default.

extensions/color/src/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ function colorDecorations(view: EditorView) {
6666
to,
6767
alpha: a ? a.replace(/(\/|,)/g, '') : '',
6868
}),
69-
side: 1,
69+
side: 0,
7070
});
7171
widgets.push(widget.range(from));
7272
} else if (type.name === 'CallExpression' && hslMatcher(callExp)) {
@@ -108,7 +108,7 @@ function colorDecorations(view: EditorView) {
108108
to,
109109
alpha: match.a ? match.a.toString() : '',
110110
}),
111-
side: 1,
111+
side: 0,
112112
});
113113
widgets.push(widget.range(from));
114114
} else if (type.name === 'ColorLiteral') {
@@ -122,7 +122,7 @@ function colorDecorations(view: EditorView) {
122122
to,
123123
alpha,
124124
}),
125-
side: 1,
125+
side: 0,
126126
});
127127
widgets.push(widget.range(from));
128128
} else if (type.name === 'ValueName') {
@@ -137,7 +137,7 @@ function colorDecorations(view: EditorView) {
137137
to,
138138
alpha: '',
139139
}),
140-
side: 1,
140+
side: 0,
141141
});
142142
widgets.push(widget.range(from));
143143
}

extensions/hyper-link/README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<!--rehype:ignore:start-->
2+
3+
# Hyper link Extensions
4+
5+
<!--rehype:ignore:end-->
6+
7+
[![npm version](https://img.shields.io/npm/v/@uiw/codemirror-extensions-hyper-link.svg)](https://www.npmjs.com/package/@uiw/codemirror-extensions-hyper-link)
8+
9+
Hyper link Extensions for CodeMirror6.
10+
11+
## Install
12+
13+
```bash
14+
npm install @uiw/codemirror-extensions-hyper-link --save
15+
```
16+
17+
## Usage
18+
19+
```jsx
20+
import CodeMirror from '@uiw/react-codemirror';
21+
import { hyperLink } from '@uiw/codemirror-extensions-hyper-link';
22+
23+
const code = `https://uiwjs.github.io/react-codemirror`;
24+
25+
function App() {
26+
return <CodeMirror value={code} height="200px" extensions={[hyperLink]} />;
27+
}
28+
export default App;
29+
```
30+
31+
```js
32+
import { EditorView } from '@codemirror/view';
33+
import { EditorState } from '@codemirror/state';
34+
import { hyperLink } from '@uiw/codemirror-extensions-hyper-link';
35+
36+
const code = `https://uiwjs.github.io/react-codemirror`;
37+
38+
const state = EditorState.create({
39+
doc: code,
40+
extensions: [hyperLink],
41+
});
42+
43+
const view = new EditorView({
44+
parent: document.querySelector('#editor'),
45+
state,
46+
});
47+
```
48+
49+
## Contributors
50+
51+
As always, thanks to our amazing contributors!
52+
53+
<a href="https://github.com/uiwjs/react-codemirror/graphs/contributors">
54+
<img src="https://uiwjs.github.io/react-codemirror/CONTRIBUTORS.svg" />
55+
</a>
56+
57+
Made with [github-action-contributors](https://github.com/jaywcjlove/github-action-contributors).
58+
59+
## License
60+
61+
Licensed under the MIT License.

extensions/hyper-link/package.json

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"name": "@uiw/codemirror-extensions-hyper-link",
3+
"version": "4.11.1",
4+
"description": "Hyper link Extensions for CodeMirror6.",
5+
"homepage": "https://uiwjs.github.io/react-codemirror/#/extensions/hyper-link",
6+
"author": "kenny wong <[email protected]>",
7+
"license": "MIT",
8+
"main": "./cjs/index.js",
9+
"module": "./esm/index.js",
10+
"scripts": {
11+
"watch": "tsbb watch",
12+
"build": "tsbb build"
13+
},
14+
"repository": {
15+
"type": "git",
16+
"url": "https://github.com/uiwjs/react-codemirror.git"
17+
},
18+
"files": [
19+
"src",
20+
"esm",
21+
"cjs"
22+
],
23+
"peerDependencies": {
24+
"@codemirror/state": ">=6.0.0",
25+
"@codemirror/view": ">=6.0.0"
26+
},
27+
"devDependencies": {
28+
"@codemirror/state": "^6.1.0",
29+
"@codemirror/view": "^6.0.0"
30+
},
31+
"keywords": [
32+
"codemirror",
33+
"codemirror6",
34+
"link",
35+
"url",
36+
"hyper-link",
37+
"extensions",
38+
"ide",
39+
"code"
40+
],
41+
"jest": {
42+
"coverageReporters": [
43+
"lcov",
44+
"json-summary"
45+
]
46+
}
47+
}

extensions/hyper-link/src/index.ts

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import { ViewPlugin, EditorView, Decoration, DecorationSet, WidgetType, ViewUpdate } from '@codemirror/view';
2+
import { Extension, Range } from '@codemirror/state';
3+
import { syntaxTree } from '@codemirror/language';
4+
5+
const pathStr = `<svg viewBox="0 0 1024 1024" width="16" height="16" fill="currentColor"><path d="M607.934444 417.856853c-6.179746-6.1777-12.766768-11.746532-19.554358-16.910135l-0.01228 0.011256c-6.986111-6.719028-16.47216-10.857279-26.930349-10.857279-21.464871 0-38.864146 17.400299-38.864146 38.864146 0 9.497305 3.411703 18.196431 9.071609 24.947182l-0.001023 0c0.001023 0.001023 0.00307 0.00307 0.005117 0.004093 2.718925 3.242857 5.953595 6.03853 9.585309 8.251941 3.664459 3.021823 7.261381 5.997598 10.624988 9.361205l3.203972 3.204995c40.279379 40.229237 28.254507 109.539812-12.024871 149.820214L371.157763 796.383956c-40.278355 40.229237-105.761766 40.229237-146.042167 0l-3.229554-3.231601c-40.281425-40.278355-40.281425-105.809861 0-145.991002l75.93546-75.909877c9.742898-7.733125 15.997346-19.668968 15.997346-33.072233 0-23.312962-18.898419-42.211381-42.211381-42.211381-8.797363 0-16.963347 2.693342-23.725354 7.297197-0.021489-0.045025-0.044002-0.088004-0.066515-0.134053l-0.809435 0.757247c-2.989077 2.148943-5.691629 4.669346-8.025791 7.510044l-78.913281 73.841775c-74.178443 74.229608-74.178443 195.632609 0 269.758863l3.203972 3.202948c74.178443 74.127278 195.529255 74.127278 269.707698 0l171.829484-171.880649c74.076112-74.17435 80.357166-191.184297 6.282077-265.311575L607.934444 417.856853z"></path><path d="M855.61957 165.804257l-3.203972-3.203972c-74.17742-74.178443-195.528232-74.178443-269.706675 0L410.87944 334.479911c-74.178443 74.178443-78.263481 181.296089-4.085038 255.522628l3.152806 3.104711c3.368724 3.367701 6.865361 6.54302 10.434653 9.588379 2.583848 2.885723 5.618974 5.355985 8.992815 7.309476 0.025583 0.020466 0.052189 0.041956 0.077771 0.062422l0.011256-0.010233c5.377474 3.092431 11.608386 4.870938 18.257829 4.870938 20.263509 0 36.68962-16.428158 36.68962-36.68962 0-5.719258-1.309832-11.132548-3.645017-15.95846l0 0c-4.850471-10.891048-13.930267-17.521049-20.210297-23.802102l-3.15383-3.102664c-40.278355-40.278355-24.982998-98.79612 15.295358-139.074476l171.930791-171.830507c40.179095-40.280402 105.685018-40.280402 145.965419 0l3.206018 3.152806c40.279379 40.281425 40.279379 105.838513 0 146.06775l-75.686796 75.737962c-10.296507 7.628748-16.97358 19.865443-16.97358 33.662681 0 23.12365 18.745946 41.87062 41.87062 41.87062 8.048303 0 15.563464-2.275833 21.944801-6.211469 0.048095 0.081864 0.093121 0.157589 0.141216 0.240477l1.173732-1.083681c3.616364-2.421142 6.828522-5.393847 9.529027-8.792247l79.766718-73.603345C929.798013 361.334535 929.798013 239.981676 855.61957 165.804257z"></path></svg>`;
6+
7+
export interface HyperLinkState {
8+
from: number;
9+
to: number;
10+
url: string;
11+
}
12+
13+
class HyperLink extends WidgetType {
14+
private readonly state: HyperLinkState;
15+
constructor({ ...state }: HyperLinkState) {
16+
super();
17+
this.state = state;
18+
}
19+
eq(other: HyperLink) {
20+
return (
21+
this.state.url === other.state.url && this.state.to === other.state.to && this.state.from === other.state.from
22+
);
23+
}
24+
toDOM() {
25+
const wrapper = document.createElement('a');
26+
wrapper.href = this.state.url;
27+
wrapper.target = '__blank';
28+
wrapper.innerHTML = pathStr;
29+
wrapper.className = 'cm-hyper-link-icon';
30+
return wrapper;
31+
}
32+
ignoreEvent() {
33+
return false;
34+
}
35+
}
36+
37+
function hyperLinkDecorations(view: EditorView) {
38+
const widgets: Array<Range<Decoration>> = [];
39+
for (const range of view.visibleRanges) {
40+
syntaxTree(view.state).iterate({
41+
from: range.from,
42+
to: range.to,
43+
enter: ({ type, node, from, to }) => {
44+
const callExp: string = view.state.doc.sliceString(from, to);
45+
if (type.name === 'URL') {
46+
const widget = Decoration.widget({
47+
widget: new HyperLink({
48+
from,
49+
to,
50+
url: callExp,
51+
}),
52+
side: 1,
53+
});
54+
widgets.push(widget.range(to));
55+
} else if (type.name === 'String') {
56+
console.log('type.name:', type.name, callExp);
57+
} else if (type.name === 'CodeText') {
58+
console.log('type.name:', type.name, callExp);
59+
} else {
60+
console.log('type.name:', type.name, callExp);
61+
}
62+
},
63+
});
64+
}
65+
return Decoration.set(widgets);
66+
}
67+
68+
export function hyperLinkExtension() {
69+
return ViewPlugin.fromClass(
70+
class HyperLinkView {
71+
decorations: DecorationSet;
72+
constructor(view: EditorView) {
73+
this.decorations = hyperLinkDecorations(view);
74+
}
75+
update(update: ViewUpdate) {
76+
if (update.docChanged || update.viewportChanged) {
77+
this.decorations = hyperLinkDecorations(update.view);
78+
}
79+
}
80+
},
81+
{
82+
decorations: (v) => v.decorations,
83+
},
84+
);
85+
}
86+
87+
export const hyperLinkStyle = EditorView.baseTheme({
88+
'.cm-hyper-link-icon': {
89+
display: 'inline-block',
90+
verticalAlign: 'middle',
91+
marginLeft: '0.2ch',
92+
},
93+
'.cm-hyper-link-icon svg': {
94+
display: 'block',
95+
},
96+
});
97+
98+
export const hyperLink: Extension = [hyperLinkExtension(), hyperLinkStyle];
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"extends": "../../tsconfig",
3+
"include": ["src"],
4+
"compilerOptions": {
5+
"outDir": "./cjs",
6+
"baseUrl": ".",
7+
"noEmit": false
8+
}
9+
}

www/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"@codemirror/legacy-modes": "~6.1.0",
4040
"@uiw/codemirror-extensions-color": "4.11.1",
4141
"@uiw/codemirror-extensions-events": "4.11.1",
42+
"@uiw/codemirror-extensions-hyper-link": "4.11.1",
4243
"@uiw/codemirror-theme-abcdef": "4.11.1",
4344
"@uiw/codemirror-theme-androidstudio": "4.11.1",
4445
"@uiw/codemirror-theme-bespin": "4.11.1",

www/src/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { ThemeOkaidia } from './pages/theme/themes';
1010
import { ExtensionsLayout } from './pages/extensions';
1111
import { EventsDoc } from './pages/extensions/events';
1212
import { LineNumbersRelativeDoc } from './pages/extensions/line-numbers-relative';
13+
import { HyperLinkDoc } from './pages/extensions/hyper-link';
1314
import { ColorDoc } from './pages/extensions/color';
1415

1516
export const GlobalStyle = createGlobalStyle`
@@ -73,6 +74,7 @@ root.render(
7374
<Route path="color" element={<ColorDoc />} />
7475
<Route path="events" element={<EventsDoc />} />
7576
<Route path="line-numbers-relative" element={<LineNumbersRelativeDoc />} />
77+
<Route path="hyper-link" element={<HyperLinkDoc />} />
7678
</Route>
7779
</Routes>
7880
</HashRouter>,

www/src/pages/extensions/datas.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import eventsMd from '@uiw/codemirror-extensions-events/README.md';
22
import colorMd from '@uiw/codemirror-extensions-color/README.md';
33
import lineNumbersRelativeMd from '@uiw/codemirror-extensions-line-numbers-relative/README.md';
4+
import hyperLinkMd from '@uiw/codemirror-extensions-hyper-link/README.md';
45

56
export const mdSource = {
67
color: colorMd.source,
78
events: eventsMd.source,
89
'line-numbers-relative': lineNumbersRelativeMd.source,
10+
'hyper-link': hyperLinkMd.source,
911
};

0 commit comments

Comments
 (0)