Skip to content

Commit

Permalink
start starry night editor
Browse files Browse the repository at this point in the history
  • Loading branch information
souporserious committed Sep 28, 2023
1 parent 9ec78cb commit 353140d
Show file tree
Hide file tree
Showing 10 changed files with 3,956 additions and 95 deletions.
5 changes: 5 additions & 0 deletions .changeset/clean-rules-relax.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"mdxts": patch
---

Add Editor based on starry-night highlighter.
2 changes: 2 additions & 0 deletions mdxts/editor/grammars/TypeScriptReact.tmLanguage.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"version": "https://github.com/microsoft/TypeScript-TmLanguage/commit/0d73d1117e0a9b1d6635ebbe9aa37d615171b02d",
"name": "TypeScriptReact",
"scopeName": "source.tsx",
"extensions": [".tsx"],
"names": ["tsx"],
"patterns": [
{
"include": "#directives"
Expand Down
3,606 changes: 3,606 additions & 0 deletions mdxts/editor/grammars/source.tsx.ts

Large diffs are not rendered by default.

166 changes: 88 additions & 78 deletions mdxts/editor/index.tsx
Original file line number Diff line number Diff line change
@@ -1,85 +1,95 @@
import * as React from 'react'
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'
import { initializeMonaco } from './initialize'
import { getTheme } from './theme'
// @ts-expect-error
import { Fragment, jsx, jsxs } from 'react/jsx-runtime'
import React, { use, useState } from 'react'
import { toJsxRuntime } from 'hast-util-to-jsx-runtime'
import { createStarryNight } from '@wooorm/starry-night'
import sourceTsx from './grammars/source.tsx'

const languageMap = {
tsx: 'typescript',
}
// import sourceCss from '@wooorm/starry-night/lang/source.css.js'
// import sourceDiff from '@wooorm/starry-night/lang/source.diff.js'
// import sourceJs from '@wooorm/starry-night/lang/source.js.js'
// import sourceJson from '@wooorm/starry-night/lang/source.json.js'
// import sourceToml from '@wooorm/starry-night/lang/source.toml.js'
// import sourceTs from '@wooorm/starry-night/lang/source.ts.js'
// import sourceTsx from '@wooorm/starry-night/lang/source.tsx'
// import sourceYaml from '@wooorm/starry-night/lang/source.yaml.js'
// import textHtmlBasic from '@wooorm/starry-night/lang/text.html.basic.js'
// import textXmlSvg from '@wooorm/starry-night/lang/text.xml.svg.js'

// const grammars = [
// sourceCss,
// sourceDiff,
// sourceJs,
// sourceJson,
// sourceToml,
// sourceTs,
// sourceTsx,
// sourceYaml,
// textHtmlBasic,
// textXmlSvg,
// ]

export default function Editor({
const starryNightPromise = createStarryNight([sourceTsx])

/** Code editor with syntax highlighting. */
export function Editor({
language = 'typescript',
scope = 'source.tsx',
defaultValue,
language: languageProp = 'typescript',
theme,
...props
value,
onChange,
}: {
defaultValue?: string
language?: string
theme?: any
scope?: string
defaultValue?: string
value: string
onChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void
}) {
const language = languageMap[languageProp] || languageProp
const id = React.useId().slice(1, -1)
const ref = React.useRef(null)

React.useLayoutEffect(() => {
try {
monaco.editor.defineTheme('mdxts', getTheme(theme))
} catch (error) {
throw new Error(
`MDXTS: Invalid theme configuration. Theme must be a valid VS Code theme.`,
{ cause: error }
)
}

const model = monaco.editor.createModel(
defaultValue,
language,
monaco.Uri.parse(`file:///${id}.index.tsx`)
)

const editor = monaco.editor.create(ref.current, {
model,
language,
theme: 'mdxts',
automaticLayout: true,
fontSize: 16,
fontFamily: 'monospace',
lineNumbers: 'off',
minimap: { enabled: false },
selectionHighlight: false,
...props,
})

monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
target: monaco.languages.typescript.ScriptTarget.ESNext,
jsx: monaco.languages.typescript.JsxEmit.ReactJSX,
jsxImportSource: monaco.languages.typescript.JsxEmit.React,
moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
module: monaco.languages.typescript.ModuleKind.ESNext,
})

const languages = [
{
id: 'css',
extensions: ['.css'],
aliases: ['CSS', 'css'],
},
{
id: 'typescript',
extensions: ['.ts', '.tsx'],
aliases: ['TypeScript', 'ts', 'typescript'],
},
]

languages.forEach((config) => monaco.languages.register(config))

initializeMonaco(theme)

return () => {
model.dispose()
editor.dispose()
}
}, [])

return <div ref={ref} style={{ height: 400 }} />
const [stateValue, setStateValue] = useState(defaultValue)
const starryNight = use(starryNightPromise)
const resolvedValue = value ?? stateValue
const sharedStyle = {
gridArea: '1 / 1',
padding: 0,
whiteSpace: 'pre-wrap',
wordWrap: 'break-word',
fontFamily: 'monospace',
fontSize: 14,
tabSize: 4,
letterSpacing: 'normal',
lineHeight: 'calc(1 * (1em + 1ex))',
} satisfies React.CSSProperties
return (
<div style={{ display: 'grid', width: '100%' }}>
<div style={sharedStyle}>
{toJsxRuntime(starryNight.highlight(resolvedValue, scope), {
jsx,
jsxs,
Fragment,
})}
{/\n[ \t]*$/.test(resolvedValue) ? <br /> : undefined}
</div>
<textarea
spellCheck="false"
className="write"
value={resolvedValue}
onChange={
defaultValue
? (event: React.ChangeEvent<HTMLTextAreaElement>) => {
setStateValue(event.target.value)
onChange?.(event)
}
: onChange
}
rows={resolvedValue.split('\n').length + 1}
style={{
...sharedStyle,
backgroundColor: 'transparent',
color: 'transparent',
caretColor: '#79c0ff',
resize: 'none',
}}
/>
</div>
)
}
2 changes: 2 additions & 0 deletions mdxts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,13 @@
"@types/github-slugger": "^2.0.0",
"@types/hast": "^3.0.0",
"@types/mdast": "^4.0.0",
"@wooorm/starry-night": "^3.0.0",
"case-anything": "^2.1.13",
"chokidar": "^3.5.3",
"color": "^4.2.3",
"copy-webpack-plugin": "^11.0.0",
"github-slugger": "^2.0.0",
"hast-util-to-jsx-runtime": "^2.2.0",
"hast-util-to-string": "^3.0.0",
"mdast-util-to-string": "^4.0.0",
"monaco-editor": "0.43.0",
Expand Down
35 changes: 33 additions & 2 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions site/docs/06.test.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import './index.css'

```tsx
/**
* Say hello.
*
* @example
* <Hello name="Penny" />
*/
function Hello({ name }: { name: string }) {
return <div>Hello, {name}</div>
}
```
Loading

0 comments on commit 353140d

Please sign in to comment.