Skip to content

Commit bdb7e9a

Browse files
committedDec 4, 2022
feat: add zebra-stripes component. #424
1 parent 7bd0ed7 commit bdb7e9a

File tree

11 files changed

+359
-1
lines changed

11 files changed

+359
-1
lines changed
 

‎.github/workflows/ci.yml

+20
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,12 @@ jobs:
237237
token: ${{ secrets.NPM_TOKEN }}
238238
package: ./extensions/mentions/package.json
239239

240+
- name: 📦 @uiw/codemirror-extensions-zebra-stripes to NPM
241+
uses: JS-DevTools/npm-publish@v1
242+
with:
243+
token: ${{ secrets.NPM_TOKEN }}
244+
package: ./extensions/zebra-stripes/package.json
245+
240246
outputs:
241247
successful: ${{steps.create_tag.outputs.successful }}
242248

@@ -579,3 +585,17 @@ jobs:
579585
if: success() || failure()
580586
env:
581587
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
588+
589+
590+
- name: Modify @uiw/codemirror-extensions-zebra-stripes => @uiwjs/codemirror-extensions-zebra-stripes
591+
uses: jaywcjlove/github-action-package@main
592+
if: success() || failure()
593+
with:
594+
path: extensions/zebra-stripes/package.json
595+
rename: "@uiwjs/codemirror-extensions-zebra-stripes"
596+
597+
- run: npm publish
598+
working-directory: extensions/zebra-stripes
599+
if: success() || failure()
600+
env:
601+
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}

‎core/README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ npm install @uiw/react-codemirror --save
4141
**All Packages**
4242

4343
| Name | NPM Version | Website |
44-
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
44+
| :------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
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) |
@@ -50,6 +50,7 @@ npm install @uiw/react-codemirror --save
5050
| `@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) |
5151
| `@uiw/codemirror-extensions-line-numbers-relative` | [![npm version](https://img.shields.io/npm/v/@uiw/codemirror-extensions-line-numbers-relative.svg)](https://www.npmjs.com/package/@uiw/codemirror-extensions-line-numbers-relative) [![NPM Downloads](https://img.shields.io/npm/dm/@uiw/codemirror-extensions-line-numbers-relative.svg?style=flat)](https://www.npmjs.com/package/@uiw/codemirror-extensions-line-numbers-relative) | [`#preview`](https://uiwjs.github.io/react-codemirror/#/extensions/line-numbers-relative) |
5252
| `@uiw/codemirror-extensions-mentions` | [![npm version](https://img.shields.io/npm/v/@uiw/codemirror-extensions-mentions.svg)](https://www.npmjs.com/package/@uiw/codemirror-extensions-mentions) [![NPM Downloads](https://img.shields.io/npm/dm/@uiw/codemirror-extensions-mentions.svg?style=flat)](https://www.npmjs.com/package/@uiw/codemirror-extensions-mentions) | [`#preview`](https://uiwjs.github.io/react-codemirror/#/extensions/mentions) |
53+
| `@uiw/codemirror-extensions-zebra-stripes` | [![npm version](https://img.shields.io/npm/v/@uiw/codemirror-extensions-zebra-stripes.svg)](https://www.npmjs.com/package/@uiw/codemirror-extensions-zebra-stripes) [![NPM Downloads](https://img.shields.io/npm/dm/@uiw/codemirror-extensions-zebra-stripes.svg?style=flat)](https://www.npmjs.com/package/@uiw/codemirror-extensions-zebra-stripes) | [`#preview`](https://uiwjs.github.io/react-codemirror/#/extensions/mentions) |
5354
| `@uiw/codemirror-themes` | [![npm version](https://img.shields.io/npm/v/@uiw/codemirror-themes.svg)](https://www.npmjs.com/package/@uiw/codemirror-themes) [![NPM Downloads](https://img.shields.io/npm/dm/@uiw/codemirror-themes.svg?style=flat)](https://www.npmjs.com/package/@uiw/codemirror-themes) | [`#preview`](https://uiwjs.github.io/react-codemirror/#/theme/doc) |
5455
| `@uiw/codemirror-themes-all` | [![npm version](https://img.shields.io/npm/v/@uiw/codemirror-themes-all.svg)](https://www.npmjs.com/package/@uiw/codemirror-themes-all) [![NPM Downloads](https://img.shields.io/npm/dm/@uiw/codemirror-themes-all.svg?style=flat)](https://www.npmjs.com/package/@uiw/codemirror-themes-all) | [`#preview`](https://uiwjs.github.io/react-codemirror/#/theme/all) |
5556
| `@uiw/codemirror-theme-abcdef` | [![npm version](https://img.shields.io/npm/v/@uiw/codemirror-theme-abcdef.svg)](https://www.npmjs.com/package/@uiw/codemirror-theme-abcdef) [![NPM Downloads](https://img.shields.io/npm/dm/@uiw/codemirror-theme-abcdef.svg?style=flat)](https://www.npmjs.com/package/@uiw/codemirror-theme-abcdef) | [`#preview`](https://uiwjs.github.io/react-codemirror/#/theme/data/abcdef) |

‎extensions/zebra-stripes/README.md

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<!--rehype:ignore:start-->
2+
3+
# Zebra Stripes Extensions
4+
5+
<!--rehype:ignore:end-->
6+
7+
[![npm version](https://img.shields.io/npm/v/@uiw/codemirror-extensions-mentions.svg)](https://www.npmjs.com/package/@uiw/codemirror-extensions-mentions)
8+
9+
Styles alternating lines 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/mentions)
12+
13+
## Install
14+
15+
```bash
16+
npm install @uiw/codemirror-zebra-stripes --save
17+
```
18+
19+
## Usage
20+
21+
```jsx
22+
import CodeMirror from '@uiw/react-codemirror';
23+
import { zebraStripes } from '@uiw/codemirror-zebra-stripes';
24+
25+
function App() {
26+
return <CodeMirror value="" height="200px" extensions={[zebraStripes({ step: 2 })]} />;
27+
}
28+
export default App;
29+
```
30+
31+
```jsx
32+
import CodeMirror from '@uiw/react-codemirror';
33+
import { zebraStripes } from '@uiw/codemirror-zebra-stripes';
34+
35+
function App() {
36+
return (
37+
<CodeMirror
38+
value=""
39+
height="200px"
40+
extensions={[
41+
zebraStripes({
42+
lineNumber: [1, [3, 6], 10],
43+
lightColor: '#aca2ff33',
44+
darkColor: '#aca2ff40',
45+
}),
46+
]}
47+
/>
48+
);
49+
}
50+
export default App;
51+
```
52+
53+
```js
54+
import { EditorView } from '@codemirror/view';
55+
import { EditorState } from '@codemirror/state';
56+
import { mentions } from '@uiw/codemirror-zebra-stripes';
57+
58+
const state = EditorState.create({
59+
doc: 'my source code',
60+
extensions: [zebraStripes({ step: 2 })],
61+
});
62+
63+
const view = new EditorView({
64+
parent: document.querySelector('#editor'),
65+
state,
66+
});
67+
```
68+
69+
## API
70+
71+
```ts
72+
import { Extension } from '@codemirror/state';
73+
export declare type ZebraStripesOptions = {
74+
step?: number | null;
75+
lightColor?: string;
76+
darkColor?: string;
77+
/**
78+
* @example `[1,[2,6], 10]`
79+
*/
80+
lineNumber?: (number | number[])[] | null;
81+
};
82+
export declare function zebraStripes(options?: ZebraStripesOptions): Extension;
83+
```
84+
85+
## Contributors
86+
87+
As always, thanks to our amazing contributors!
88+
89+
<a href="https://github.com/uiwjs/react-codemirror/graphs/contributors">
90+
<img src="https://uiwjs.github.io/react-codemirror/CONTRIBUTORS.svg" />
91+
</a>
92+
93+
Made with [github-action-contributors](https://github.com/jaywcjlove/github-action-contributors).
94+
95+
## License
96+
97+
Licensed under the MIT License.

‎extensions/zebra-stripes/package.json

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"name": "@uiw/codemirror-extensions-zebra-stripes",
3+
"version": "4.15.1",
4+
"description": "Styles alternating lines for CodeMirror6.",
5+
"homepage": "https://uiwjs.github.io/react-codemirror/#/extensions/zebra-stripes",
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+
"zebra-stripes",
35+
"extensions",
36+
"ide",
37+
"code"
38+
],
39+
"jest": {
40+
"coverageReporters": [
41+
"lcov",
42+
"json-summary"
43+
]
44+
}
45+
}

‎extensions/zebra-stripes/src/index.ts

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { Extension } from '@codemirror/state';
2+
import { Facet, RangeSetBuilder } from '@codemirror/state';
3+
import { EditorView, Decoration, ViewPlugin, DecorationSet, ViewUpdate } from '@codemirror/view';
4+
5+
const lineNumber = Facet.define({
6+
combine: (values) => {
7+
return values.length && Array.isArray(values) ? values.flat() : [];
8+
},
9+
});
10+
11+
const stepSize = Facet.define({
12+
combine: (values) => {
13+
return values.length && Array.isArray(values) ? Math.min(...values) : 2;
14+
},
15+
});
16+
17+
const stripe = Decoration.line({
18+
attributes: { class: 'cm-zebra-stripe' },
19+
});
20+
21+
function stripeDeco(view: EditorView) {
22+
const step = view.state.facet(stepSize);
23+
const num = view.state.facet(lineNumber);
24+
const builder = new RangeSetBuilder<Decoration>();
25+
for (let { from, to } of view.visibleRanges) {
26+
for (let pos = from; pos <= to; ) {
27+
let line = view.state.doc.lineAt(pos);
28+
29+
if (line.number % step === 0 && num.length === 0) {
30+
builder.add(line.from, line.from, stripe);
31+
}
32+
if (num.length > 0 && num.flat().includes(line.number)) {
33+
builder.add(line.from, line.from, stripe);
34+
}
35+
pos = line.to + 1;
36+
}
37+
}
38+
return builder.finish();
39+
}
40+
41+
const showStripes = ViewPlugin.fromClass(
42+
class {
43+
decorations: DecorationSet;
44+
constructor(view: EditorView) {
45+
this.decorations = stripeDeco(view);
46+
}
47+
48+
update(update: ViewUpdate) {
49+
this.decorations = stripeDeco(update.view);
50+
// if (update.docChanged || update.viewportChanged) {
51+
// this.decorations = stripeDeco(update.view);
52+
// }
53+
}
54+
},
55+
{
56+
decorations: (v) => v.decorations,
57+
},
58+
);
59+
60+
const baseTheme = (opt: Pick<Partial<ZebraStripesOptions>, 'lightColor' | 'darkColor'> = {}) => {
61+
return EditorView.baseTheme({
62+
'&light .cm-zebra-stripe': { backgroundColor: opt.lightColor || '#eef6ff' },
63+
'&dark .cm-zebra-stripe': { backgroundColor: opt.darkColor || '#3a404d' },
64+
});
65+
};
66+
67+
export type ZebraStripesOptions = {
68+
step?: number | null;
69+
lightColor?: string;
70+
darkColor?: string;
71+
/**
72+
* @example `[1,[2,6], 10]`
73+
*/
74+
lineNumber?: (number | number[])[] | null;
75+
};
76+
77+
const range = (start: number, stop: number, step: number) =>
78+
Array.from({ length: (stop - start) / step + 1 }, (_, i) => start + i * step);
79+
80+
export function zebraStripes(options: ZebraStripesOptions = {}): Extension {
81+
const zebraStripeTheme = baseTheme({ lightColor: options.lightColor, darkColor: options.darkColor });
82+
if (options.lineNumber && Array.isArray(options.lineNumber)) {
83+
options.step = null;
84+
options.lineNumber = options.lineNumber.map((item) => {
85+
if (Array.isArray(item) && typeof item[0] === 'number' && typeof item[1] === 'number') {
86+
return range(item[0], item[1], 1);
87+
}
88+
return item;
89+
});
90+
} else {
91+
options.lineNumber = null;
92+
}
93+
return [
94+
options.lineNumber === null ? [] : lineNumber.of(options.lineNumber || []),
95+
options.step === null ? [] : stepSize.of(options.step || 2),
96+
showStripes,
97+
zebraStripeTheme,
98+
];
99+
}
+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+
}

‎www/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"@uiw/codemirror-extensions-hyper-link": "4.15.1",
4343
"@uiw/codemirror-extensions-langs": "4.15.1",
4444
"@uiw/codemirror-extensions-mentions": "4.15.1",
45+
"@uiw/codemirror-extensions-zebra-stripes": "4.15.1",
4546
"@uiw/codemirror-theme-abcdef": "4.15.1",
4647
"@uiw/codemirror-theme-androidstudio": "4.15.1",
4748
"@uiw/codemirror-theme-atomone": "4.15.1",

‎www/src/index.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { BasicSetupDoc } from './pages/extensions/basic-setup';
1616
import { ColorDoc } from './pages/extensions/color';
1717
import { MentionsDoc } from './pages/extensions/mentions';
1818
import { ThemesAllDoc } from './pages/extensions/themes';
19+
import { ZebraStripesDoc } from './pages/extensions/zebra-stripes';
1920

2021
export const GlobalStyle = createGlobalStyle`
2122
[data-color-mode*='dark'], [data-color-mode*='dark'] body {
@@ -83,6 +84,7 @@ root.render(
8384
<Route path="languages" element={<LangsDoc />} />
8485
<Route path="hyper-link" element={<HyperLinkDoc />} />
8586
<Route path="mentions" element={<MentionsDoc />} />
87+
<Route path="zebra-stripes" element={<ZebraStripesDoc />} />
8688
</Route>
8789
</Routes>
8890
</HashRouter>,

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

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import langsMd from '@uiw/codemirror-extensions-langs/README.md';
66
import themesAllMd from '@uiw/codemirror-themes-all/README.md';
77
import hyperLinkMd from '@uiw/codemirror-extensions-hyper-link/README.md';
88
import mentionsMd from '@uiw/codemirror-extensions-mentions/README.md';
9+
import zebraStripesMd from '@uiw/codemirror-extensions-zebra-stripes/README.md';
910

1011
export const mdSource = {
1112
color: basicSetupMd.source,
@@ -16,4 +17,5 @@ export const mdSource = {
1617
languages: langsMd.source,
1718
'hyper-link': hyperLinkMd.source,
1819
mentions: mentionsMd.source,
20+
'zebra-stripes': zebraStripesMd.source,
1921
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import data from '@uiw/codemirror-extensions-zebra-stripes/README.md';
2+
import { zebraStripes } from '@uiw/codemirror-extensions-zebra-stripes';
3+
import CodeMirror, { ReactCodeMirrorProps } from '@uiw/react-codemirror';
4+
import { useEffect, useState } from 'react';
5+
import { langs } from '@uiw/codemirror-extensions-langs';
6+
7+
export const LineNumberDemo = () => {
8+
const dark = document.documentElement.getAttribute('data-color-mode');
9+
const [theme, setTheme] = useState<ReactCodeMirrorProps['theme']>(dark === 'dark' ? 'dark' : 'light');
10+
useEffect(() => {
11+
setTheme(document.documentElement.getAttribute('data-color-mode') === 'dark' ? 'dark' : 'light');
12+
document.addEventListener('colorschemechange', (e) => {
13+
setTheme(e.detail.colorScheme as ReactCodeMirrorProps['theme']);
14+
});
15+
}, []);
16+
17+
return (
18+
<CodeMirror
19+
value={data.source}
20+
theme={theme}
21+
height="300px"
22+
style={{ margin: '0 0 23px 0' }}
23+
extensions={[
24+
langs.markdown(),
25+
zebraStripes({ lineNumber: [1, [3, 6], 10], lightColor: '#aca2ff33', darkColor: '#aca2ff40' }),
26+
]}
27+
/>
28+
);
29+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import MarkdownPreview from '@uiw/react-markdown-preview';
2+
import data from '@uiw/codemirror-extensions-zebra-stripes/README.md';
3+
import { zebraStripes } from '@uiw/codemirror-extensions-zebra-stripes';
4+
import CodeMirror, { ReactCodeMirrorProps } from '@uiw/react-codemirror';
5+
import { useEffect, useState } from 'react';
6+
import { langs } from '@uiw/codemirror-extensions-langs';
7+
import styled from 'styled-components';
8+
import { PageWarpper } from '../';
9+
import { LineNumberDemo } from './LineNumberDemo';
10+
11+
const OptionsView = styled.div`
12+
padding-bottom: 24px;
13+
display: flex;
14+
gap: 18px;
15+
`;
16+
17+
export const ZebraStripesDoc = () => {
18+
const dark = document.documentElement.getAttribute('data-color-mode');
19+
const [theme, setTheme] = useState<ReactCodeMirrorProps['theme']>(dark === 'dark' ? 'dark' : 'light');
20+
useEffect(() => {
21+
setTheme(document.documentElement.getAttribute('data-color-mode') === 'dark' ? 'dark' : 'light');
22+
document.addEventListener('colorschemechange', (e) => {
23+
setTheme(e.detail.colorScheme as ReactCodeMirrorProps['theme']);
24+
});
25+
}, []);
26+
27+
const [step, setStep] = useState(2);
28+
29+
const zebra = zebraStripes({ step: step });
30+
return (
31+
<PageWarpper>
32+
<CodeMirror
33+
value={data.source}
34+
theme={theme}
35+
height="300px"
36+
style={{ margin: '0 0 23px 0' }}
37+
extensions={[langs.markdown(), zebra]}
38+
/>
39+
<OptionsView>
40+
<select value={step} onChange={(evn) => setStep(Number(evn.target.value))}>
41+
<option value={1}>1</option>
42+
<option value={2}>2</option>
43+
<option value={3}>3</option>
44+
<option value={4}>4</option>
45+
<option value={5}>5</option>
46+
<option value={6}>6</option>
47+
</select>
48+
</OptionsView>
49+
<LineNumberDemo />
50+
<MarkdownPreview source={data.source} />
51+
</PageWarpper>
52+
);
53+
};

0 commit comments

Comments
 (0)
Please sign in to comment.