Skip to content

Commit 48dbe9c

Browse files
committedDec 15, 2022
feat(classname): add classname extension. #433
1 parent 964bb2c commit 48dbe9c

File tree

13 files changed

+314
-1
lines changed

13 files changed

+314
-1
lines changed
 

‎.github/workflows/ci.yml

+18
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,12 @@ jobs:
250250
token: ${{ secrets.NPM_TOKEN }}
251251
package: ./extensions/basic-setup/package.json
252252

253+
- name: 📦 @uiw/codemirror-extensions-classname to NPM
254+
uses: JS-DevTools/npm-publish@v1
255+
with:
256+
token: ${{ secrets.NPM_TOKEN }}
257+
package: ./extensions/classname/package.json
258+
253259
- name: 📦 @uiw/codemirror-extensions-events to NPM
254260
uses: JS-DevTools/npm-publish@v1
255261
with:
@@ -655,6 +661,18 @@ jobs:
655661
env:
656662
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
657663

664+
- name: Modify @uiw/codemirror-extensions-classname => @uiwjs/codemirror-extensions-classname
665+
uses: jaywcjlove/github-action-package@main
666+
with:
667+
path: extensions/classname/package.json
668+
rename: "@uiwjs/codemirror-extensions-classname"
669+
670+
- run: npm publish
671+
working-directory: extensions/classname
672+
continue-on-error: true
673+
env:
674+
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
675+
658676
- name: Modify @uiw/codemirror-extensions-color => @uiwjs/codemirror-extensions-color
659677
uses: jaywcjlove/github-action-package@main
660678
with:

‎core/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ npm install @uiw/react-codemirror --save
4545
| `@uiw/react-codemirror` | [![npm version](https://img.shields.io/npm/v/@uiw/react-codemirror.svg)](https://www.npmjs.com/package/@uiw/react-codemirror) [![NPM Downloads](https://img.shields.io/npm/dm/@uiw/react-codemirror.svg?style=flat)](https://www.npmjs.com/package/@uiw/react-codemirror) | [`#preview`](https://uiwjs.github.io/react-codemirror/) |
4646
| `@uiw/codemirror-extensions-basic-setup` | [![npm version](https://img.shields.io/npm/v/@uiw/codemirror-extensions-basic-setup.svg)](https://www.npmjs.com/package/@uiw/codemirror-extensions-basic-setup) [![NPM Downloads](https://img.shields.io/npm/dm/@uiw/codemirror-extensions-basic-setup.svg?style=flat)](https://www.npmjs.com/package/@uiw/codemirror-extensions-basic-setup) | [`#preview`](https://uiwjs.github.io/react-codemirror/#/extensions/basic-setup) |
4747
| `@uiw/codemirror-extensions-color` | [![npm version](https://img.shields.io/npm/v/@uiw/codemirror-extensions-color.svg)](https://www.npmjs.com/package/@uiw/codemirror-extensions-color) [![NPM Downloads](https://img.shields.io/npm/dm/@uiw/codemirror-extensions-color.svg?style=flat)](https://www.npmjs.com/package/@uiw/codemirror-extensions-color) | [`#preview`](https://uiwjs.github.io/react-codemirror/#/extensions/color) |
48+
| `@uiw/codemirror-extensions-classname` | [![npm version](https://img.shields.io/npm/v/@uiw/codemirror-extensions-classname.svg)](https://www.npmjs.com/package/@uiw/codemirror-extensions-classname) [![NPM Downloads](https://img.shields.io/npm/dm/@uiw/codemirror-extensions-classname.svg?style=flat)](https://www.npmjs.com/package/@uiw/codemirror-extensions-classname) | [`#preview`](https://uiwjs.github.io/react-codemirror/#/extensions/classname) |
4849
| `@uiw/codemirror-extensions-events` | [![npm version](https://img.shields.io/npm/v/@uiw/codemirror-extensions-events.svg)](https://www.npmjs.com/package/@uiw/codemirror-extensions-events) [![NPM Downloads](https://img.shields.io/npm/dm/@uiw/codemirror-extensions-events.svg?style=flat)](https://www.npmjs.com/package/@uiw/codemirror-extensions-events) | [`#preview`](https://uiwjs.github.io/react-codemirror/#/extensions/events) |
4950
| `@uiw/codemirror-extensions-hyper-link` | [![npm version](https://img.shields.io/npm/v/@uiw/codemirror-extensions-hyper-link.svg)](https://www.npmjs.com/package/@uiw/codemirror-extensions-hyper-link) [![NPM Downloads](https://img.shields.io/npm/dm/@uiw/codemirror-extensions-hyper-link.svg?style=flat)](https://www.npmjs.com/package/@uiw/codemirror-extensions-hyper-link) | [`#preview`](https://uiwjs.github.io/react-codemirror/#/extensions/hyper-link) |
5051
| `@uiw/codemirror-extensions-langs` | [![npm version](https://img.shields.io/npm/v/@uiw/codemirror-extensions-langs.svg)](https://www.npmjs.com/package/@uiw/codemirror-extensions-langs) [![NPM Downloads](https://img.shields.io/npm/dm/@uiw/codemirror-extensions-langs.svg?style=flat)](https://www.npmjs.com/package/@uiw/codemirror-extensions-langs) | [`#preview`](https://uiwjs.github.io/react-codemirror/#/extensions/languages) |

‎extensions/classname/README.md

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<!--rehype:ignore:start-->
2+
3+
# Add className Extensions
4+
5+
<!--rehype:ignore:end-->
6+
7+
[![npm version](https://img.shields.io/npm/v/@uiw/codemirror-extensions-classname.svg)](https://www.npmjs.com/package/@uiw/codemirror-extensions-classname)
8+
9+
Adding a class for a specific line for CodeMirror6.
10+
11+
[![Zebra Stripes Extensions](https://user-images.githubusercontent.com/1680273/205496628-e7e6f83f-18e9-4bff-8bc8-71a913c60687.png)](https://uiwjs.github.io/react-codemirror/#/extensions/classname)
12+
13+
## Install
14+
15+
```bash
16+
npm install @uiw/codemirror-extensions-classname --save
17+
```
18+
19+
## Usage
20+
21+
```jsx
22+
import CodeMirror from '@uiw/react-codemirror';
23+
import { classname } from '@uiw/codemirror-extensions-classname';
24+
25+
const themeDemo = EditorView.baseTheme({
26+
'&dark .first-line': { backgroundColor: 'red' },
27+
'&light .first-line': { backgroundColor: 'red' },
28+
'&dark .line-color': { backgroundColor: 'blue' },
29+
'&light .line-color': { backgroundColor: 'blue' },
30+
});
31+
32+
function App() {
33+
const classnameExt = classname({
34+
add: (lineNumber) => {
35+
if (lineNumber === 1) {
36+
return 'first-line';
37+
}
38+
if (lineNumber === 5) {
39+
return 'line-color';
40+
}
41+
},
42+
});
43+
return <CodeMirror value="" height="200px" extensions={[theme, classnameExt]} />;
44+
}
45+
46+
export default App;
47+
```
48+
49+
```jsx
50+
import CodeMirror from '@uiw/react-codemirror';
51+
import { classname } from '@uiw/codemirror-extensions-classname';
52+
53+
function App() {
54+
const classnameExt = classname({
55+
add: (lineNumber) => {
56+
if (lineNumber === 1) {
57+
return 'first-line';
58+
}
59+
if (lineNumber === 5) {
60+
return 'line-color';
61+
}
62+
},
63+
});
64+
return <CodeMirror value="" height="200px" extensions={[classnameExt]} />;
65+
}
66+
export default App;
67+
```
68+
69+
```js
70+
import { EditorView } from '@codemirror/view';
71+
import { EditorState } from '@codemirror/state';
72+
import { classname } from '@uiw/codemirror-extensions-classname';
73+
74+
const classnameExt = classname({
75+
add: (lineNumber) => {
76+
if (lineNumber === 1) {
77+
return 'first-line';
78+
}
79+
if (lineNumber === 5) {
80+
return 'line-color';
81+
}
82+
},
83+
});
84+
85+
const state = EditorState.create({
86+
doc: 'my source code',
87+
extensions: [classnameExt],
88+
});
89+
90+
const view = new EditorView({
91+
parent: document.querySelector('#editor'),
92+
state,
93+
});
94+
```
95+
96+
## API
97+
98+
```ts
99+
import { Extension } from '@codemirror/state';
100+
export declare type ClassnameOptions = {
101+
add?: (lineNumber: number) => string | undefined;
102+
};
103+
export declare function classname(options?: ClassnameOptions): Extension;
104+
```
105+
106+
## Contributors
107+
108+
As always, thanks to our amazing contributors!
109+
110+
<a href="https://github.com/uiwjs/react-codemirror/graphs/contributors">
111+
<img src="https://uiwjs.github.io/react-codemirror/CONTRIBUTORS.svg" />
112+
</a>
113+
114+
Made with [github-action-contributors](https://github.com/jaywcjlove/github-action-contributors).
115+
116+
## License
117+
118+
Licensed under the MIT License.

‎extensions/classname/package.json

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"name": "@uiw/codemirror-extensions-classname",
3+
"version": "4.19.3",
4+
"description": "Adding a class for a specific line for CodeMirror6.",
5+
"homepage": "https://uiwjs.github.io/react-codemirror/#/extensions/classname",
6+
"author": "kenny wong <wowohoo@qq.com>",
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+
"classname",
35+
"extensions",
36+
"ide",
37+
"code"
38+
],
39+
"jest": {
40+
"coverageReporters": [
41+
"lcov",
42+
"json-summary"
43+
]
44+
}
45+
}

‎extensions/classname/src/index.ts

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { Extension } from '@codemirror/state';
2+
import { RangeSetBuilder } from '@codemirror/state';
3+
import { EditorView, Decoration, ViewPlugin, DecorationSet, ViewUpdate } from '@codemirror/view';
4+
5+
function stripeDeco(view: EditorView, opts: ClassnameOptions) {
6+
const builder = new RangeSetBuilder<Decoration>();
7+
for (let { from, to } of view.visibleRanges) {
8+
for (let pos = from; pos <= to; ) {
9+
let line = view.state.doc.lineAt(pos);
10+
if (opts.add && typeof opts.add === 'function') {
11+
const cls = opts.add(line.number);
12+
if (cls && typeof cls === 'string') {
13+
const attributes = { class: cls } as Record<string, string>;
14+
builder.add(
15+
line.from,
16+
line.from,
17+
Decoration.line({
18+
attributes,
19+
}),
20+
);
21+
}
22+
}
23+
pos = line.to + 1;
24+
}
25+
}
26+
return builder.finish();
27+
}
28+
29+
export type ClassnameOptions = {
30+
add?: (lineNumber: number) => string | undefined;
31+
};
32+
33+
export function classname(options: ClassnameOptions = {}): Extension {
34+
return ViewPlugin.fromClass(
35+
class {
36+
decorations: DecorationSet;
37+
constructor(view: EditorView) {
38+
this.decorations = stripeDeco(view, options);
39+
}
40+
update(update: ViewUpdate) {
41+
if (update.docChanged || update.viewportChanged) {
42+
this.decorations = stripeDeco(update.view, options);
43+
}
44+
}
45+
},
46+
{
47+
decorations: (v) => v.decorations,
48+
},
49+
);
50+
}

‎extensions/classname/tsconfig.json

+9
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+
}

‎extensions/zebra-stripes/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export default App;
5353
```js
5454
import { EditorView } from '@codemirror/view';
5555
import { EditorState } from '@codemirror/state';
56-
import { mentions } from '@uiw/codemirror-zebra-stripes';
56+
import { zebraStripes } from '@uiw/codemirror-zebra-stripes';
5757

5858
const state = EditorState.create({
5959
doc: 'my source code',

‎www/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"@codemirror/language-data": "^6.1.0",
3939
"@codemirror/legacy-modes": "~6.3.0",
4040
"@uiw/codemirror-extensions-color": "4.19.3",
41+
"@uiw/codemirror-extensions-classname": "4.19.3",
4142
"@uiw/codemirror-extensions-events": "4.19.3",
4243
"@uiw/codemirror-extensions-hyper-link": "4.19.3",
4344
"@uiw/codemirror-extensions-langs": "4.19.3",

‎www/src/index.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { LangsDoc } from './pages/extensions/langs';
1515
import { HyperLinkDoc } from './pages/extensions/hyper-link';
1616
import { BasicSetupDoc } from './pages/extensions/basic-setup';
1717
import { ColorDoc } from './pages/extensions/color';
18+
import { ClassNameDoc } from './pages/extensions/classname';
1819
import { MentionsDoc } from './pages/extensions/mentions';
1920
import { ThemesAllDoc } from './pages/extensions/themes';
2021
import { ZebraStripesDoc } from './pages/extensions/zebra-stripes';
@@ -87,6 +88,7 @@ root.render(
8788
<Route path="themes-all" element={<ThemesAllDoc />} />
8889
<Route path="basic-setup" element={<BasicSetupDoc />} />
8990
<Route path="color" element={<ColorDoc />} />
91+
<Route path="classname" element={<ClassNameDoc />} />
9092
<Route path="events" element={<EventsDoc />} />
9193
<Route path="line-numbers-relative" element={<LineNumbersRelativeDoc />} />
9294
<Route path="languages" element={<LangsDoc />} />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import data from '@uiw/codemirror-extensions-classname/README.md';
2+
import { classname } from '@uiw/codemirror-extensions-classname';
3+
import CodeMirror from '@uiw/react-codemirror';
4+
import { langs } from '@uiw/codemirror-extensions-langs';
5+
import { EditorView } from '@codemirror/view';
6+
import { useTheme } from '../../../utils/useTheme';
7+
8+
export const ClassNameDemo = () => {
9+
const theme = useTheme();
10+
11+
const themeDemo = EditorView.baseTheme({
12+
'&dark .first-line': { backgroundColor: 'red' },
13+
'&light .first-line': { backgroundColor: 'red' },
14+
'&dark .line-color': { backgroundColor: 'blue' },
15+
'&light .line-color': { backgroundColor: 'blue' },
16+
});
17+
18+
return (
19+
<CodeMirror
20+
value={data.source}
21+
theme={theme}
22+
height="300px"
23+
style={{ margin: '0 0 23px 0' }}
24+
extensions={[
25+
langs.markdown(),
26+
themeDemo,
27+
classname({
28+
add: (lineNumber) => {
29+
if (lineNumber === 3) {
30+
return 'first-line';
31+
}
32+
if (lineNumber === 5) {
33+
return 'line-color';
34+
}
35+
},
36+
}),
37+
]}
38+
/>
39+
);
40+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import MarkdownPreview from '@uiw/react-markdown-preview';
2+
import data from '@uiw/codemirror-extensions-classname/README.md';
3+
import { PageWarpper } from '../';
4+
import { ClassNameDemo } from './ClassNameDemo';
5+
6+
export const ClassNameDoc = () => {
7+
return (
8+
<PageWarpper>
9+
<ClassNameDemo />
10+
<MarkdownPreview source={data.source} />
11+
</PageWarpper>
12+
);
13+
};

‎www/src/pages/extensions/datas.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import eventsMd from '@uiw/codemirror-extensions-events/README.md';
22
import basicSetupMd from '@uiw/codemirror-extensions-basic-setup/README.md';
33
import colorMd from '@uiw/codemirror-extensions-color/README.md';
4+
import classnameMd from '@uiw/codemirror-extensions-classname/README.md';
45
import lineNumbersRelativeMd from '@uiw/codemirror-extensions-line-numbers-relative/README.md';
56
import langsMd from '@uiw/codemirror-extensions-langs/README.md';
67
import themesAllMd from '@uiw/codemirror-themes-all/README.md';
@@ -10,6 +11,7 @@ import zebraStripesMd from '@uiw/codemirror-extensions-zebra-stripes/README.md';
1011

1112
export const mdSource = {
1213
color: basicSetupMd.source,
14+
classname: classnameMd.source,
1315
'basic-setup': colorMd.source,
1416
events: eventsMd.source,
1517
'themes-all': themesAllMd.source,

‎www/src/utils/useTheme.tsx

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { useEffect, useState } from 'react';
2+
import { ReactCodeMirrorProps } from '@uiw/react-codemirror';
3+
4+
export function useTheme() {
5+
const dark = document.documentElement.getAttribute('data-color-mode');
6+
const [theme, setTheme] = useState<ReactCodeMirrorProps['theme']>(dark === 'dark' ? 'dark' : 'light');
7+
useEffect(() => {
8+
setTheme(document.documentElement.getAttribute('data-color-mode') === 'dark' ? 'dark' : 'light');
9+
document.addEventListener('colorschemechange', (e) => {
10+
setTheme(e.detail.colorScheme as ReactCodeMirrorProps['theme']);
11+
});
12+
}, []);
13+
return theme;
14+
}

0 commit comments

Comments
 (0)
Please sign in to comment.