├── apps └── demo │ ├── .gitignore │ ├── src │ ├── Comp.tsx │ ├── index.tsx │ ├── CodeMirror1.tsx │ ├── CodeMirror2.tsx │ └── App.tsx │ ├── tsconfig.json │ ├── vite.config.ts │ ├── index.html │ ├── package.json │ └── README.md ├── packages ├── codemirror │ ├── src │ │ ├── index.ts │ │ ├── utils │ │ │ ├── index.ts │ │ │ ├── createTheme.ts │ │ │ ├── createExtensions.ts │ │ │ ├── createWrapLine.ts │ │ │ ├── createLineNumbers.ts │ │ │ └── createReadOnly.ts │ │ └── CodeMirror.tsx │ ├── setupVitest.ts │ ├── rollup.config.ts │ ├── tsconfig.json │ ├── test │ │ ├── createLineNumbers.test.tsx │ │ ├── __snapshots__ │ │ │ └── CodeMirror.test.tsx.snap │ │ ├── createReadOnly.test.tsx │ │ └── CodeMirror.test.tsx │ ├── vitest.config.ts │ ├── LICENSE.md │ ├── CHANGELOG.md │ ├── package.json │ └── README.md └── core │ ├── src │ ├── index.ts │ ├── types.ts │ └── createCodeMirror.ts │ ├── rollup.config.ts │ ├── tsconfig.json │ ├── CHANGELOG.md │ ├── vitest.config.ts │ ├── LICENSE.md │ ├── package.json │ ├── test │ └── createCodeMirror.test.tsx │ └── README.md ├── pnpm-workspace.yaml ├── .gitignore ├── .changeset └── config.json ├── turbo.json ├── package.json ├── .github └── workflows │ └── release.yml ├── LICENSE.md └── README.md /apps/demo/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /packages/codemirror/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./CodeMirror"; 2 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "packages/*" 3 | - "apps/*" 4 | -------------------------------------------------------------------------------- /packages/codemirror/setupVitest.ts: -------------------------------------------------------------------------------- 1 | import "@testing-library/jest-dom"; 2 | -------------------------------------------------------------------------------- /apps/demo/src/Comp.tsx: -------------------------------------------------------------------------------- 1 | export default () => { 2 | return

Hello world!!!

; 3 | }; 4 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./createCodeMirror"; 2 | export * from "./types"; 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | .turbo 4 | *.log 5 | .next 6 | dist 7 | dist-ssr 8 | *.local 9 | .env 10 | .cache 11 | server/dist 12 | public/dist 13 | .turbo -------------------------------------------------------------------------------- /apps/demo/src/index.tsx: -------------------------------------------------------------------------------- 1 | /* @refresh reload */ 2 | import { render } from 'solid-js/web'; 3 | 4 | import App from './App'; 5 | 6 | render(() => , document.getElementById('root') as HTMLElement); 7 | -------------------------------------------------------------------------------- /packages/core/rollup.config.ts: -------------------------------------------------------------------------------- 1 | import withSolid from "rollup-preset-solid"; 2 | 3 | export default withSolid([ 4 | { 5 | input: "src/index.ts", 6 | targets: ["esm", "cjs"], 7 | }, 8 | ]); 9 | -------------------------------------------------------------------------------- /packages/codemirror/rollup.config.ts: -------------------------------------------------------------------------------- 1 | import withSolid from "rollup-preset-solid"; 2 | 3 | export default withSolid([ 4 | { 5 | input: "src/index.ts", 6 | targets: ["esm", "cjs"], 7 | }, 8 | ]); 9 | -------------------------------------------------------------------------------- /packages/codemirror/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./createLineNumbers"; 2 | export * from "./createReadOnly"; 3 | export * from "./createWrapLine"; 4 | export * from "./createExtensions"; 5 | export * from "./createTheme"; 6 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.0.0/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "public", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": ["@solid-codemirror/demo"] 11 | } 12 | -------------------------------------------------------------------------------- /apps/demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "node", 6 | "allowSyntheticDefaultImports": true, 7 | "esModuleInterop": true, 8 | "jsx": "preserve", 9 | "jsxImportSource": "solid-js", 10 | "types": ["vite/client"], 11 | "noEmit": true, 12 | "isolatedModules": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "pipeline": { 3 | "build": { 4 | "outputs": ["dist/**"], 5 | "dependsOn": ["^build"] 6 | }, 7 | "test": { 8 | "outputs": ["coverage/**"], 9 | "dependsOn": [] 10 | }, 11 | "lint": { 12 | "outputs": [] 13 | }, 14 | "dev": { 15 | "cache": false 16 | }, 17 | "clean": { 18 | "cache": false 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /apps/demo/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import solidPlugin from "vite-plugin-solid"; 3 | 4 | export default defineConfig({ 5 | plugins: [solidPlugin()], 6 | build: { 7 | target: "esnext", 8 | polyfillDynamicImport: false, 9 | }, 10 | optimizeDeps: { 11 | // Add both @codemirror/state and @codemirror/view to included deps to optimize 12 | include: ["@codemirror/state", "@codemirror/view"], 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /packages/core/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { EditorView } from "@codemirror/view"; 2 | 3 | export interface CodeMirrorProps { 4 | /** 5 | * The initial value of the editor. 6 | */ 7 | value?: string; 8 | /** 9 | * Called whenever the editor code value changes. 10 | */ 11 | onValueChange?: (value: string) => void; 12 | /** 13 | * Called when the editor first mounts, receiving the current EditorView instance. 14 | */ 15 | onEditorMount?: (editor: EditorView) => void; 16 | } 17 | -------------------------------------------------------------------------------- /apps/demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Solid CodeMirror 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "commonjs", 5 | "allowSyntheticDefaultImports": true, 6 | "esModuleInterop": true, 7 | "declaration": true, 8 | "moduleResolution": "node", 9 | "declarationDir": "./types", 10 | "emitDeclarationOnly": true, 11 | "strict": true, 12 | "jsx": "preserve", 13 | "resolveJsonModule": true, 14 | "jsxImportSource": "solid-js" 15 | }, 16 | "include": ["src", "test"], 17 | "exclude": ["node_modules", "dist"] 18 | } 19 | -------------------------------------------------------------------------------- /packages/codemirror/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "commonjs", 5 | "allowSyntheticDefaultImports": true, 6 | "esModuleInterop": true, 7 | "declaration": true, 8 | "moduleResolution": "node", 9 | "declarationDir": "./types", 10 | "emitDeclarationOnly": true, 11 | "strict": true, 12 | "jsx": "preserve", 13 | "resolveJsonModule": true, 14 | "jsxImportSource": "solid-js" 15 | }, 16 | "include": ["src", "test"], 17 | "exclude": ["node_modules", "dist"] 18 | } 19 | -------------------------------------------------------------------------------- /packages/core/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @solid-codemirror/core 2 | 3 | ## 1.0.1 4 | 5 | ### Patch Changes 6 | 7 | - Set `@codemirror/state` and `@codemirror/view` as dev dependencies 8 | 9 | ## 1.0.0 10 | 11 | ### Major Changes 12 | 13 | - - Add an optional `onEditorMount` prop to `createCodeMirror` function 14 | 15 | ## 0.0.4 16 | 17 | ### Patch Changes 18 | 19 | - Add tests for `createCodeMirror` function 20 | 21 | ## 0.0.1 22 | 23 | ### Patch Changes 24 | 25 | - 9ae1cce: Add `createCodeMirror` primitive that creates a CodeMirror view object from the supplied ref 26 | -------------------------------------------------------------------------------- /packages/core/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | import solid from "vite-plugin-solid"; 3 | 4 | export default defineConfig({ 5 | test: { 6 | environment: "jsdom", 7 | transformMode: { 8 | web: [/.[jt]sx?/], 9 | }, 10 | deps: { 11 | inline: [/solid-js/], 12 | }, 13 | threads: false, 14 | isolate: false, 15 | }, 16 | plugins: [solid()], 17 | build: { 18 | target: "esnext", 19 | polyfillDynamicImport: false, 20 | }, 21 | resolve: { 22 | conditions: ["development", "browser"], 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /packages/codemirror/test/createLineNumbers.test.tsx: -------------------------------------------------------------------------------- 1 | import { describe, expect, it, vi, afterEach } from "vitest"; 2 | import { screen, render } from "solid-testing-library"; 3 | import { CodeMirror } from "../src"; 4 | 5 | describe("createLineNumbers", () => { 6 | afterEach(() => { 7 | vi.restoreAllMocks(); 8 | }); 9 | 10 | it("is default false", async () => { 11 | const { unmount } = render(() => ); 12 | // TODO 13 | unmount(); 14 | }); 15 | 16 | it("can be set to true", async () => { 17 | const { unmount } = render(() => ); 18 | // TODO 19 | unmount(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/codemirror/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | import solid from "vite-plugin-solid"; 3 | 4 | export default defineConfig({ 5 | test: { 6 | globals: true, 7 | environment: "jsdom", 8 | transformMode: { 9 | web: [/.[jt]sx?/], 10 | }, 11 | setupFiles: "./setupVitest.ts", 12 | deps: { 13 | inline: [/solid-js/], 14 | }, 15 | threads: false, 16 | isolate: false, 17 | }, 18 | plugins: [solid()], 19 | build: { 20 | target: "esnext", 21 | polyfillDynamicImport: false, 22 | }, 23 | resolve: { 24 | conditions: ["development", "browser"], 25 | }, 26 | }); 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solid-codemirror", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "private": true, 6 | "scripts": { 7 | "build": "turbo run build", 8 | "build:packages": "turbo run build --filter=demo^...", 9 | "dev": "turbo run dev --parallel", 10 | "test": "turbo run test", 11 | "lint": "turbo run lint", 12 | "clean": "turbo run clean && rm -rf node_modules", 13 | "changeset": "changeset", 14 | "version-packages": "changeset version", 15 | "release": "turbo run build --filter=demo^... && changeset publish" 16 | }, 17 | "devDependencies": { 18 | "@changesets/cli": "^2.22.0", 19 | "turbo": "^1.2.16" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/codemirror/src/utils/createTheme.ts: -------------------------------------------------------------------------------- 1 | import type { Extension } from "@codemirror/state"; 2 | import { createEffect, mergeProps, on } from "solid-js"; 3 | 4 | export interface ThemeProps { 5 | /** 6 | * The CodeMirror theme extension to use 7 | */ 8 | theme?: Extension; 9 | } 10 | 11 | export function createTheme( 12 | props: ThemeProps, 13 | createExtension: (extension: Extension) => (extension: Extension) => void 14 | ) { 15 | const merged = mergeProps({ theme: [] }, props); 16 | 17 | const reconfigureTheme = createExtension(merged.theme); 18 | 19 | createEffect( 20 | on( 21 | () => merged.theme, 22 | (theme) => { 23 | reconfigureTheme(theme); 24 | }, 25 | { defer: true } 26 | ) 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /apps/demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@solid-codemirror/demo", 3 | "version": "0.0.0", 4 | "description": "", 5 | "private": true, 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "serve": "vite preview" 10 | }, 11 | "license": "MIT", 12 | "devDependencies": { 13 | "typescript": "^4.6.4", 14 | "vite": "^2.9.9", 15 | "vite-plugin-solid": "^2.2.6" 16 | }, 17 | "dependencies": { 18 | "@codemirror/lang-python": "^6.0.0", 19 | "@codemirror/theme-one-dark": "^6.0.0", 20 | "@codemirror/view": "^6.0.0", 21 | "@solid-codemirror/codemirror": "workspace:*", 22 | "@solid-codemirror/core": "workspace:*", 23 | "@solid-primitives/refs": "^0.3.0", 24 | "codemirror": "^6.0.0", 25 | "solid-js": "^1.4.2" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/codemirror/src/utils/createExtensions.ts: -------------------------------------------------------------------------------- 1 | import type { Extension } from "@codemirror/state"; 2 | import { createEffect, mergeProps, on } from "solid-js"; 3 | 4 | export interface ExtensionsProps { 5 | /** 6 | * An array of CodeMirror extensions to use 7 | */ 8 | extensions?: Extension[]; 9 | } 10 | 11 | export function createExtensions( 12 | props: ExtensionsProps, 13 | createExtension: (extension: Extension) => (extension: Extension) => void 14 | ) { 15 | const merged = mergeProps({ extensions: [] }, props); 16 | 17 | const reconfigureExtensions = createExtension(merged.extensions); 18 | 19 | createEffect( 20 | on( 21 | () => merged.extensions, 22 | (extensions) => { 23 | reconfigureExtensions(extensions); 24 | }, 25 | { defer: true } 26 | ) 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /apps/demo/src/CodeMirror1.tsx: -------------------------------------------------------------------------------- 1 | import { CodeMirrorProps, createCodeMirror } from "@solid-codemirror/core"; 2 | import { lineNumbers } from "@codemirror/view"; 3 | 4 | export function CodeMirror1(props: CodeMirrorProps) { 5 | let ref: HTMLDivElement | undefined; 6 | 7 | const { createExtension } = createCodeMirror(props, () => ref); 8 | 9 | const reconfigureLineNumbers = createExtension(lineNumbers()); 10 | 11 | return ( 12 | <> 13 |
14 | 15 | {/* Buttons to show/hide line numbers */} 16 |
17 | 20 | 23 |
24 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /packages/codemirror/test/__snapshots__/CodeMirror.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1 2 | 3 | exports[`CodeMirror > renders 1`] = `"
9
1

"`; 4 | -------------------------------------------------------------------------------- /packages/codemirror/test/createReadOnly.test.tsx: -------------------------------------------------------------------------------- 1 | import { describe, expect, it, vi, afterEach } from "vitest"; 2 | import { screen, render } from "solid-testing-library"; 3 | import { CodeMirror } from "../src"; 4 | 5 | describe("createReadOnly", () => { 6 | afterEach(() => { 7 | vi.restoreAllMocks(); 8 | }); 9 | 10 | it("is default false", async () => { 11 | const { unmount } = render(() => ); 12 | 13 | const div = (await screen.findByRole("textbox")) as HTMLDivElement; 14 | expect(div.getAttribute("contenteditable")).toBe("true"); 15 | 16 | unmount(); 17 | }); 18 | 19 | it("can be set to true", async () => { 20 | const { unmount } = render(() => ); 21 | const div = (await screen.findByRole("textbox")) as HTMLDivElement; 22 | expect(div.getAttribute("contenteditable")).toBe("false"); 23 | 24 | unmount(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | concurrency: ${{ github.workflow }}-${{ github.ref }} 9 | 10 | jobs: 11 | release: 12 | name: Release 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout Repo 16 | uses: actions/checkout@v2 17 | with: 18 | fetch-depth: 0 19 | 20 | - name: Setup Node.js 16.x 21 | uses: actions/setup-node@v2 22 | with: 23 | node-version: 16.x 24 | 25 | - name: Install pnpm 26 | run: npm i pnpm@latest -g 27 | 28 | - name: Install Dependencies 29 | run: pnpm install 30 | 31 | - name: Create Release Pull Request or Publish to npm 32 | id: changesets 33 | uses: changesets/action@v1 34 | with: 35 | publish: pnpm release 36 | env: 37 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 38 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 39 | -------------------------------------------------------------------------------- /packages/codemirror/src/utils/createWrapLine.ts: -------------------------------------------------------------------------------- 1 | import type { Extension } from "@codemirror/state"; 2 | import { EditorView } from "@codemirror/view"; 3 | import { createEffect, mergeProps, on } from "solid-js"; 4 | 5 | export interface WrapLineProps { 6 | /** 7 | * Whether to wrap lines 8 | * @default false 9 | */ 10 | wrapLine?: boolean; 11 | } 12 | 13 | export function createWrapLine( 14 | props: WrapLineProps, 15 | createExtension: (extension: Extension) => (extension: Extension) => void 16 | ) { 17 | const merged = mergeProps({ wrapLine: false }, props); 18 | 19 | const reconfigureWrapLine = createExtension(getWrapLine(merged.wrapLine)); 20 | 21 | createEffect( 22 | on( 23 | () => merged.wrapLine, 24 | (wrapLine) => { 25 | reconfigureWrapLine(getWrapLine(wrapLine)); 26 | }, 27 | { defer: true } 28 | ) 29 | ); 30 | } 31 | 32 | function getWrapLine(wrapLine: boolean) { 33 | return wrapLine ? EditorView.lineWrapping : []; 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Nimesh Nayaju 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /packages/codemirror/src/utils/createLineNumbers.ts: -------------------------------------------------------------------------------- 1 | import type { Extension } from "@codemirror/state"; 2 | import { lineNumbers } from "@codemirror/view"; 3 | import { createEffect, mergeProps, on } from "solid-js"; 4 | 5 | export interface LineNumbersProps { 6 | /** 7 | * Whether to display line numbers 8 | * @default true 9 | */ 10 | showLineNumbers?: boolean; 11 | } 12 | 13 | export function createLineNumbers( 14 | props: LineNumbersProps, 15 | createExtension: (extension: Extension) => (extension: Extension) => void 16 | ) { 17 | const merged = mergeProps({ showLineNumbers: true }, props); 18 | 19 | const reconfigureLineNumbers = createExtension( 20 | getLineNumbers(merged.showLineNumbers) 21 | ); 22 | 23 | createEffect( 24 | on( 25 | () => merged.showLineNumbers, 26 | (showLineNumbers) => { 27 | reconfigureLineNumbers(getLineNumbers(showLineNumbers)); 28 | }, 29 | { defer: true } 30 | ) 31 | ); 32 | } 33 | 34 | function getLineNumbers(showLineNumbers: boolean) { 35 | return showLineNumbers ? lineNumbers() : []; 36 | } 37 | -------------------------------------------------------------------------------- /packages/core/LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Nimesh Nayaju 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /packages/codemirror/LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Nimesh Nayaju 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /packages/codemirror/src/utils/createReadOnly.ts: -------------------------------------------------------------------------------- 1 | import type { Extension } from "@codemirror/state"; 2 | import { 3 | EditorView, 4 | highlightActiveLine, 5 | highlightActiveLineGutter, 6 | } from "@codemirror/view"; 7 | import { createEffect, mergeProps, on } from "solid-js"; 8 | 9 | export interface ReadOnlyProps { 10 | /** 11 | * Whether to set the editor to read-only 12 | * @default false 13 | */ 14 | readOnly?: boolean; 15 | } 16 | 17 | export function createReadOnly( 18 | props: ReadOnlyProps, 19 | createExtension: (extension: Extension) => (extension: Extension) => void 20 | ) { 21 | const merged = mergeProps({ readOnly: false }, props); 22 | 23 | const reconfigureLineNumbers = createExtension(getReadOnly(merged.readOnly)); 24 | 25 | createEffect( 26 | on( 27 | () => merged.readOnly, 28 | (readOnly) => { 29 | reconfigureLineNumbers(getReadOnly(readOnly)); 30 | }, 31 | { defer: true } 32 | ) 33 | ); 34 | } 35 | 36 | function getReadOnly(readOnly: boolean) { 37 | return readOnly 38 | ? EditorView.editable.of(false) 39 | : [highlightActiveLine(), highlightActiveLineGutter()]; 40 | } 41 | -------------------------------------------------------------------------------- /apps/demo/README.md: -------------------------------------------------------------------------------- 1 | ## Usage 2 | 3 | Those templates dependencies are maintained via [pnpm](https://pnpm.io) via `pnpm up -Lri`. 4 | 5 | This is the reason you see a `pnpm-lock.yaml`. That being said, any package manager will work. This file can be safely be removed once you clone a template. 6 | 7 | ```bash 8 | $ npm install # or pnpm install or yarn install 9 | ``` 10 | 11 | ### Learn more on the [Solid Website](https://solidjs.com) and come chat with us on our [Discord](https://discord.com/invite/solidjs) 12 | 13 | ## Available Scripts 14 | 15 | In the project directory, you can run: 16 | 17 | ### `npm dev` or `npm start` 18 | 19 | Runs the app in the development mode.
20 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 21 | 22 | The page will reload if you make edits.
23 | 24 | ### `npm run build` 25 | 26 | Builds the app for production to the `dist` folder.
27 | It correctly bundles Solid in production mode and optimizes the build for the best performance. 28 | 29 | The build is minified and the filenames include the hashes.
30 | Your app is ready to be deployed! 31 | 32 | ## Deployment 33 | 34 | You can deploy the `dist` folder to any static host provider (netlify, surge, now, etc.) 35 | -------------------------------------------------------------------------------- /apps/demo/src/CodeMirror2.tsx: -------------------------------------------------------------------------------- 1 | import { createEffect, mergeProps, on, splitProps } from "solid-js"; 2 | import type { JSX } from "solid-js/jsx-runtime"; 3 | import { mergeRefs } from "@solid-primitives/refs"; 4 | import { type CodeMirrorProps, createCodeMirror } from "@solid-codemirror/core"; 5 | import { lineNumbers } from "@codemirror/view"; 6 | 7 | export function CodeMirror2( 8 | props: CodeMirrorProps & JSX.HTMLAttributes & { showLineNumbers?: boolean }, 9 | ) { 10 | let ref: HTMLDivElement | undefined; 11 | 12 | const [codemirrorProps, local, others] = splitProps(props, ["value", "onValueChange"], ["showLineNumbers"]); 13 | const { createExtension } = createCodeMirror(codemirrorProps, () => ref); 14 | 15 | const merged = mergeProps({ showLineNumbers: true, readOnly: false }, local); 16 | 17 | const reconfigureLineNumbers = createExtension(getLineNumbers(merged.showLineNumbers)); 18 | 19 | createEffect(on(() => merged.showLineNumbers, (showLineNumbers) => { 20 | reconfigureLineNumbers(getLineNumbers(showLineNumbers)); 21 | }, { defer: true })); 22 | 23 | return
(ref = el), props.ref)} {...others} />; 24 | } 25 | 26 | function getLineNumbers(showLineNumbers: boolean) { 27 | return showLineNumbers ? lineNumbers() : []; 28 | } 29 | 30 | 31 | -------------------------------------------------------------------------------- /packages/codemirror/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @solid-codemirror/codemirror 2 | 3 | ## 1.0.4 4 | 5 | ### Patch Changes 6 | 7 | - b7e996c: Roll back to `rollup` for SSR serving 8 | 9 | ## 1.0.3 10 | 11 | ### Patch Changes 12 | 13 | - Fix extension configuration error due to bundling 14 | 15 | ## 1.0.2 16 | 17 | ### Patch Changes 18 | 19 | - Set `@codemirror/state` and `@codemirror/view` as dev dependencies 20 | - Updated dependencies 21 | - @solid-codemirror/core@1.0.1 22 | 23 | ## 1.0.1 24 | 25 | ### Patch Changes 26 | 27 | - Flag `@codemirror/state` and `@codemirror/view` as peer dependencies 28 | 29 | ## 1.0.0 30 | 31 | ### Major Changes 32 | 33 | - Add tests to `createReadOnly` and `createWrapLine` 34 | 35 | ## 0.0.6 36 | 37 | ### Patch Changes 38 | 39 | - Updated dependencies 40 | - @solid-codemirror/core@1.0.0 41 | 42 | ## 0.0.5 43 | 44 | ### Patch Changes 45 | 46 | - Add an optional `theme` prop that accepts an Codemirror Extension object 47 | - Updated dependencies 48 | - @solid-codemirror/core@0.0.4 49 | 50 | ## 0.0.4 51 | 52 | ### Patch Changes 53 | 54 | - 5da6aea: Add optional `extensions` option that takes in an array of extensions 55 | 56 | ## 0.0.2 57 | 58 | ### Patch Changes 59 | 60 | - 9d28f08: Add an optional boolean `wrapLine` option. 61 | 62 | ## 0.0.1 63 | 64 | ### Patch Changes 65 | 66 | - 9ae1cce: 67 | - Add `readOnly` and `showLineNumbers` option to the `CodeMirror` component 68 | -------------------------------------------------------------------------------- /packages/codemirror/src/CodeMirror.tsx: -------------------------------------------------------------------------------- 1 | import { onMount, splitProps } from "solid-js"; 2 | import type { JSX } from "solid-js/jsx-runtime"; 3 | import { mergeRefs } from "@solid-primitives/refs"; 4 | import { type CodeMirrorProps, createCodeMirror } from "@solid-codemirror/core"; 5 | import { createExtensions, createLineNumbers, createReadOnly, createTheme, createWrapLine, ExtensionsProps, LineNumbersProps, ReadOnlyProps, ThemeProps, WrapLineProps } from "./utils"; 6 | 7 | export type Props = CodeMirrorProps & LineNumbersProps & ReadOnlyProps & WrapLineProps & ExtensionsProps & ThemeProps & JSX.HTMLAttributes; 8 | 9 | export function CodeMirror( 10 | props: Props 11 | ) { 12 | let ref: HTMLDivElement | undefined; 13 | 14 | const [codemirrorProps, lineNumberProps, readOnlyProps, wrapLineProps, extensionProps, themeProps, others] = splitProps(props, ["value", "onValueChange", "onEditorMount"], ["showLineNumbers"], ["readOnly"], ["wrapLine"], ["extensions"], ["theme"]); 15 | 16 | const { createExtension } = createCodeMirror(codemirrorProps, () => ref); 17 | 18 | createLineNumbers(lineNumberProps, createExtension); 19 | createReadOnly(readOnlyProps, createExtension); 20 | createWrapLine(wrapLineProps, createExtension); 21 | createTheme(themeProps, createExtension); 22 | createExtensions(extensionProps, createExtension); 23 | 24 | return
(ref = el), props.ref)} {...others} />; 25 | } 26 | 27 | 28 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@solid-codemirror/core", 3 | "version": "1.0.1", 4 | "main": "dist/index/index.common.js", 5 | "module": "dist/index/index.module.js", 6 | "types": "dist/index/index.d.ts", 7 | "exports": { 8 | ".": { 9 | "import": "./dist/index/index.module.js", 10 | "browser": { 11 | "import": "./dist/index/index.module.js", 12 | "require": "./dist/index/index.common.js" 13 | }, 14 | "require": "./dist/index/index.common.js", 15 | "node": "./dist/index/index.common.js" 16 | } 17 | }, 18 | "files": [ 19 | "dist" 20 | ], 21 | "sideEffects": false, 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/nimeshnayaju/solid-codemirror.git" 25 | }, 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/nimeshnayaju/solid-codemirror.git/issues" 29 | }, 30 | "homepage": "https://github.com/nimeshnayaju/solid-codemirror.git#readme", 31 | "scripts": { 32 | "build": "rollup -c rollup.config.ts", 33 | "dev": "rollup -c rollup.config.ts --watch", 34 | "test": "vitest run", 35 | "test:watch": "vitest watch" 36 | }, 37 | "peerDependencies": { 38 | "@codemirror/state": "^6.0.0", 39 | "@codemirror/view": "^6.0.0", 40 | "solid-js": "^1.4.2" 41 | }, 42 | "devDependencies": { 43 | "@codemirror/state": "^6.0.0", 44 | "@codemirror/view": "^6.0.0", 45 | "jsdom": "^20.0.0", 46 | "rollup": "^2.76.0", 47 | "rollup-preset-solid": "^1.4.0", 48 | "solid-js": "^1.4.2", 49 | "solid-testing-library": "^0.3.0", 50 | "typescript": "^4.7.3", 51 | "vite-plugin-solid": "^2.2.6", 52 | "vitest": "^0.16.0" 53 | }, 54 | "publishConfig": { 55 | "access": "public" 56 | }, 57 | "keywords": [ 58 | "solid", 59 | "codemirror" 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /packages/codemirror/test/CodeMirror.test.tsx: -------------------------------------------------------------------------------- 1 | import { describe, expect, it, vi, afterEach } from "vitest"; 2 | import { fireEvent, screen, render } from "solid-testing-library"; 3 | import { CodeMirror } from "../src"; 4 | import { EditorView } from "@codemirror/view"; 5 | 6 | describe("CodeMirror", () => { 7 | afterEach(() => { 8 | vi.restoreAllMocks(); 9 | }); 10 | 11 | it("renders", () => { 12 | const { container, unmount } = render(() => ); 13 | expect(container.innerHTML).toMatchSnapshot(); 14 | unmount(); 15 | }); 16 | 17 | it("handles default value", async () => { 18 | const { unmount } = render(() => ); 19 | 20 | const div = (await screen.findByRole("textbox")) as HTMLDivElement; 21 | 22 | expect(div.textContent).toBe("test"); 23 | 24 | unmount(); 25 | }); 26 | 27 | it("can be controlled on value change", async () => { 28 | const onChangeMock = vi.fn().mockImplementation((code) => {}); 29 | 30 | const { unmount } = render(() => ( 31 | 32 | )); 33 | 34 | const div = (await screen.findByRole("textbox")) as HTMLDivElement; 35 | 36 | await fireEvent.change(div, { target: { textContent: "test" } }); 37 | 38 | expect(onChangeMock).toHaveBeenCalledTimes(1); 39 | expect(onChangeMock).toHaveBeenCalledWith("test"); 40 | 41 | unmount(); 42 | }); 43 | 44 | it("can be controlled on editor mount", async () => { 45 | const onEditorMountMock = vi.fn().mockImplementation((editor) => {}); 46 | 47 | const { unmount } = render(() => ( 48 | 49 | )); 50 | 51 | expect(onEditorMountMock).toHaveBeenCalledTimes(1); 52 | expect(onEditorMountMock).toHaveBeenCalledWith(expect.any(EditorView)); 53 | 54 | unmount(); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /packages/codemirror/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@solid-codemirror/codemirror", 3 | "version": "1.0.4", 4 | "type": "module", 5 | "main": "dist/index/index.common.js", 6 | "module": "dist/index/index.module.js", 7 | "types": "dist/index/index.d.ts", 8 | "exports": { 9 | ".": { 10 | "solid": "./dist/index/CodeMirror.jsx", 11 | "import": "./dist/index/index.module.js", 12 | "browser": { 13 | "import": "./dist/index/index.module.js", 14 | "require": "./dist/index/index.common.js" 15 | }, 16 | "require": "./dist/index/index.common.js", 17 | "node": "./dist/index/index.common.js" 18 | } 19 | }, 20 | "files": [ 21 | "dist" 22 | ], 23 | "sideEffects": false, 24 | "repository": { 25 | "type": "git", 26 | "url": "git+https://github.com/nimeshnayaju/solid-codemirror.git" 27 | }, 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/nimeshnayaju/solid-codemirror.git/issues" 31 | }, 32 | "homepage": "https://github.com/nimeshnayaju/solid-codemirror.git#readme", 33 | "scripts": { 34 | "build": "rollup -c rollup.config.ts", 35 | "dev": "rollup -c rollup.config.ts --watch", 36 | "test": "vitest run", 37 | "test:watch": "vitest watch" 38 | }, 39 | "dependencies": { 40 | "@solid-codemirror/core": "workspace:*", 41 | "@solid-primitives/refs": "^0.3.0" 42 | }, 43 | "peerDependencies": { 44 | "@codemirror/state": "^6.0.0", 45 | "@codemirror/view": "^6.0.0", 46 | "solid-js": "^1.4.2" 47 | }, 48 | "devDependencies": { 49 | "@codemirror/state": "^6.0.0", 50 | "@codemirror/view": "^6.0.0", 51 | "@testing-library/jest-dom": "^5.16.4", 52 | "rollup": "^2.76.0", 53 | "rollup-preset-solid": "^1.4.0", 54 | "jsdom": "^20.0.0", 55 | "solid-js": "^1.4.2", 56 | "solid-testing-library": "^0.3.0", 57 | "typescript": "^4.7.3", 58 | "vite-plugin-solid": "^2.2.6", 59 | "vitest": "^0.16.0" 60 | }, 61 | "publishConfig": { 62 | "access": "public" 63 | }, 64 | "keywords": [ 65 | "solid", 66 | "codemirror" 67 | ] 68 | } 69 | -------------------------------------------------------------------------------- /apps/demo/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { createSignal } from "solid-js"; 2 | import { CodeMirror } from "@solid-codemirror/codemirror"; 3 | import { CodeMirror1 } from "./CodeMirror1"; 4 | import { CodeMirror2 } from "./CodeMirror2"; 5 | import { basicSetup } from "codemirror"; 6 | import { python } from "@codemirror/lang-python"; 7 | import { oneDark } from "@codemirror/theme-one-dark"; 8 | 9 | export default function App() { 10 | const [value, setValue] = createSignal("Hello World 🌎"); 11 | const [showLineNumbers, setShowLineNumbers] = createSignal(true); 12 | const [readOnly, setReadOnly] = createSignal(false); 13 | const [wrapLine, setWrapLine] = createSignal(false); 14 | 15 | return ( 16 | <> 17 | 18 | 19 | 20 | {/* CodeMirror Example 1 */} 21 |
22 |

Example 1

23 | 24 |
25 | 26 | {/* CodeMirror Example 2 */} 27 |
28 |

Example 2

29 | 34 |
35 | 36 | 41 | 42 | {/* CodeMirror Example 3 */} 43 |
44 |

Example 3

45 | 54 | 55 | 58 | 61 |
62 | 63 | ); 64 | } 65 | -------------------------------------------------------------------------------- /packages/core/test/createCodeMirror.test.tsx: -------------------------------------------------------------------------------- 1 | import { describe, expect, it, vi, afterEach } from "vitest"; 2 | import { fireEvent, screen, render } from "solid-testing-library"; 3 | import { createCodeMirror, CodeMirrorProps } from "../src"; 4 | import { createRoot } from "solid-js"; 5 | import { EditorView } from "@codemirror/view"; 6 | 7 | function CodeMirror(props: CodeMirrorProps) { 8 | let ref: HTMLDivElement | undefined; 9 | 10 | createCodeMirror(props, () => ref); 11 | 12 | return
; 13 | } 14 | 15 | describe("createCodeMirror", () => { 16 | afterEach(() => { 17 | vi.restoreAllMocks(); 18 | }); 19 | 20 | it("handles default", () => { 21 | createRoot(async (dispose) => { 22 | let ref: HTMLDivElement | undefined; 23 | const { createExtension } = createCodeMirror({}, () => ref); 24 | expect(typeof createExtension).toBe("function"); 25 | 26 | dispose(); 27 | }); 28 | }); 29 | 30 | it("handles default value", async () => { 31 | const { unmount } = render(() => ); 32 | 33 | const div = (await screen.findByRole("textbox")) as HTMLDivElement; 34 | 35 | expect(div.textContent).toBe("test"); 36 | 37 | unmount(); 38 | }); 39 | 40 | it("can be controlled on value change", async () => { 41 | const onChangeMock = vi.fn().mockImplementation((code) => {}); 42 | 43 | const { unmount } = render(() => ( 44 | 45 | )); 46 | 47 | const div = (await screen.findByRole("textbox")) as HTMLDivElement; 48 | 49 | await fireEvent.change(div, { target: { textContent: "test" } }); 50 | 51 | expect(onChangeMock).toHaveBeenCalledTimes(1); 52 | expect(onChangeMock).toHaveBeenCalledWith("test"); 53 | 54 | unmount(); 55 | }); 56 | 57 | it("can be controlled on editor mount", async () => { 58 | const onEditorMountMock = vi.fn().mockImplementation((editor) => {}); 59 | 60 | const { unmount } = render(() => ( 61 | 62 | )); 63 | 64 | expect(onEditorMountMock).toHaveBeenCalledTimes(1); 65 | expect(onEditorMountMock).toHaveBeenCalledWith(expect.any(EditorView)); 66 | 67 | unmount(); 68 | }); 69 | }); 70 | -------------------------------------------------------------------------------- /packages/core/src/createCodeMirror.ts: -------------------------------------------------------------------------------- 1 | import { Accessor, onCleanup, onMount, on, createEffect } from "solid-js"; 2 | import { EditorView } from "@codemirror/view"; 3 | import { 4 | Compartment, 5 | EditorState, 6 | StateEffect, 7 | type Extension, 8 | } from "@codemirror/state"; 9 | import { CodeMirrorProps } from "./types"; 10 | 11 | /** 12 | * Creates a CodeMirror editor view instance (the editor's user interface). 13 | * @param props See {@link CodeMirrorProps} for details. 14 | * @param ref the element to attach the editor to on creation. 15 | */ 16 | export function createCodeMirror( 17 | props: CodeMirrorProps, 18 | ref: Accessor 19 | ) { 20 | let view: EditorView | undefined; 21 | 22 | onMount(() => { 23 | const state = EditorState.create({ 24 | doc: props.value, 25 | }); 26 | 27 | // Construct a new EditorView instance 28 | view = new EditorView({ 29 | state, 30 | parent: ref(), 31 | dispatch: (tr): void => { 32 | if (!view) return; 33 | 34 | view.update([tr]); 35 | 36 | if (tr.docChanged) { 37 | const newCode = tr.newDoc.sliceString(0, tr.newDoc.length); 38 | props.onValueChange?.(newCode); 39 | } 40 | }, 41 | }); 42 | 43 | props.onEditorMount?.(view); 44 | 45 | onCleanup(() => { 46 | if (!view) return; 47 | view.destroy(); 48 | }); 49 | }); 50 | 51 | createEffect( 52 | on( 53 | () => props.value, 54 | (value) => { 55 | if (!view || value === view.state.doc.toString()) { 56 | return; 57 | } 58 | view.dispatch({ 59 | changes: { 60 | from: 0, 61 | to: view.state.doc.length, 62 | insert: value, 63 | }, 64 | }); 65 | }, 66 | { defer: true } 67 | ) 68 | ); 69 | 70 | /** 71 | * Creates a compartment instance with the given extension and appends it to the top-level configuration of the editor. 72 | * See {@link https://codemirror.net/examples/config/| CodeMirror Configuration} and {@link https://codemirror.net/docs/ref/#state.Compartment| Compartment} for details on editor configuration. 73 | * @param extension the extension to append 74 | */ 75 | function createExtension(extension: Extension) { 76 | const compartment = new Compartment(); 77 | 78 | onMount(() => { 79 | if (!view) return; 80 | 81 | view.dispatch({ 82 | effects: StateEffect.appendConfig.of(compartment.of(extension)), 83 | }); 84 | }); 85 | 86 | /** 87 | * Reconfigures the extension compartment with the given extension. 88 | * @param extension the extension to reconfigure the extension compartment with. 89 | */ 90 | function reconfigure(extension: Extension) { 91 | if (!view) return; 92 | 93 | view.dispatch({ 94 | effects: compartment.reconfigure(extension), 95 | }); 96 | } 97 | 98 | return reconfigure; 99 | } 100 | 101 | return { createExtension }; 102 | } 103 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 |

2 | Core 3 |

4 | 5 | # @solid-codemirror/core 6 | 7 | Provides a `createCodeMirror` function that takes in a `ref` object and attaches a `CodeMirror` view to it. 8 | 9 | ## Demo 10 | 11 | https://solid-codemirror.vercel.app/ 12 | 13 | ## Installation 14 | 15 | ```bash 16 | yarn add @solid-codemirror/core 17 | # or 18 | npm i @solid-codemirror/core 19 | ``` 20 | 21 | > **Note** The [@codemirror/state](https://github.com/codemirror/state) and [@codemirror/view](https://github.com/codemirror/state) libraries are flagged as peer dependencies and are recommeneded to be installed alongside this package. 22 | 23 | ## `createCodeMirror` 24 | 25 | Attaches a `CodeMirror` view to the specified `ref` object and returns a object with a `createExtension` method to add extension compartments to the codemirror state instance. 26 | 27 | ## Basic Usage 28 | 29 | ```tsx 30 | import { CodeMirrorProps, createCodeMirror } from "@solid-codemirror/core"; 31 | 32 | export default function CodeMirror(props: CodeMirrorProps) { 33 | let ref: HTMLDivElement | undefined; 34 | 35 | createCodeMirror(props, () => ref); 36 | 37 | return
; 38 | } 39 | ``` 40 | 41 | ## Add Extension 42 | 43 | ```tsx 44 | import { CodeMirrorProps, createCodeMirror } from "@solid-codemirror/core"; 45 | import { lineNumbers } from "@codemirror/view"; 46 | 47 | export default function App(props: CodeMirrorProps) { 48 | let ref: HTMLDivElement | undefined; 49 | 50 | const { createExtension } = createCodeMirror(props, () => ref); 51 | 52 | createExtension(lineNumbers()); 53 | 54 | return
; 55 | } 56 | ``` 57 | 58 | ## Reconfigure Extension 59 | 60 | ```tsx 61 | import { CodeMirrorProps, createCodeMirror } from "@solid-codemirror/core"; 62 | import { lineNumbers } from "@codemirror/view"; 63 | 64 | export default function App(props: CodeMirrorProps) { 65 | let ref: HTMLDivElement | undefined; 66 | 67 | const { createExtension } = createCodeMirror(props, () => ref); 68 | 69 | const reconfigureLineNumbers = createExtension(lineNumbers()); 70 | 71 | return ( 72 |
73 |
74 | 75 | {/* Buttons to show/hide line numbers */} 76 |
77 | 80 | 83 |
84 |
85 | ); 86 | } 87 | ``` 88 | 89 | > **Info** Extensions in `@codemirror/core` are wrapped inside an editor [Comparment](https://codemirror.net/docs/ref/#state.Compartment). Compartments enable [dynamic reconfiguration](https://codemirror.net/examples/config/) (partially reconfigure a tree of extensions) of the editor. 90 | 91 | ## `CodeMirrorProps` 92 | 93 | You can control the CodeMirror editor instance through the following props. **All props are optional.** 94 | 95 | | Prop | Type | Description | 96 | | --------------- | ------------------------------ | ------------------------------------------------------------------------------ | 97 | | `value` | `string` | The initial value of the editor | 98 | | `onValueChange` | `(value: string) => void` | Called whenever the editor code value changes | 99 | | `onEditorMount` | `(editor: EditorView) => void` | Called when the editor first mounts, receiving the current EditorView instance | 100 | 101 | ### Definition 102 | 103 | ```ts 104 | function createCodeMirror( 105 | props: { 106 | value?: string; 107 | onValueChange?: (value: string) => void; 108 | onEditorMount?: (editor: EditorView) => void; 109 | } 110 | ref: Accessor 111 | ): { 112 | createExtension: (extension: Extension) => (extension: Extension) => void; 113 | }; 114 | ``` 115 | 116 | > **Note** Extensions in `@codemirror/core` are wrapped inside an editor [Comparment](https://codemirror.net/docs/ref/#state.Compartment). Compartments enable [dynamic reconfiguration](https://codemirror.net/examples/config/) (partially reconfigure a tree of extensions) of the editor. 117 | 118 | > **Note** The `@solid-codemirror/codemirror` package is based on `@codemirror/core`. You can view the [source code](https://github.com/nimeshnayaju/solid-codemirror/tree/main/packages/codemirror) of the library here. 119 | 120 | ## License 121 | 122 | This project is licensed under MIT. 123 | 124 | ## Author 125 | 126 | - [@nayajunimesh](https://twitter.com/nayajunimesh) 127 | -------------------------------------------------------------------------------- /packages/codemirror/README.md: -------------------------------------------------------------------------------- 1 |

2 | Codemirror 3 |

4 | 5 | # @solid-codemirror/codemirror 6 | 7 | CodeMirror 6 component for SolidJS 8 | 9 | ## Demo 10 | 11 | https://solid-codemirror.vercel.app/ 12 | 13 | ## Installation 14 | 15 | ```bash 16 | yarn add @solid-codemirror/codemirror 17 | # or 18 | npm i @solid-codemirror/codemirror 19 | ``` 20 | 21 | > **Note** The [@codemirror/state](https://github.com/codemirror/state) and [@codemirror/view](https://github.com/codemirror/state) libraries are flagged as peer dependencies and are recommeneded to be installed alongside this package. 22 | 23 | ## Known issue with `Vite` 24 | 25 | > **Warning** You may encounter the following error if you're using Vite as your bundling tool: 26 | > 27 | > ```bash 28 | > Error: Unrecognized extension value in extension set ([object Object]). This sometimes happens because multipleinstances of @codemirror/state are loaded, breaking instanceof checks. 29 | > ``` 30 | > 31 | > This error can be fixed by adding the following configuration option to your `vite.config.{js,ts}` file. 32 | > 33 | > ```typescript 34 | > export default defineConfig({ 35 | > // Your configuration 36 | > optimizeDeps: { 37 | > // Add both @codemirror/state and @codemirror/view to included deps for optimization 38 | > include: ["@codemirror/state", "@codemirror/view"], 39 | > }, 40 | > }); 41 | > ``` 42 | 43 | ## Basic Usage 44 | 45 | ```tsx 46 | import { CodeMirror } from "@solid-codemirror/codemirror"; 47 | 48 | export default function App() { 49 | return ; 50 | } 51 | ``` 52 | 53 | ## Controlling the `CodeMirror` component 54 | 55 | You can control the `CodeMirror` component through the following props. **All props are optional.** 56 | 57 | | Prop | Type | Description | 58 | | ----------------- | ------------------------------ | ------------------------------------------------------------------------------ | 59 | | `value` | `string` | The initial value of the editor | 60 | | `onValueChange` | `(value: string) => void` | Called whenever the editor code value changes | 61 | | `onEditorMount` | `(editor: EditorView) => void` | Called when the editor first mounts, receiving the current EditorView instance | 62 | | `showLineNumbers` | `boolean` | Whether to display line numbers | 63 | | `wrapLine` | `boolean` | Whether to wrap lines | 64 | | `readOnly` | `boolean` | Whether to set the editor to read-only | 65 | | `theme` | `Extension` | The CodeMirror theme extension to use | 66 | | `extensions` | `Extension[]` | An array of CodeMirror extensions to use | 67 | 68 | ## Configure Line Numbers / Read Only / Line Wrapping 69 | 70 | ```tsx 71 | import { CodeMirror } from "@solid-codemirror/codemirror"; 72 | 73 | export default function App() { 74 | return ; 75 | } 76 | ``` 77 | 78 | ## Configure theme 79 | 80 | ```tsx 81 | import { CodeMirror } from "@solid-codemirror/codemirror"; 82 | import { oneDark } from "@codemirror/theme-one-dark"; 83 | 84 | export default function App() { 85 | return ; 86 | } 87 | ``` 88 | 89 | ## Configure Extensions 90 | 91 | ```tsx 92 | import { CodeMirror } from "@solid-codemirror/codemirror"; 93 | import { basicSetup } from "codemirror"; 94 | import { python } from "@codemirror/lang-python"; 95 | import { oneDark } from "@codemirror/theme-one-dark"; 96 | 97 | export default function App() { 98 | return ; 99 | } 100 | ``` 101 | 102 | ## Register callbacks on editor value change or editor mount 103 | 104 | ```tsx 105 | import { CodeMirror } from "@solid-codemirror/codemirror"; 106 | import type { EditorView } from "@codemirror/view"; 107 | 108 | export default function App() { 109 | const onValueChange = (value: string) => { 110 | console.log(value); 111 | }; 112 | 113 | const onEditorMount = (view: EditorView) => { 114 | console.log(view); 115 | }; 116 | 117 | return ( 118 | 119 | ); 120 | } 121 | ``` 122 | 123 | ## License 124 | 125 | This project is licensed under MIT. 126 | 127 | ## Author 128 | 129 | - [@nayajunimesh](https://twitter.com/nayajunimesh) 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | solid-codemirror 3 |

4 | 5 | # solid-codemirror 6 | 7 | A set of libraries to integrate CodeMirror to any SolidJS app. This repository contains two packages: 8 | 9 | - [@solid-codemirror/core](https://github.com/nimeshnayaju/solid-codemirror/tree/main/packages/core) 10 | 11 | - [@solid-codemirror/codemirror](https://github.com/nimeshnayaju/solid-codemirror/tree/main/packages/codemirror) 12 | 13 | ## Demo 14 | 15 | https://solid-codemirror.vercel.app/ 16 | 17 | ## Installation 18 | 19 | ```bash 20 | yarn add @solid-codemirror/codemirror 21 | # or 22 | npm i @solid-codemirror/codemirror 23 | ``` 24 | 25 | > **Note** The [@codemirror/state](https://github.com/codemirror/state) and [@codemirror/view](https://github.com/codemirror/state) libraries are flagged as peer dependencies and are recommeneded to be installed alongside this package. 26 | 27 | ## Known issue with `Vite` 28 | 29 | > **Warning** You may encounter the following error if you're using Vite as your bundling tool: 30 | > 31 | > ```bash 32 | > Error: Unrecognized extension value in extension set ([object Object]). This sometimes happens because multipleinstances of @codemirror/state are loaded, breaking instanceof checks. 33 | > ``` 34 | > 35 | > This error can be fixed by adding the following configuration option to your `vite.config.{js,ts}` file. 36 | > 37 | > ```typescript 38 | > export default defineConfig({ 39 | > // Your configuration 40 | > optimizeDeps: { 41 | > // Add both @codemirror/state and @codemirror/view to included deps for optimization 42 | > include: ["@codemirror/state", "@codemirror/view"], 43 | > }, 44 | > }); 45 | > ``` 46 | 47 | ## Basic Usage 48 | 49 | ```tsx 50 | import { CodeMirror } from "@solid-codemirror/codemirror"; 51 | 52 | export default function App() { 53 | return ; 54 | } 55 | ``` 56 | 57 | ## Configure Line Numbers / Read Only / Line Wrapping 58 | 59 | ```tsx 60 | import { CodeMirror } from "@solid-codemirror/codemirror"; 61 | 62 | export default function App() { 63 | return ; 64 | } 65 | ``` 66 | 67 | ## Configure theme 68 | 69 | ```tsx 70 | import { CodeMirror } from "@solid-codemirror/codemirror"; 71 | import { oneDark } from "@codemirror/theme-one-dark"; 72 | 73 | export default function App() { 74 | return ; 75 | } 76 | ``` 77 | 78 | ## Configure Extensions 79 | 80 | ```tsx 81 | import { CodeMirror } from "@solid-codemirror/codemirror"; 82 | import { basicSetup } from "codemirror"; 83 | import { python } from "@codemirror/lang-python"; 84 | import { oneDark } from "@codemirror/theme-one-dark"; 85 | 86 | export default function App() { 87 | return ; 88 | } 89 | ``` 90 | 91 | ## Register callbacks on editor value change or editor mount 92 | 93 | ```tsx 94 | import { CodeMirror } from "@solid-codemirror/codemirror"; 95 | import type { EditorView } from "@codemirror/view"; 96 | 97 | export default function App() { 98 | const onValueChange = (value: string) => { 99 | console.log(value); 100 | }; 101 | 102 | const onEditorMount = (view: EditorView) => { 103 | console.log(view); 104 | }; 105 | 106 | return ( 107 | 108 | ); 109 | } 110 | ``` 111 | 112 | ## Controlling the `CodeMirror` component 113 | 114 | You can control the `CodeMirror` component through the following props. **All props are optional.** 115 | 116 | | Prop | Type | Description | 117 | | ----------------- | ------------------------------ | ------------------------------------------------------------------------------ | 118 | | `value` | `string` | The initial value of the editor | 119 | | `onValueChange` | `(value: string) => void` | Called whenever the editor code value changes | 120 | | `onEditorMount` | `(editor: EditorView) => void` | Called when the editor first mounts, receiving the current EditorView instance | 121 | | `showLineNumbers` | `boolean` | Whether to display line numbers | 122 | | `wrapLine` | `boolean` | Whether to wrap lines | 123 | | `readOnly` | `boolean` | Whether to set the editor to read-only | 124 | | `theme` | `Extension` | The CodeMirror theme extension to use | 125 | | `extensions` | `Extension[]` | An array of CodeMirror extensions to use | 126 | 127 | For more information on the usage of the `CodeMirror` component, check out [@solid-codemirror/codemirror](https://github.com/nimeshnayaju/solid-codemirror/tree/main/packages/codemirror). 128 | \ 129 |   130 | \ 131 |   132 | 133 | # Advanced usage 134 | 135 | ### Want more control over your `CodeMirror` component? Create your custom component using the `createCodeMirror` function. 136 | 137 | ## Installation 138 | 139 | ```bash 140 | yarn add @solid-codemirror/core @codemirror/state @codemirror/view 141 | # or 142 | npm i @solid-codemirror/core @codemirror/state @codemirror/view 143 | ``` 144 | 145 | ## `createCodeMirror` 146 | 147 | Attaches a `CodeMirror` view to the specified `ref` object and returns a object with a `createExtension` method to add extension compartments to the codemirror state instance. 148 | 149 | ## Basic Usage 150 | 151 | ```tsx 152 | import { CodeMirrorProps, createCodeMirror } from "@solid-codemirror/core"; 153 | 154 | export default function CodeMirror(props: CodeMirrorProps) { 155 | let ref: HTMLDivElement | undefined; 156 | 157 | createCodeMirror(props, () => ref); 158 | 159 | return
; 160 | } 161 | ``` 162 | 163 | ## Add Extension 164 | 165 | ```tsx 166 | import { CodeMirrorProps, createCodeMirror } from "@solid-codemirror/core"; 167 | import { lineNumbers } from "@codemirror/view"; 168 | 169 | export default function App(props: CodeMirrorProps) { 170 | let ref: HTMLDivElement | undefined; 171 | 172 | const { createExtension } = createCodeMirror(props, () => ref); 173 | 174 | createExtension(lineNumbers()); 175 | 176 | return
; 177 | } 178 | ``` 179 | 180 | ## Reconfigure Extension 181 | 182 | ```tsx 183 | import { CodeMirrorProps, createCodeMirror } from "@solid-codemirror/core"; 184 | import { lineNumbers } from "@codemirror/view"; 185 | 186 | export default function App(props: CodeMirrorProps) { 187 | let ref: HTMLDivElement | undefined; 188 | 189 | const { createExtension } = createCodeMirror(props, () => ref); 190 | 191 | const reconfigureLineNumbers = createExtension(lineNumbers()); 192 | 193 | return ( 194 |
195 |
196 | 197 | {/* Buttons to show/hide line numbers */} 198 |
199 | 202 | 205 |
206 |
207 | ); 208 | } 209 | ``` 210 | 211 | > **Note** Extensions in `@codemirror/core` are wrapped inside an editor [Comparment](https://codemirror.net/docs/ref/#state.Compartment). Compartments enable [dynamic reconfiguration](https://codemirror.net/examples/config/) (partially reconfigure a tree of extensions) of the editor. 212 | 213 | > **Note** The `@solid-codemirror/codemirror` package is based on `@codemirror/core`. You can view the [source code](https://github.com/nimeshnayaju/solid-codemirror/tree/main/packages/codemirror) of the library here. 214 | 215 | For more information on the usage of the `createCodeMirror` function, check out [@solid-codemirror/core](https://github.com/nimeshnayaju/solid-codemirror/tree/main/packages/core). 216 | 217 | ## License 218 | 219 | This project is licensed under MIT. 220 | 221 | ## Author 222 | 223 | - [@nayajunimesh](https://twitter.com/nayajunimesh) 224 | --------------------------------------------------------------------------------