Skip to content

Commit

Permalink
add MonacoDiffEditor
Browse files Browse the repository at this point in the history
  • Loading branch information
alxnddr committed Oct 9, 2023
1 parent 88c2750 commit 02f4fcb
Show file tree
Hide file tree
Showing 14 changed files with 509 additions and 29 deletions.
64 changes: 57 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ yarn add solid-monaco
pnpm add solid-monaco
```

## MonacoEditor

Basic usage:

You can import and use the `MonacoEditor` component in your Solid application:
Expand All @@ -32,7 +34,7 @@ function MyEditor() {
}
```

## Props
### Props

The `MonacoEditor` component accepts the following props:

Expand All @@ -44,15 +46,16 @@ The `MonacoEditor` component accepts the following props:
| `class` | `string` | - | CSS class for the editor container. |
| `theme` | `BuiltinTheme` or `string` | `"vs"` | The theme to be applied to the editor. |
| `path` | `string` | `""` | Path used for Monaco model management for multiple files. |
| `overrideServices` | `editor.IEditorOverrideServices` | - | Services to override the default ones provided by Monaco. |
| `overrideServices` | `object` | - | Services to override the default ones provided by Monaco. |
| `width` | `string` | `"100%"` | Width of the editor container. |
| `height` | `string` | `"100%"` | Height of the editor container. |
| `options` | `editor.IStandaloneEditorConstructionOptions` | - | Additional options for the Monaco editor. |
| `options` | `object` | - | Additional options for the Monaco editor. |
| `saveViewState` | `string` | `true` | Whether to save the model view state for a given path of the editor. |
| `onChange` | `(value: string, event: editor.IModelContentChangedEvent) => void` | - | Callback triggered when the content of the editor changes. |
| `onMount` | `(monaco: Monaco, editor: editor.IStandaloneCodeEditor) => void` | - | Callback triggered when the editor mounts. |
| `onBeforeUnmount` | `(monaco: Monaco, editor: editor.IStandaloneCodeEditor) => void` | - | Callback triggered before the editor unmounts. |

## Getting Monaco and Editor Instances
### Getting Monaco and Editor Instances

You can get instances of both `monaco` and the `editor` by using the `onMount` callback:

Expand All @@ -74,15 +77,62 @@ function MyEditor() {
}
```

## MonacoDiffEditor

For a side-by-side comparison view of code, the package provides a `MonacoDiffEditor` component.

### Basic Usage

You can incorporate the `MonacoDiffEditor` component into your Solid application:

```jsx
import { MonacoDiffEditor } from 'solid-monaco';

function MyDiffEditor() {
return (
<MonacoDiffEditor
original="const foo = 1;"
modified="const foo = 2;"
originalLanguage="javascript"
modifiedLanguage="javascript"
/>
);
}
```

### Props

The `MonacoDiffEditor` component accepts the following props:

| Prop | Type | Default | Description |
|--------------------|------------------------------------------------------------------|--------------|------------------------------------------------------------------------|
| `original` | `string` | - | Original content to be displayed on the left side of the diff editor. |
| `modified` | `string` | - | Modified content to be displayed on the right side of the diff editor. |
| `originalLanguage` | `string` | - | Language for the original content. |
| `modifiedLanguage` | `string` | - | Language for the modified content. |
| `originalPath` | `string` | - | Path for the original content used in Monaco model management. |
| `modifiedPath` | `string` | - | Path for the modified content used in Monaco model management. |
| `loadingState` | `JSX.Element` | `"Loading…"` | JSX element displayed during the loading state. |
| `class` | `string` | - | CSS class for the diff editor container. |
| `theme` | `BuiltinTheme` or `string` | `"vs"` | Theme applied to the diff editor. |
| `overrideServices` | `object` | - | Services to override the default ones provided by Monaco. |
| `width` | `string` | `"100%"` | Width of the diff editor container. |
| `height` | `string` | `"100%"` | Height of the diff editor container. |
| `options` | `object` | - | Additional options for the Monaco diff editor. |
| `saveViewState` | `boolean` | `true` | Whether to save the model view state. |
| `onChange` | `(value: string) => void` | - | Callback triggered when the content of the modified editor changes. |
| `onMount` | `(monaco: Monaco, editor: editor.IStandaloneDiffEditor) => void` | - | Callback triggered when the diff editor mounts. |
| `onBeforeUnmount` | `(monaco: Monaco, editor: editor.IStandaloneDiffEditor) => void` | - | Callback triggered before the diff editor unmounts. |

## Contributing

Contributions to `solid-monaco` are welcomed!

## Acknowledgments

Special thanks to the [monaco-react](https://github.com/suren-atoyan/monaco-react) package
by [Suren Atoyan](https://github.com/suren-atoyan). The package has been an invaluable reference in the development for
the Solid.js community.
- [monaco-editor](https://github.com/microsoft/monaco-editor): The core editor that this package wraps for Solid.js.
- [monaco-react](https://github.com/suren-atoyan/monaco-react) by [Suren Atoyan](https://github.com/suren-atoyan): A
package referred to during the development of the solid-monaco wrapper.

## License

Expand Down
29 changes: 29 additions & 0 deletions dev/App.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,34 @@
padding: 1rem 1.5rem;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #dddde5;
}

.nav {
display: flex;
gap: 1rem;
border-radius: 4px;
font-size: 14px;
}

.navItem {
text-decoration: none;
color: #333;
transition: all 0.3s ease;
font-size: 14px;
display: inline-block;
padding: 8px 12px;
border-radius: 4px;
}

.navItem:hover {
background-color: #007BFF;
color: #FFFFFF;
}

.navItemActive {
background-color: #c8e3ff;
}


27 changes: 22 additions & 5 deletions dev/App.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
import type { Component } from 'solid-js'
import styles from './App.module.css'
import { MonacoPlayground } from './MonacoPlayground'
import { MonacoDiffPlayground } from './MonacoDiffPlayground'
import { A, Route, Router, Routes } from '@solidjs/router'

const App: Component = () => {
return (
<div class={styles.root}>
<div class={styles.header}>solid-monaco playground</div>
<div class={styles.editorContainer}>
<MonacoPlayground />
<Router>
<div class={styles.root}>
<div class={styles.header}>
solid-monaco playground
<div class={styles.nav}>
<A href="/" class={styles.navItem} activeClass={styles.navItemActive} end>
Editor
</A>
<A href="/diff" class={styles.navItem} activeClass={styles.navItemActive} end>
Diff Editor
</A>
</div>
</div>
<div class={styles.editorContainer}>
<Routes>
<Route path="/" component={MonacoPlayground} />
<Route path="/diff" component={MonacoDiffPlayground} />
</Routes>
</div>
</div>
</div>
</Router>
)
}

Expand Down
56 changes: 56 additions & 0 deletions dev/MonacoDiffPlayground.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { createSignal, JSX } from 'solid-js'
import { MonacoDiffEditor } from '../src'

import styles from './MonacoPlayground.module.css'
import { exampleData } from './example-data'

const builtinThemes = ['vs', 'vs-dark', 'hc-light', 'hc-black'] as const

export const MonacoDiffPlayground = () => {
const [theme, setTheme] = createSignal<string>(builtinThemes[0])
const [modified, setModified] = createSignal<string>(exampleData[0].content)
const [original, setOriginal] = createSignal<string>(exampleData[0].content)
const [language, setLanguage] = createSignal<string>(exampleData[0].language)

const handleThemeChange: JSX.EventHandler<HTMLSelectElement, Event> = e => {
setTheme(e.currentTarget.value)
}

const handleLanguageChange: JSX.EventHandler<HTMLSelectElement, Event> = e => {
const sampleContent = exampleData.find(data => data.language === e.currentTarget.value)
if (!sampleContent) {
return
}

setLanguage(sampleContent.language)
setModified(sampleContent.content)
setOriginal(sampleContent.content)
}

return (
<div class={styles.root}>
<div class={styles.settings}>
<select name="theme" onChange={handleThemeChange}>
{builtinThemes.map(theme => (
<option value={theme}>{theme}</option>
))}
</select>

<select name="language" onChange={handleLanguageChange}>
{exampleData.map(data => (
<option value={data.language}>{data.language}</option>
))}
</select>
</div>
<MonacoDiffEditor
options={{ padding: { top: 24 } }}
originalLanguage={language()}
modifiedLanguage={language()}
theme={theme()}
onChange={setModified}
modified={modified()}
original={original()}
/>
</div>
)
}
3 changes: 3 additions & 0 deletions dev/MonacoPlayground.module.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
.root {
height: 100%;
display: flex;
flex-direction: column;
}

.settings {
display: flex;
gap: 1rem;
padding: 1rem 2rem;
}

1 change: 1 addition & 0 deletions dev/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,4 @@ select option:hover,
select option:active {
background-color: #f0f0f0;
}

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "solid-monaco",
"version": "0.1.0",
"version": "0.2.0",
"description": "Monaco Editor for SolidJS",
"license": "MIT",
"author": "Aleksandr Lesnenko",
Expand Down Expand Up @@ -56,6 +56,7 @@
"solid-js": "^1.6.0"
},
"devDependencies": {
"@solidjs/router": "^0.8.3",
"@typescript-eslint/eslint-plugin": "^6.1.0",
"@typescript-eslint/parser": "^6.1.0",
"concurrently": "^8.2.0",
Expand Down
13 changes: 12 additions & 1 deletion 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 src/MonacoDiffEditor.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { createRoot } from 'solid-js'
import { describe, expect, it } from 'vitest'
import { MonacoDiffEditor } from '../src'

// TODO: add real tests
describe('MonacoDiffEditor', () => {
it('renders a MonacoDiffEditor component', async () => {
createRoot(() => {
const container = (<MonacoDiffEditor />) as HTMLDivElement
expect(container.outerHTML).toMatchSnapshot()
})
})
})
Loading

0 comments on commit 02f4fcb

Please sign in to comment.