Skip to content

Commit

Permalink
feat: add zebra-stripes component. #424
Browse files Browse the repository at this point in the history
  • Loading branch information
jaywcjlove committed Dec 4, 2022
1 parent 7bd0ed7 commit bdb7e9a
Show file tree
Hide file tree
Showing 11 changed files with 359 additions and 1 deletion.
20 changes: 20 additions & 0 deletions .github/workflows/ci.yml
Expand Up @@ -237,6 +237,12 @@ jobs:
token: ${{ secrets.NPM_TOKEN }}
package: ./extensions/mentions/package.json

- name: 📦 @uiw/codemirror-extensions-zebra-stripes to NPM
uses: JS-DevTools/npm-publish@v1
with:
token: ${{ secrets.NPM_TOKEN }}
package: ./extensions/zebra-stripes/package.json

outputs:
successful: ${{steps.create_tag.outputs.successful }}

Expand Down Expand Up @@ -579,3 +585,17 @@ jobs:
if: success() || failure()
env:
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}


- name: Modify @uiw/codemirror-extensions-zebra-stripes => @uiwjs/codemirror-extensions-zebra-stripes
uses: jaywcjlove/github-action-package@main
if: success() || failure()
with:
path: extensions/zebra-stripes/package.json
rename: "@uiwjs/codemirror-extensions-zebra-stripes"

- run: npm publish
working-directory: extensions/zebra-stripes
if: success() || failure()
env:
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
3 changes: 2 additions & 1 deletion core/README.md
Expand Up @@ -41,7 +41,7 @@ npm install @uiw/react-codemirror --save
**All Packages**

| Name | NPM Version | Website |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| :------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| `@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/) |
| `@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) |
| `@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) |
Expand All @@ -50,6 +50,7 @@ npm install @uiw/react-codemirror --save
| `@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) |
| `@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) |
| `@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) |
| `@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) |
| `@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) |
| `@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) |
| `@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) |
Expand Down
97 changes: 97 additions & 0 deletions extensions/zebra-stripes/README.md
@@ -0,0 +1,97 @@
<!--rehype:ignore:start-->

# Zebra Stripes Extensions

<!--rehype:ignore:end-->

[![npm version](https://img.shields.io/npm/v/@uiw/codemirror-extensions-mentions.svg)](https://www.npmjs.com/package/@uiw/codemirror-extensions-mentions)

Styles alternating lines for CodeMirror6.

[![Zebra Stripes Extensions](https://user-images.githubusercontent.com/1680273/205496628-e7e6f83f-18e9-4bff-8bc8-71a913c60687.png)](https://uiwjs.github.io/react-codemirror/#/extensions/mentions)

## Install

```bash
npm install @uiw/codemirror-zebra-stripes --save
```

## Usage

```jsx
import CodeMirror from '@uiw/react-codemirror';
import { zebraStripes } from '@uiw/codemirror-zebra-stripes';

function App() {
return <CodeMirror value="" height="200px" extensions={[zebraStripes({ step: 2 })]} />;
}
export default App;
```

```jsx
import CodeMirror from '@uiw/react-codemirror';
import { zebraStripes } from '@uiw/codemirror-zebra-stripes';

function App() {
return (
<CodeMirror
value=""
height="200px"
extensions={[
zebraStripes({
lineNumber: [1, [3, 6], 10],
lightColor: '#aca2ff33',
darkColor: '#aca2ff40',
}),
]}
/>
);
}
export default App;
```

```js
import { EditorView } from '@codemirror/view';
import { EditorState } from '@codemirror/state';
import { mentions } from '@uiw/codemirror-zebra-stripes';

const state = EditorState.create({
doc: 'my source code',
extensions: [zebraStripes({ step: 2 })],
});

const view = new EditorView({
parent: document.querySelector('#editor'),
state,
});
```

## API

```ts
import { Extension } from '@codemirror/state';
export declare type ZebraStripesOptions = {
step?: number | null;
lightColor?: string;
darkColor?: string;
/**
* @example `[1,[2,6], 10]`
*/
lineNumber?: (number | number[])[] | null;
};
export declare function zebraStripes(options?: ZebraStripesOptions): Extension;
```

## Contributors

As always, thanks to our amazing contributors!

<a href="https://github.com/uiwjs/react-codemirror/graphs/contributors">
<img src="https://uiwjs.github.io/react-codemirror/CONTRIBUTORS.svg" />
</a>

Made with [github-action-contributors](https://github.com/jaywcjlove/github-action-contributors).

## License

Licensed under the MIT License.
45 changes: 45 additions & 0 deletions extensions/zebra-stripes/package.json
@@ -0,0 +1,45 @@
{
"name": "@uiw/codemirror-extensions-zebra-stripes",
"version": "4.15.1",
"description": "Styles alternating lines for CodeMirror6.",
"homepage": "https://uiwjs.github.io/react-codemirror/#/extensions/zebra-stripes",
"author": "kenny wong <wowohoo@qq.com>",
"license": "MIT",
"main": "./cjs/index.js",
"module": "./esm/index.js",
"scripts": {
"watch": "tsbb watch",
"build": "tsbb build"
},
"repository": {
"type": "git",
"url": "https://github.com/uiwjs/react-codemirror.git"
},
"files": [
"src",
"esm",
"cjs"
],
"peerDependencies": {
"@codemirror/state": ">=6.0.0",
"@codemirror/view": ">=6.0.0"
},
"devDependencies": {
"@codemirror/state": "^6.1.0",
"@codemirror/view": "^6.0.0"
},
"keywords": [
"codemirror",
"codemirror6",
"zebra-stripes",
"extensions",
"ide",
"code"
],
"jest": {
"coverageReporters": [
"lcov",
"json-summary"
]
}
}
99 changes: 99 additions & 0 deletions extensions/zebra-stripes/src/index.ts
@@ -0,0 +1,99 @@
import { Extension } from '@codemirror/state';
import { Facet, RangeSetBuilder } from '@codemirror/state';
import { EditorView, Decoration, ViewPlugin, DecorationSet, ViewUpdate } from '@codemirror/view';

const lineNumber = Facet.define({
combine: (values) => {
return values.length && Array.isArray(values) ? values.flat() : [];
},
});

const stepSize = Facet.define({
combine: (values) => {
return values.length && Array.isArray(values) ? Math.min(...values) : 2;
},
});

const stripe = Decoration.line({
attributes: { class: 'cm-zebra-stripe' },
});

function stripeDeco(view: EditorView) {
const step = view.state.facet(stepSize);
const num = view.state.facet(lineNumber);
const builder = new RangeSetBuilder<Decoration>();
for (let { from, to } of view.visibleRanges) {
for (let pos = from; pos <= to; ) {
let line = view.state.doc.lineAt(pos);

if (line.number % step === 0 && num.length === 0) {
builder.add(line.from, line.from, stripe);
}
if (num.length > 0 && num.flat().includes(line.number)) {
builder.add(line.from, line.from, stripe);
}
pos = line.to + 1;
}
}
return builder.finish();
}

const showStripes = ViewPlugin.fromClass(
class {
decorations: DecorationSet;
constructor(view: EditorView) {
this.decorations = stripeDeco(view);
}

update(update: ViewUpdate) {
this.decorations = stripeDeco(update.view);
// if (update.docChanged || update.viewportChanged) {
// this.decorations = stripeDeco(update.view);
// }
}
},
{
decorations: (v) => v.decorations,
},
);

const baseTheme = (opt: Pick<Partial<ZebraStripesOptions>, 'lightColor' | 'darkColor'> = {}) => {
return EditorView.baseTheme({
'&light .cm-zebra-stripe': { backgroundColor: opt.lightColor || '#eef6ff' },
'&dark .cm-zebra-stripe': { backgroundColor: opt.darkColor || '#3a404d' },
});
};

export type ZebraStripesOptions = {
step?: number | null;
lightColor?: string;
darkColor?: string;
/**
* @example `[1,[2,6], 10]`
*/
lineNumber?: (number | number[])[] | null;
};

const range = (start: number, stop: number, step: number) =>
Array.from({ length: (stop - start) / step + 1 }, (_, i) => start + i * step);

export function zebraStripes(options: ZebraStripesOptions = {}): Extension {
const zebraStripeTheme = baseTheme({ lightColor: options.lightColor, darkColor: options.darkColor });
if (options.lineNumber && Array.isArray(options.lineNumber)) {
options.step = null;
options.lineNumber = options.lineNumber.map((item) => {
if (Array.isArray(item) && typeof item[0] === 'number' && typeof item[1] === 'number') {
return range(item[0], item[1], 1);
}
return item;
});
} else {
options.lineNumber = null;
}
return [
options.lineNumber === null ? [] : lineNumber.of(options.lineNumber || []),
options.step === null ? [] : stepSize.of(options.step || 2),
showStripes,
zebraStripeTheme,
];
}
9 changes: 9 additions & 0 deletions extensions/zebra-stripes/tsconfig.json
@@ -0,0 +1,9 @@
{
"extends": "../../tsconfig",
"include": ["src"],
"compilerOptions": {
"outDir": "./cjs",
"baseUrl": ".",
"noEmit": false
}
}
1 change: 1 addition & 0 deletions www/package.json
Expand Up @@ -42,6 +42,7 @@
"@uiw/codemirror-extensions-hyper-link": "4.15.1",
"@uiw/codemirror-extensions-langs": "4.15.1",
"@uiw/codemirror-extensions-mentions": "4.15.1",
"@uiw/codemirror-extensions-zebra-stripes": "4.15.1",
"@uiw/codemirror-theme-abcdef": "4.15.1",
"@uiw/codemirror-theme-androidstudio": "4.15.1",
"@uiw/codemirror-theme-atomone": "4.15.1",
Expand Down
2 changes: 2 additions & 0 deletions www/src/index.tsx
Expand Up @@ -16,6 +16,7 @@ import { BasicSetupDoc } from './pages/extensions/basic-setup';
import { ColorDoc } from './pages/extensions/color';
import { MentionsDoc } from './pages/extensions/mentions';
import { ThemesAllDoc } from './pages/extensions/themes';
import { ZebraStripesDoc } from './pages/extensions/zebra-stripes';

export const GlobalStyle = createGlobalStyle`
[data-color-mode*='dark'], [data-color-mode*='dark'] body {
Expand Down Expand Up @@ -83,6 +84,7 @@ root.render(
<Route path="languages" element={<LangsDoc />} />
<Route path="hyper-link" element={<HyperLinkDoc />} />
<Route path="mentions" element={<MentionsDoc />} />
<Route path="zebra-stripes" element={<ZebraStripesDoc />} />
</Route>
</Routes>
</HashRouter>,
Expand Down
2 changes: 2 additions & 0 deletions www/src/pages/extensions/datas.tsx
Expand Up @@ -6,6 +6,7 @@ import langsMd from '@uiw/codemirror-extensions-langs/README.md';
import themesAllMd from '@uiw/codemirror-themes-all/README.md';
import hyperLinkMd from '@uiw/codemirror-extensions-hyper-link/README.md';
import mentionsMd from '@uiw/codemirror-extensions-mentions/README.md';
import zebraStripesMd from '@uiw/codemirror-extensions-zebra-stripes/README.md';

export const mdSource = {
color: basicSetupMd.source,
Expand All @@ -16,4 +17,5 @@ export const mdSource = {
languages: langsMd.source,
'hyper-link': hyperLinkMd.source,
mentions: mentionsMd.source,
'zebra-stripes': zebraStripesMd.source,
};
29 changes: 29 additions & 0 deletions www/src/pages/extensions/zebra-stripes/LineNumberDemo.tsx
@@ -0,0 +1,29 @@
import data from '@uiw/codemirror-extensions-zebra-stripes/README.md';
import { zebraStripes } from '@uiw/codemirror-extensions-zebra-stripes';
import CodeMirror, { ReactCodeMirrorProps } from '@uiw/react-codemirror';
import { useEffect, useState } from 'react';
import { langs } from '@uiw/codemirror-extensions-langs';

export const LineNumberDemo = () => {
const dark = document.documentElement.getAttribute('data-color-mode');
const [theme, setTheme] = useState<ReactCodeMirrorProps['theme']>(dark === 'dark' ? 'dark' : 'light');
useEffect(() => {
setTheme(document.documentElement.getAttribute('data-color-mode') === 'dark' ? 'dark' : 'light');
document.addEventListener('colorschemechange', (e) => {
setTheme(e.detail.colorScheme as ReactCodeMirrorProps['theme']);
});
}, []);

return (
<CodeMirror
value={data.source}
theme={theme}
height="300px"
style={{ margin: '0 0 23px 0' }}
extensions={[
langs.markdown(),
zebraStripes({ lineNumber: [1, [3, 6], 10], lightColor: '#aca2ff33', darkColor: '#aca2ff40' }),
]}
/>
);
};

0 comments on commit bdb7e9a

Please sign in to comment.