This commit is contained in:
Nathan Bierema 2025-06-16 22:32:01 -04:00
parent 37637f7d3a
commit c11cb47aa5
4 changed files with 132 additions and 124 deletions

View File

@ -42,13 +42,14 @@
},
"dependencies": {
"@babel/runtime": "^7.27.1",
"@codemirror/lang-javascript": "^6.2.4",
"@codemirror/view": "^6.37.2",
"@rjsf/core": "^5.24.10",
"@rjsf/utils": "^5.24.10",
"@rjsf/validator-ajv8": "^5.24.10",
"@types/codemirror": "^5.60.15",
"@types/json-schema": "^7.0.15",
"@types/simple-element-resize-detector": "^1.3.3",
"codemirror": "^6.0.1",
"@uiw/react-codemirror": "^4.23.13",
"color": "^5.0.0",
"react-base16-styling": "workspace:^",
"react-icons": "^5.5.0",

View File

@ -24,14 +24,12 @@ export const Default: Story = {
args: {
value,
lineNumbers: true,
lineWrapping: false,
foldGutter: true,
readOnly: false,
autofocus: true,
},
argTypes: {
autofocus: { control: { disable: true } },
mode: { control: { disable: true } },
theme: { control: { disable: true } },
onChange: { control: { disable: true } },
},
@ -45,8 +43,6 @@ export const WithTabs: StoryObj<WithTabsProps> = {
},
argTypes: {
value: { control: { disable: true } },
mode: { control: { disable: true } },
lineWrapping: { control: { disable: true } },
readOnly: { control: { disable: true } },
theme: { control: { disable: true } },
foldGutter: { control: { disable: true } },

View File

@ -1,18 +1,11 @@
import React, { Component } from 'react';
import React from 'react';
import styled from '@emotion/styled';
import CodeMirror, { EditorChange } from 'codemirror';
import CodeMirror from '@uiw/react-codemirror';
import { javascript } from '@codemirror/lang-javascript';
import type { Base16Theme } from 'react-base16-styling';
import { defaultStyle, themedStyle } from './styles';
import { Theme } from '../themes/default';
import 'codemirror/mode/javascript/javascript';
import 'codemirror/addon/fold/foldgutter';
import 'codemirror/addon/fold/foldcode';
import 'codemirror/addon/fold/brace-fold';
import '../../fonts/index.css';
import 'codemirror/lib/codemirror.css';
import 'codemirror/addon/fold/foldgutter.css';
import type { ViewUpdate } from '@codemirror/view';
const EditorContainer = styled.div(
'' as unknown as TemplateStringsArray,
@ -24,85 +17,33 @@ const EditorContainer = styled.div(
export interface EditorProps {
value: string;
mode: string;
lineNumbers: boolean;
lineWrapping: boolean;
readOnly: boolean;
lineNumbers?: boolean;
readOnly?: boolean;
theme?: Base16Theme;
foldGutter: boolean;
autofocus: boolean;
onChange?: (value: string, change: EditorChange) => void;
foldGutter?: boolean;
autofocus?: boolean;
onChange?: (value: string, viewUpdate: ViewUpdate) => void;
}
/**
* Based on [CodeMirror](http://codemirror.net/).
*/
export default class Editor extends Component<EditorProps> {
cm?: CodeMirror.Editor | null;
node?: HTMLDivElement | null;
componentDidMount() {
this.cm = CodeMirror(this.node!, {
value: this.props.value,
mode: this.props.mode,
lineNumbers: this.props.lineNumbers,
lineWrapping: this.props.lineWrapping,
readOnly: this.props.readOnly,
autofocus: this.props.autofocus,
foldGutter: this.props.foldGutter,
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
});
if (this.props.onChange) {
this.cm.on('change', (doc, change) => {
this.props.onChange!(doc.getValue(), change);
});
}
}
UNSAFE_componentWillReceiveProps(nextProps: EditorProps) {
if (nextProps.value !== this.cm!.getValue()) {
this.cm!.setValue(nextProps.value);
}
if (nextProps.readOnly !== this.props.readOnly) {
this.cm!.setOption('readOnly', nextProps.readOnly);
}
if (nextProps.lineNumbers !== this.props.lineNumbers) {
this.cm!.setOption('lineNumbers', nextProps.lineNumbers);
}
if (nextProps.lineWrapping !== this.props.lineWrapping) {
this.cm!.setOption('lineWrapping', nextProps.lineWrapping);
}
if (nextProps.foldGutter !== this.props.foldGutter) {
this.cm!.setOption('foldGutter', nextProps.foldGutter);
}
}
shouldComponentUpdate() {
return false;
}
componentWillUnmount() {
const node = this.node!;
node.removeChild(node.children[0]);
this.cm = null;
}
getRef: React.RefCallback<HTMLDivElement> = (node) => {
this.node = node;
};
render() {
return <EditorContainer ref={this.getRef} theme={this.props.theme} />;
}
static defaultProps = {
value: '',
mode: 'javascript',
lineNumbers: true,
lineWrapping: false,
readOnly: false,
foldGutter: true,
autofocus: false,
};
export default function Editor({
value,
lineNumbers = true,
readOnly = false,
foldGutter = true,
autofocus = false,
onChange,
}: EditorProps) {
return (
<CodeMirror
value={value}
extensions={[javascript()]}
onChange={onChange}
readOnly={readOnly}
autoFocus={autofocus}
basicSetup={{
lineNumbers,
foldGutter,
}}
/>
);
}

View File

@ -2357,6 +2357,12 @@ importers:
'@babel/runtime':
specifier: ^7.27.1
version: 7.27.1
'@codemirror/lang-javascript':
specifier: ^6.2.4
version: 6.2.4
'@codemirror/view':
specifier: ^6.37.2
version: 6.37.2
'@rjsf/core':
specifier: ^5.24.10
version: 5.24.10(@rjsf/utils@5.24.10(react@19.1.0))(react@19.1.0)
@ -2366,18 +2372,15 @@ importers:
'@rjsf/validator-ajv8':
specifier: ^5.24.10
version: 5.24.10(@rjsf/utils@5.24.10(react@19.1.0))
'@types/codemirror':
specifier: ^5.60.15
version: 5.60.15
'@types/json-schema':
specifier: ^7.0.15
version: 7.0.15
'@types/simple-element-resize-detector':
specifier: ^1.3.3
version: 1.3.3
codemirror:
specifier: ^6.0.1
version: 6.0.1
'@uiw/react-codemirror':
specifier: ^4.23.13
version: 4.23.13(@babel/runtime@7.27.1)(@codemirror/autocomplete@6.18.6)(@codemirror/language@6.11.0)(@codemirror/lint@6.8.5)(@codemirror/search@6.5.11)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.37.2)(codemirror@6.0.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
color:
specifier: ^5.0.0
version: 5.0.0
@ -3543,6 +3546,9 @@ packages:
'@codemirror/commands@6.8.1':
resolution: {integrity: sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==}
'@codemirror/lang-javascript@6.2.4':
resolution: {integrity: sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==}
'@codemirror/language@6.11.0':
resolution: {integrity: sha512-A7+f++LodNNc1wGgoRDTt78cOwWm9KVezApgjOMp1W4hM0898nsqBXwF+sbePE7ZRcjN7Sa1Z5m2oN27XkmEjQ==}
@ -3555,8 +3561,11 @@ packages:
'@codemirror/state@6.5.2':
resolution: {integrity: sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==}
'@codemirror/view@6.37.1':
resolution: {integrity: sha512-Qy4CAUwngy/VQkEz0XzMKVRcckQuqLYWKqVpDDDghBe5FSXSqfVrJn49nw3ePZHxRUz4nRmb05Lgi+9csWo4eg==}
'@codemirror/theme-one-dark@6.1.2':
resolution: {integrity: sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==}
'@codemirror/view@6.37.2':
resolution: {integrity: sha512-XD3LdgQpxQs5jhOOZ2HRVT+Rj59O4Suc7g2ULvZ+Yi8eCkickrkZ5JFuoDhs2ST1mNI5zSsNYgR3NGa4OUrbnw==}
'@cspotcode/source-map-support@0.8.1':
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
@ -4092,6 +4101,9 @@ packages:
'@lezer/highlight@1.2.1':
resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==}
'@lezer/javascript@1.5.1':
resolution: {integrity: sha512-ATOImjeVJuvgm3JQ/bpo2Tmv55HSScE2MTPnKRMRIPx2cLhHGyX2VnqpHhtIV1tVzIjZDbcWQm+NCTF40ggZVw==}
'@lezer/lr@1.4.2':
resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==}
@ -4614,9 +4626,6 @@ packages:
'@types/chrome@0.0.323':
resolution: {integrity: sha512-ipiDwx41lmGeLnbiT6ENOayvWXdkqKqNwqDQWEuz6dujaX7slSkk1nbSt5Q5c6xnQ708+kuCFrC00VLltSbWVA==}
'@types/codemirror@5.60.15':
resolution: {integrity: sha512-dTOvwEQ+ouKJ/rE9LT1Ue2hmP6H1mZv5+CCnNWu2qtiOe2LQa9lCprEY20HxiDmV/Bxh+dXjywmy5aKvoGjULA==}
'@types/color-convert@2.0.4':
resolution: {integrity: sha512-Ub1MmDdyZ7mX//g25uBAoH/mWGd9swVbt8BseymnaE18SU4po/PjmCrHxqIIRjBo3hV/vh1KGr0eMxUhp+t+dQ==}
@ -4972,9 +4981,6 @@ packages:
'@types/supertest@6.0.3':
resolution: {integrity: sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==}
'@types/tern@0.23.9':
resolution: {integrity: sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==}
'@types/tough-cookie@4.0.5':
resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==}
@ -5055,6 +5061,28 @@ packages:
resolution: {integrity: sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@uiw/codemirror-extensions-basic-setup@4.23.13':
resolution: {integrity: sha512-U1CnDFpq6ydNqrRDS5Bdnvgso8ezwwbrmKvmAD3hmoVyRDsDU6HTtmcV+w0rZ3kElUCkKI5lY0DMvTTQ4+L3RQ==}
peerDependencies:
'@codemirror/autocomplete': '>=6.0.0'
'@codemirror/commands': '>=6.0.0'
'@codemirror/language': '>=6.0.0'
'@codemirror/lint': '>=6.0.0'
'@codemirror/search': '>=6.0.0'
'@codemirror/state': '>=6.0.0'
'@codemirror/view': '>=6.0.0'
'@uiw/react-codemirror@4.23.13':
resolution: {integrity: sha512-y65ULzxOAfpxrA/8epoAOeCfmJXu9z0P62BbGOkITJTtU7WI59KfPbbwj35npSsMAkAmDE841qZo2I8jst/THg==}
peerDependencies:
'@babel/runtime': '>=7.11.0'
'@codemirror/state': '>=6.0.0'
'@codemirror/theme-one-dark': '>=6.0.0'
'@codemirror/view': '>=6.0.0'
codemirror: '>=6.0.0'
react: '>=16.8.0'
react-dom: '>=16.8.0'
'@vitest/expect@3.0.9':
resolution: {integrity: sha512-5eCqRItYgIML7NNVgJj6TVCmdzE7ZVgJhruW0ziSQV4V7PvLkDL1bBkBdcTs/VuIz0IxPb5da1IDSqc1TR9eig==}
@ -11290,20 +11318,30 @@ snapshots:
dependencies:
'@codemirror/language': 6.11.0
'@codemirror/state': 6.5.2
'@codemirror/view': 6.37.1
'@codemirror/view': 6.37.2
'@lezer/common': 1.2.3
'@codemirror/commands@6.8.1':
dependencies:
'@codemirror/language': 6.11.0
'@codemirror/state': 6.5.2
'@codemirror/view': 6.37.1
'@codemirror/view': 6.37.2
'@lezer/common': 1.2.3
'@codemirror/lang-javascript@6.2.4':
dependencies:
'@codemirror/autocomplete': 6.18.6
'@codemirror/language': 6.11.0
'@codemirror/lint': 6.8.5
'@codemirror/state': 6.5.2
'@codemirror/view': 6.37.2
'@lezer/common': 1.2.3
'@lezer/javascript': 1.5.1
'@codemirror/language@6.11.0':
dependencies:
'@codemirror/state': 6.5.2
'@codemirror/view': 6.37.1
'@codemirror/view': 6.37.2
'@lezer/common': 1.2.3
'@lezer/highlight': 1.2.1
'@lezer/lr': 1.4.2
@ -11312,20 +11350,27 @@ snapshots:
'@codemirror/lint@6.8.5':
dependencies:
'@codemirror/state': 6.5.2
'@codemirror/view': 6.37.1
'@codemirror/view': 6.37.2
crelt: 1.0.6
'@codemirror/search@6.5.11':
dependencies:
'@codemirror/state': 6.5.2
'@codemirror/view': 6.37.1
'@codemirror/view': 6.37.2
crelt: 1.0.6
'@codemirror/state@6.5.2':
dependencies:
'@marijn/find-cluster-break': 1.0.2
'@codemirror/view@6.37.1':
'@codemirror/theme-one-dark@6.1.2':
dependencies:
'@codemirror/language': 6.11.0
'@codemirror/state': 6.5.2
'@codemirror/view': 6.37.2
'@lezer/highlight': 1.2.1
'@codemirror/view@6.37.2':
dependencies:
'@codemirror/state': 6.5.2
crelt: 1.0.6
@ -11938,6 +11983,12 @@ snapshots:
dependencies:
'@lezer/common': 1.2.3
'@lezer/javascript@1.5.1':
dependencies:
'@lezer/common': 1.2.3
'@lezer/highlight': 1.2.1
'@lezer/lr': 1.4.2
'@lezer/lr@1.4.2':
dependencies:
'@lezer/common': 1.2.3
@ -12477,10 +12528,6 @@ snapshots:
'@types/filesystem': 0.0.36
'@types/har-format': 1.2.16
'@types/codemirror@5.60.15':
dependencies:
'@types/tern': 0.23.9
'@types/color-convert@2.0.4':
dependencies:
'@types/color-name': 1.1.5
@ -12894,10 +12941,6 @@ snapshots:
'@types/methods': 1.1.4
'@types/superagent': 8.1.9
'@types/tern@0.23.9':
dependencies:
'@types/estree': 1.0.7
'@types/tough-cookie@4.0.5': {}
'@types/use-sync-external-store@0.0.6': {}
@ -13006,6 +13049,33 @@ snapshots:
'@typescript-eslint/types': 8.32.1
eslint-visitor-keys: 4.2.0
'@uiw/codemirror-extensions-basic-setup@4.23.13(@codemirror/autocomplete@6.18.6)(@codemirror/commands@6.8.1)(@codemirror/language@6.11.0)(@codemirror/lint@6.8.5)(@codemirror/search@6.5.11)(@codemirror/state@6.5.2)(@codemirror/view@6.37.2)':
dependencies:
'@codemirror/autocomplete': 6.18.6
'@codemirror/commands': 6.8.1
'@codemirror/language': 6.11.0
'@codemirror/lint': 6.8.5
'@codemirror/search': 6.5.11
'@codemirror/state': 6.5.2
'@codemirror/view': 6.37.2
'@uiw/react-codemirror@4.23.13(@babel/runtime@7.27.1)(@codemirror/autocomplete@6.18.6)(@codemirror/language@6.11.0)(@codemirror/lint@6.8.5)(@codemirror/search@6.5.11)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.37.2)(codemirror@6.0.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
'@babel/runtime': 7.27.1
'@codemirror/commands': 6.8.1
'@codemirror/state': 6.5.2
'@codemirror/theme-one-dark': 6.1.2
'@codemirror/view': 6.37.2
'@uiw/codemirror-extensions-basic-setup': 4.23.13(@codemirror/autocomplete@6.18.6)(@codemirror/commands@6.8.1)(@codemirror/language@6.11.0)(@codemirror/lint@6.8.5)(@codemirror/search@6.5.11)(@codemirror/state@6.5.2)(@codemirror/view@6.37.2)
codemirror: 6.0.1
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
transitivePeerDependencies:
- '@codemirror/autocomplete'
- '@codemirror/language'
- '@codemirror/lint'
- '@codemirror/search'
'@vitest/expect@3.0.9':
dependencies:
'@vitest/spy': 3.0.9
@ -14249,7 +14319,7 @@ snapshots:
'@codemirror/lint': 6.8.5
'@codemirror/search': 6.5.11
'@codemirror/state': 6.5.2
'@codemirror/view': 6.37.1
'@codemirror/view': 6.37.2
collect-v8-coverage@1.0.2: {}