├── .editorconfig ├── .gitattributes ├── .github ├── CODEOWNERS └── workflows │ └── build-docs.yml ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .prettierrc.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── env.d.ts ├── eslint.config.ts ├── index.html ├── package.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── public └── .gitignore ├── src-docs ├── App.vue ├── DemoPage.vue ├── components │ ├── LinterAndCrossBindingDemo.vue │ ├── MarkdownDemo.vue │ ├── ReadonlyAndDisabledDemo.vue │ ├── SlotDemo.vue │ └── ToggleTheme.vue ├── main.ts └── style.scss ├── src ├── components │ └── CodeMirror.ts ├── helpers │ └── h-demi.ts ├── index.ts └── interfaces │ └── MetaInterface.ts ├── tsconfig.app.json ├── tsconfig.docs.json ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 2 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | * vue eol=lf encoding=UTF-8 4 | *.css eol=lf encoding=UTF-8 5 | *.html eol=lf encoding=UTF-8 6 | *.js eol=lf encoding=UTF-8 7 | *.jsx eol=lf encoding=UTF-8 8 | *.md eol=lf encoding=UTF-8 9 | *.scss eol=lf encoding=UTF-8 10 | *.ts eol=lf encoding=UTF-8 11 | *.tsx eol=lf encoding=UTF-8 12 | *.txt eol=lf encoding=UTF-8 13 | *.xml eol=lf encoding=UTF-8 14 | 15 | # Images 16 | *.gif binary 17 | *.ico binary 18 | *.jpg binary 19 | *.png binary 20 | *.svg eol=lf encoding=UTF-8 21 | *.webp binary 22 | 23 | # Fonts 24 | *.eot binary 25 | *.otf binary 26 | *.ttf binary 27 | *.woff binary 28 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Generated by CODEOWNERS.com 2 | 3 | -------------------------------------------------------------------------------- /.github/workflows/build-docs.yml: -------------------------------------------------------------------------------- 1 | name: NodeJS with Vite 2 | 3 | on: 4 | push: 5 | branches: ['master'] 6 | pull_request: 7 | branches: ['master'] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | node-version: [22.x] 16 | 17 | steps: 18 | - name: Checkout ✅ 19 | uses: actions/checkout@v4.2.2 20 | 21 | - name: Use Node.js ${{ matrix.node-version }} ⚡ 22 | uses: actions/setup-node@v4.1.0 23 | with: 24 | node-version: ${{ matrix.node-version }} 25 | 26 | - name: Install pnpm 🎁 27 | uses: pnpm/action-setup@v4 28 | 29 | - name: Build 🔧 30 | run: | 31 | pnpm install 32 | pnpm run build:docs 33 | 34 | - name: Deploy to gh-pages 🚀 35 | uses: JamesIves/github-pages-deploy-action@v4.6.8 36 | with: 37 | branch: gh-pages # The branch the action should deploy to. 38 | folder: docs # The folder the action should deploy. 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.yarn/* 2 | # !/.yarn/patches 3 | # !/.yarn/plugins 4 | !/.yarn/releases 5 | # !/.yarn/sdks 6 | # !/.yarn/cache 7 | /.vscode/* 8 | node_modules 9 | .DS_Store 10 | dist 11 | dist-ssr 12 | *.local 13 | /src/Meta.ts 14 | docs/ 15 | stats.html 16 | *.tsbuildinfo 17 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 22.11.0 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .husky/ 2 | .vscode/ 3 | .yarn/ 4 | dist/ 5 | public/assets/ 6 | docs/ 7 | stats.html 8 | -------------------------------------------------------------------------------- /.prettierrc.yml: -------------------------------------------------------------------------------- 1 | printWidth: 80 2 | tabWidth: 2 3 | useTabs: false 4 | semi: true 5 | singleQuote: true 6 | trailingComma: es5 7 | bracketSpacing: true 8 | bracketSameLine: false 9 | arrowParens: avoid 10 | htmlWhitespaceSensitivity: ignore 11 | endOfLine: lf 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### Changelog 2 | 3 | All notable changes to this project will be documented in this file. Dates are displayed in UTC. 4 | 5 | Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). 6 | 7 | #### [1.3.17](https://github.com/logue/vue-codemirror6/compare/1.3.13...1.3.17) 8 | 9 | - fix: full example link [`#58`](https://github.com/logue/vue-codemirror6/pull/58) 10 | - Update dependencies. [`985f36f`](https://github.com/logue/vue-codemirror6/commit/985f36f23c4fc1b562b53b664deb7ff1eec79989) 11 | - Removed unnecessary comment. [`8d624a4`](https://github.com/logue/vue-codemirror6/commit/8d624a46cebc0f9196e5987f793e90184332ae4b) 12 | - Fixed typo. [`b39f9cb`](https://github.com/logue/vue-codemirror6/commit/b39f9cb0993708338f0a96429b4cdc2fd510208e) 13 | 14 | #### [1.3.13](https://github.com/logue/vue-codemirror6/compare/1.3.8...1.3.13) 15 | 16 | > 31 March 2025 17 | 18 | - Rewrite to eslint.config.ts [`841f686`](https://github.com/logue/vue-codemirror6/commit/841f686ebab5f542a5b7bc1569660ce58a21af65) 19 | - Fixed types path. [`2b86b2c`](https://github.com/logue/vue-codemirror6/commit/2b86b2c4da906f4591e13221e5c41e52b8792523) 20 | - Update @codemirror/language, @codemirror/lint, @codemirror/state, @codemirror/view. [`916fa98`](https://github.com/logue/vue-codemirror6/commit/916fa9899e7c3806199f53bddb210d3cba9e7517) 21 | 22 | #### [1.3.8](https://github.com/logue/vue-codemirror6/compare/1.1.16...1.3.8) 23 | 24 | > 22 November 2024 25 | 26 | - Fix sample code syntax error [`#47`](https://github.com/logue/vue-codemirror6/pull/47) 27 | - chore: demo docs [`#43`](https://github.com/logue/vue-codemirror6/pull/43) 28 | - fix: editor not update content when `modelValue` change and selection is out of range [`#44`](https://github.com/logue/vue-codemirror6/pull/44) 29 | - chore: props and readme doc [`#31`](https://github.com/logue/vue-codemirror6/pull/31) 30 | - Reduce unnecessary updates [`#22`](https://github.com/logue/vue-codemirror6/pull/22) 31 | - fix: coalescing-operator [`#20`](https://github.com/logue/vue-codemirror6/pull/20) 32 | - Migrate to pnpm. [`6d83aec`](https://github.com/logue/vue-codemirror6/commit/6d83aec625d50228cbfb248bc5811b6f83975219) 33 | - Update dependencies. [`992f209`](https://github.com/logue/vue-codemirror6/commit/992f209c5e4c269b72be119f693b0d0376d529bb) 34 | - Update dependencies. [`b839a33`](https://github.com/logue/vue-codemirror6/commit/b839a33569fadf3a9bb5e2a8f972c377fc1fce88) 35 | 36 | #### [1.1.16](https://github.com/logue/vue-codemirror6/compare/1.1.13...1.1.16) 37 | 38 | > 18 March 2023 39 | 40 | - Expose `view`. #16 [`daf3e6b`](https://github.com/logue/vue-codemirror6/commit/daf3e6b17a161a5c0c5a35ea2442d85421f05d82) 41 | - Fixed Maximum call stack size exceeded error. [`f10eaae`](https://github.com/logue/vue-codemirror6/commit/f10eaaea9145bc1d7a6605ab3cb8a82c0ca12df6) 42 | - Partially fixed the problem that the values defined in props disappeared under certain conditions. [`1cc4468`](https://github.com/logue/vue-codemirror6/commit/1cc4468e35e39ee8eaae1b2f007e3425a757217f) 43 | 44 | #### [1.1.13](https://github.com/logue/vue-codemirror6/compare/1.1.12...1.1.13) 45 | 46 | > 13 March 2023 47 | 48 | - Changed minimum Vue version requirement to 2.7.14. [`5b8b255`](https://github.com/logue/vue-codemirror6/commit/5b8b2558967f9fb6f6d9e83a0181afa50f182b98) 49 | - Add allow-multiple-selections prop. [`ced91ed`](https://github.com/logue/vue-codemirror6/commit/ced91edab8fc25f8f1299341489f6bbbdace9ce8) 50 | - Update CHANGELOG.md [`51d30e2`](https://github.com/logue/vue-codemirror6/commit/51d30e2f6370847ef888ab2b39ff6e1c8e3ec851) 51 | 52 | #### [1.1.12](https://github.com/logue/vue-codemirror6/compare/1.1.11...1.1.12) 53 | 54 | > 10 March 2023 55 | 56 | - chore(CODEOWNERS): CODEOWNERS.com Bot, at your service! [`#14`](https://github.com/logue/vue-codemirror6/pull/14) 57 | - Update demo code. (Replaced @codemirror/html to @codemirror/vue.) [`8da1a8a`](https://github.com/logue/vue-codemirror6/commit/8da1a8a4e37d713cc78281ce9c304c42a06940dc) 58 | - Changed implementation to generate *.d.ts with vite-plugin-dts. [`1caaa20`](https://github.com/logue/vue-codemirror6/commit/1caaa20b1423a3d252a6c770a630fb60e2e3440d) 59 | - Update README.md. [`f8dd493`](https://github.com/logue/vue-codemirror6/commit/f8dd4934a7b9cc089cd830473db5250d28b3389b) 60 | 61 | #### [1.1.11](https://github.com/logue/vue-codemirror6/compare/1.1.3...1.1.11) 62 | 63 | > 4 February 2023 64 | 65 | - [SECURITY FIX] CWE-1333: Inefficient Regular Expression Complexity #13 [`fc63a9f`](https://github.com/logue/vue-codemirror6/commit/fc63a9f14b5307089e9551157b011072971b112f) 66 | - Fix for #11 [`c634b55`](https://github.com/logue/vue-codemirror6/commit/c634b555ffff93bb30da2f501ec366289fc86ec1) 67 | - Add forceReconfigure() function. [`bbfa8ad`](https://github.com/logue/vue-codemirror6/commit/bbfa8adb5bd5cdb56a53bd69337a4e0313e52033) 68 | 69 | #### [1.1.3](https://github.com/logue/vue-codemirror6/compare/1.1.2...1.1.3) 70 | 71 | > 9 January 2023 72 | 73 | - Bump json5 from 1.0.1 to 1.0.2 [`#10`](https://github.com/logue/vue-codemirror6/pull/10) 74 | - Consolidated demo code generation settings into a single vite.config.ts [`7fe3ad2`](https://github.com/logue/vue-codemirror6/commit/7fe3ad25676eb34844b7bfe64b5dc73f30211a5b) 75 | - Update dependencies. [`75b984e`](https://github.com/logue/vue-codemirror6/commit/75b984e38c13114ce30b853fba64493c55368be3) 76 | 77 | #### [1.1.2](https://github.com/logue/vue-codemirror6/compare/1.1.1...1.1.2) 78 | 79 | > 24 December 2022 80 | 81 | - Update CHANGELOG.md. [`72efba5`](https://github.com/logue/vue-codemirror6/commit/72efba5e9e272da2dcb3bd941079ee415d1b4c53) 82 | - Minor fix. [`d1e3118`](https://github.com/logue/vue-codemirror6/commit/d1e3118ca2f2efe4d63f64e505d8a01a7c29a104) 83 | - Update dependencies. [`d747a21`](https://github.com/logue/vue-codemirror6/commit/d747a21778b42ed12921dd468a91a910895925e8) 84 | 85 | #### [1.1.1](https://github.com/logue/vue-codemirror6/compare/1.1.0...1.1.1) 86 | 87 | > 7 November 2022 88 | 89 | - Fixed Markdown demo. [`399f32c`](https://github.com/logue/vue-codemirror6/commit/399f32c95440b24c253110670d46811673cf38bd) 90 | - Fix cross-binding not works. [`137765b`](https://github.com/logue/vue-codemirror6/commit/137765b23c0b27ba3c4784d0708ee7172c94083a) 91 | - Fixed taking URL class from other than node when building docs. [`fbf1d56`](https://github.com/logue/vue-codemirror6/commit/fbf1d56296b4b739b7ff84107ec33eb3681a0398) 92 | 93 | #### [1.1.0](https://github.com/logue/vue-codemirror6/compare/1.0.3...1.1.0) 94 | 95 | > 31 October 2022 96 | 97 | - Rewrite the demo code with Vue3 setup. [`fdc7e3c`](https://github.com/logue/vue-codemirror6/commit/fdc7e3c172ff8f1710a74459b1ed7da70420b732) 98 | - Fixed wrong typing of computed value. [`9b5a572`](https://github.com/logue/vue-codemirror6/commit/9b5a572c5a18bfd3cf9cd5f4c0b0866efab9e893) 99 | - Add CHANGELOG.md. [`1de388f`](https://github.com/logue/vue-codemirror6/commit/1de388f5126a6afeaec250adefc82bc709251bbd) 100 | 101 | #### [1.0.3](https://github.com/logue/vue-codemirror6/compare/1.0.2...1.0.3) 102 | 103 | > 12 October 2022 104 | 105 | - Update dependencies. [`7f096da`](https://github.com/logue/vue-codemirror6/commit/7f096da24bfc50c9f2932cac6ad023d3982281bf) 106 | - Update demo code. [`ac33441`](https://github.com/logue/vue-codemirror6/commit/ac33441c2886664c11a91b5b838db74220f0b565) 107 | - Fixed vite.config.docs.ts. [`b13628a`](https://github.com/logue/vue-codemirror6/commit/b13628aeaa29df6c525b899776ae7706cdf800bc) 108 | 109 | #### [1.0.2](https://github.com/logue/vue-codemirror6/compare/1.0.1...1.0.2) 110 | 111 | > 15 September 2022 112 | 113 | - Enabled to specify HTML tags used in components. [`9b9eecd`](https://github.com/logue/vue-codemirror6/commit/9b9eecdb4da434295bf176c4c17d832871aba927) 114 | 115 | #### [1.0.1](https://github.com/logue/vue-codemirror6/compare/1.0.0...1.0.1) 116 | 117 | > 8 September 2022 118 | 119 | - Update dependencies. [`f3631d0`](https://github.com/logue/vue-codemirror6/commit/f3631d0c3c00a07ba8e69916116db1d611397fb9) 120 | - Disable drop console. [`e27b9ef`](https://github.com/logue/vue-codemirror6/commit/e27b9efea75180b3c6031c8e3a06c2bd5cee228b) 121 | 122 | ### [1.0.0](https://github.com/logue/vue-codemirror6/compare/0.6.8...1.0.0) 123 | 124 | > 20 August 2022 125 | 126 | - Fixed editable and readonly toggle. [`97ac1bf`](https://github.com/logue/vue-codemirror6/commit/97ac1bf8b24775daefb58af91c318771ea355c8d) 127 | - 1.0 [`4493c74`](https://github.com/logue/vue-codemirror6/commit/4493c744d38002fbca943f43b14985a3ae2c592c) 128 | 129 | #### [0.6.8](https://github.com/logue/vue-codemirror6/compare/0.6.5...0.6.8) 130 | 131 | > 1 August 2022 132 | 133 | - Unify props monitoring process. [`15b8a17`](https://github.com/logue/vue-codemirror6/commit/15b8a171cec652a03800fc9b53c9f3c5b78f74bf) 134 | - Fixed an error around linter. [`b2fe3db`](https://github.com/logue/vue-codemirror6/commit/b2fe3dba9f6edd3167edeeff08f34139e444ecd7) 135 | - Fixed dispatch may be executed multiple times when the value of prop is changed. [`2e19316`](https://github.com/logue/vue-codemirror6/commit/2e193168876e7e0da06695e68176433fd328c0b7) 136 | 137 | #### [0.6.5](https://github.com/logue/vue-codemirror6/compare/0.6.4...0.6.5) 138 | 139 | > 4 July 2022 140 | 141 | - Remove banner from source code. [`043e0ed`](https://github.com/logue/vue-codemirror6/commit/043e0ed0769c0b3bf52777e0d64199e713377418) 142 | - Delete unnecessary cursor movement processing and assignment processing. [`c89fd00`](https://github.com/logue/vue-codemirror6/commit/c89fd0020e241dca2d8292511a2b55ffbece5a82) 143 | 144 | #### [0.6.4](https://github.com/logue/vue-codemirror6/compare/0.6.0...0.6.4) 145 | 146 | > 28 June 2022 147 | 148 | - Fixed a bug that the cursor may move to a strange place when inputting. [`9977976`](https://github.com/logue/vue-codemirror6/commit/9977976678fda8a268a5c998f6bb95bdf0b86a1e) 149 | - Changed the logic when assigning text values to CodeMirror. [`313e701`](https://github.com/logue/vue-codemirror6/commit/313e70196573f9365519a7558cbc0f05c193a000) 150 | - Fixed the problem that the definition file was omitted because the binary output by analyze was given to npm. [`503a52e`](https://github.com/logue/vue-codemirror6/commit/503a52ef7c5077241b72909ee27afb262b52312e) 151 | 152 | #### [0.6.0](https://github.com/logue/vue-codemirror6/compare/0.5.5...0.6.0) 153 | 154 | > 9 June 2022 155 | 156 | - Added minimal prop. [`d454d25`](https://github.com/logue/vue-codemirror6/commit/d454d257c1fd04b765f5fdb555b240395fe030b5) 157 | - Migrate to CodeMirror 6.0.0. [`50cb696`](https://github.com/logue/vue-codemirror6/commit/50cb696dcc3af61d77a7e74ef37041d20bfb71fc) 158 | - Add methods jsdoc and manual. [`44975eb`](https://github.com/logue/vue-codemirror6/commit/44975ebedf76d1179ab2c1835e9f16b8e583a64a) 159 | 160 | #### [0.5.5](https://github.com/logue/vue-codemirror6/compare/0.5.4...0.5.5) 161 | 162 | > 8 June 2022 163 | 164 | - Urgent release. [`7db9007`](https://github.com/logue/vue-codemirror6/commit/7db9007886b5daeea94f7986d256291911b7a55c) 165 | 166 | #### [0.5.4](https://github.com/logue/vue-codemirror6/compare/0.5.3...0.5.4) 167 | 168 | > 31 May 2022 169 | 170 | - Fixed a bug that the cursor goes to a strange place when inputting. [`81af5b2`](https://github.com/logue/vue-codemirror6/commit/81af5b2e950cd972bfe540621fb75a6a8e18d544) 171 | 172 | #### [0.5.3](https://github.com/logue/vue-codemirror6/compare/0.5.2...0.5.3) 173 | 174 | > 31 May 2022 175 | 176 | - Fixed an issue where parent-to-child binding did not work properly. [`d355f2c`](https://github.com/logue/vue-codemirror6/commit/d355f2c7de4437360fdbf021029506d6cce4adba) 177 | - Changed the implementation to call the extension directly with a function. [`98d338f`](https://github.com/logue/vue-codemirror6/commit/98d338f05a48922529f15f9d706f9614447ff1cb) 178 | - The initial value of linter is set to simple undefined. [`6cec8b0`](https://github.com/logue/vue-codemirror6/commit/6cec8b000ce18a44a4077c375285a45df2993931) 179 | 180 | #### [0.5.2](https://github.com/logue/vue-codemirror6/compare/0.5.1...0.5.2) 181 | 182 | > 30 May 2022 183 | 184 | - Simplify extension processing. [`cd875ff`](https://github.com/logue/vue-codemirror6/commit/cd875ffdeffa072c6abb5b4e3964298bd490b582) 185 | - Since lintGutter is displayed even for components for which linter is not specified, lintGutter is made an option. [`ab16cbb`](https://github.com/logue/vue-codemirror6/commit/ab16cbb1472a5b29c572279a303a4baa593f4eb3) 186 | - Fixed innerText is undefined error. [`6466784`](https://github.com/logue/vue-codemirror6/commit/64667849779d0511a472cf8d116ecef8e51f1db8) 187 | 188 | #### [0.5.1](https://github.com/logue/vue-codemirror6/compare/0.5.0...0.5.1) 189 | 190 | > 28 May 2022 191 | 192 | - Fixed linter bug. [`03013b4`](https://github.com/logue/vue-codemirror6/commit/03013b44ce89ba455acafaceac68b2084fe364cf) 193 | 194 | #### [0.5.0](https://github.com/logue/vue-codemirror6/compare/0.3.7...0.5.0) 195 | 196 | > 27 May 2022 197 | 198 | - The output program is compatible with both Vue2 and Vue3.☺ [`7571423`](https://github.com/logue/vue-codemirror6/commit/7571423b0b4f6150300b184b3fc765cb3bf2e21b) 199 | 200 | #### [0.3.7](https://github.com/logue/vue-codemirror6/compare/0.3.6...0.3.7) 201 | 202 | > 26 May 2022 203 | 204 | - Change the formatting settings. [`42188a5`](https://github.com/logue/vue-codemirror6/commit/42188a5de4ddf1163789cdc2fbd255ed19487fad) 205 | - Update documents. [`5a78106`](https://github.com/logue/vue-codemirror6/commit/5a7810681c786020afdac8f5d8da8d15f8ad802c) 206 | - Update docs. [`15d7f8e`](https://github.com/logue/vue-codemirror6/commit/15d7f8e7e1edda995420485160cb9cfd4980fe74) 207 | 208 | #### [0.3.6](https://github.com/logue/vue-codemirror6/compare/0.3.2...0.3.6) 209 | 210 | > 19 May 2022 211 | 212 | - Rename serve.vue to DemoPage.vue. [`3ba582b`](https://github.com/logue/vue-codemirror6/commit/3ba582b6fa24259b49d1f123b79db185ab7e077a) 213 | - Fixed an issue where CodeMirror may not work properly during initial display. [`8092b64`](https://github.com/logue/vue-codemirror6/commit/8092b64039e9a3340624ca4e347151609c933a12) 214 | - Add basic and tab props. [`54eace6`](https://github.com/logue/vue-codemirror6/commit/54eace641678967163fdf93d051181f701167e0e) 215 | 216 | #### [0.3.2](https://github.com/logue/vue-codemirror6/compare/0.3.0...0.3.2) 217 | 218 | > 6 April 2022 219 | 220 | - When building with vue3, it doesn't work with vue2, so build with vue2. [`87be702`](https://github.com/logue/vue-codemirror6/commit/87be702b278df9cf0f5b26bb8307f7a6d592fd73) 221 | - Rewrite the wrapper part. [`1e77661`](https://github.com/logue/vue-codemirror6/commit/1e776619bb5f711a789bbe758d10142725de39aa) 222 | - Update sample. [`f7ed0a5`](https://github.com/logue/vue-codemirror6/commit/f7ed0a507175b6c0d79cf6be55fbd317c5c999b6) 223 | 224 | #### [0.3.0](https://github.com/logue/vue-codemirror6/compare/0.1.7...0.3.0) 225 | 226 | > 29 March 2022 227 | 228 | #### [0.1.7](https://github.com/logue/vue-codemirror6/compare/0.1.6...0.1.7) 229 | 230 | > 26 May 2022 231 | 232 | - Change Lint settings. [`89558c1`](https://github.com/logue/vue-codemirror6/commit/89558c1ad3a11bc5bd4ee55a11d6bd58022c99eb) 233 | 234 | #### [0.1.6](https://github.com/logue/vue-codemirror6/compare/0.1.2...0.1.6) 235 | 236 | > 19 May 2022 237 | 238 | - Follow changes in the master branch [`d7a9e3f`](https://github.com/logue/vue-codemirror6/commit/d7a9e3f9cfd7580bb78c29f96e1f2c84d77d5801) 239 | - Follow Vue3 version. [`1867c6c`](https://github.com/logue/vue-codemirror6/commit/1867c6c18fdc10f331e1dace37c5773242069150) 240 | - Since past values may be included, nextTick processing was added to onMouted. [`dac2bdd`](https://github.com/logue/vue-codemirror6/commit/dac2bdd1ea935141ed25b93c9882f6ecc871099e) 241 | 242 | #### [0.1.2](https://github.com/logue/vue-codemirror6/compare/0.1.0...0.1.2) 243 | 244 | > 6 April 2022 245 | 246 | - Squashed commit of the following: [`db4abdd`](https://github.com/logue/vue-codemirror6/commit/db4abdddda262a7fa4f69f028b423d13442cec68) 247 | - When building with vue3, it doesn't work with vue2, so build with vue2. [`87be702`](https://github.com/logue/vue-codemirror6/commit/87be702b278df9cf0f5b26bb8307f7a6d592fd73) 248 | - Rewrite the wrapper part. [`1e77661`](https://github.com/logue/vue-codemirror6/commit/1e776619bb5f711a789bbe758d10142725de39aa) 249 | 250 | #### [0.1.0](https://github.com/logue/vue-codemirror6/compare/0.0.6...0.1.0) 251 | 252 | > 18 March 2022 253 | 254 | - Update Samples. (run `yarn run dev`) [`f658c65`](https://github.com/logue/vue-codemirror6/commit/f658c654f2910a133914f2fa0fdc8206dadb7232) 255 | - Fixed IME probrem. [`7a42e63`](https://github.com/logue/vue-codemirror6/commit/7a42e63f75748039ebb082732fe46cd7967f32d7) 256 | 257 | #### [0.0.6](https://github.com/logue/vue-codemirror6/compare/0.0.5...0.0.6) 258 | 259 | > 17 March 2022 260 | 261 | - Fixed d.ts file destination. [`2cd9cdf`](https://github.com/logue/vue-codemirror6/commit/2cd9cdf3f0658d62ae434600e4e8cda14c407a47) 262 | 263 | #### [0.0.5](https://github.com/logue/vue-codemirror6/compare/0.0.4...0.0.5) 264 | 265 | > 17 March 2022 266 | 267 | - Fixed a bug that the cursor position may be at the top when entering a key. [`e7f5407`](https://github.com/logue/vue-codemirror6/commit/e7f5407c76185cc805c10fc0366c5e6dff5f44f6) 268 | 269 | #### [0.0.4](https://github.com/logue/vue-codemirror6/compare/0.0.2...0.0.4) 270 | 271 | > 16 February 2022 272 | 273 | - Update demo code. [`599fa5f`](https://github.com/logue/vue-codemirror6/commit/599fa5f4d87cc7783c98f56a9436a314b368fb64) 274 | - Removed code that depends on other libraries from the output code. [`7d9e383`](https://github.com/logue/vue-codemirror6/commit/7d9e383c17f31ed8721f94711e7cd1dc595f9e07) 275 | - Add demo code. [`3e06ef7`](https://github.com/logue/vue-codemirror6/commit/3e06ef70f5ed30fce5a6cb72add2b41fea2745fe) 276 | 277 | #### [0.0.2](https://github.com/logue/vue-codemirror6/compare/0.0.1...0.0.2) 278 | 279 | > 14 February 2022 280 | 281 | - Update package.json. Fixed typing settings. [`12ead23`](https://github.com/logue/vue-codemirror6/commit/12ead23c53c0a5ebc5a68c3bee7b192b587efafc) 282 | 283 | #### 0.0.1 284 | 285 | > 10 February 2022 286 | 287 | - Initial commit. [`b410884`](https://github.com/logue/vue-codemirror6/commit/b41088482f82615e9380e6231a59a39387d172a2) 288 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-2025 Masashi Yoshikawa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-codemirror6 2 | 3 |
4 |
5 |
` tag to prevent the text in the slot from being automatically formatted. 172 | 173 | ```vue 174 | 175 |176 | 182 | 183 | 184 | 202 | ``` 203 | 204 | ### Full Example 205 | 206 | When using as a Markdown editor on [vite-vue3-ts-starter](https://github.com/logue/vite-vue3-ts-starter). 207 | 208 | ```vue 209 | 281 | 282 | 283 |177 | { 178 | "key": "value" 179 | }181 |290 | 291 | ``` 292 | 293 | ## Events 294 | 295 | | Event | Description | 296 | | ------ | ------------------------------------------------------------------------------------------------------------- | 297 | | ready | When CodeMirror loaded. | 298 | | focus | When focus changed. | 299 | | update | When CodeMirror state changed. Returns [ViewUpdate](https://codemirror.net/docs/ref/#view.ViewUpdate) object. | 300 | | change | Value changed. Returns [EditorState](https://codemirror.net/docs/ref/#state.EditorState) | 301 | 302 | ## Parameter / Function 303 | 304 | ```vue 305 | 315 | 316 | 317 | 318 | ``` 319 | 320 | | Function / Parameter | Description | 321 | | -------------------- | --------------------------------------------------------------------------------------------------- | 322 | | view | Get and set [EditorView](https://codemirror.net/docs/ref/#view.EditorView). | 323 | | selection | Get and set the [EditorSelection](https://codemirror.net/docs/ref/#state.EditorSelection) instance. | 324 | | cursor | Get and set the [cursor](https://codemirror.net/docs/ref/#state.EditorSelection^cursor) location. | 325 | | json | Get and set state to a JSON-serializable object. | 326 | | focus | Get and set [focus](https://codemirror.net/docs/ref/#view.EditorView.focus). | 327 | | lint() | Force run linter (Only if `linter` prop is specified) | 328 | | forceReconfigure() | Re register all extensions. | 329 | 330 | ### CodeMirror5 backward compatible functions 331 | 332 | The instructions below are compatible methods for those familiar with [codemirror5](https://codemirror.net/5/). 333 | Since the above method is usually sufficient, its **active use is not recommended**. 334 | 335 | | Function | Description | 336 | | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | 337 | | getRange(from?: number, to?: number) | Get the text between the given points in the editor. | 338 | | getLine(number: number) | Get the content of line. | 339 | | lineCount() | Get the number of lines in the editor. | 340 | | getCursor() | Retrieve one end of the primary selection. | 341 | | listSelections() | Retrieves a list of all current selections. | 342 | | getSelection() | Get the currently selected code. | 343 | | getSelections() | The length of the given array should be the same as the number of active selections. | 344 | | somethingSelected() | Return true if any text is selected. | 345 | | replaceRange(replacement: string \| Text, from: number, to: number) | Replace the part of the document between from and to with the given string. | 346 | | replaceSelection(replacement: string \| Text) | Replace the selection(s) with the given string. | 347 | | setCursor(position: number) | Set the cursor position. | 348 | | setSelection(anchor: number, head?: number) | Set a single selection range. | 349 | | setSelections(ranges: readonly SelectionRange[], primary?: number) | Sets a new set of selections. | 350 | | extendSelectionsBy(f: Function) | Applies the given function to all existing selections, and calls extendSelections on the result. | 351 | 352 | ## Recommendations 353 | 354 | Since CodeMirror has a relatively large capacity, when using [vite](https://vitejs.dev), it is recommended to set it to output as a separate file using the [`manualChunks`](https://vitejs.dev/guide/build.html#chunking-strategy) option at build time as shown below. 355 | 356 | ```ts 357 | const config: UserConfig = { 358 | // ... 359 | build: { 360 | rollupOptions: { 361 | output: { 362 | manualChunks: { 363 | // ... 364 | codemirror: ['vue-codemirror6'], 365 | 'codemirror-lang': [ 366 | // Add the following as needed. 367 | '@codemirror/lang-html', 368 | '@codemirror/lang-javascript', 369 | '@codemirror/lang-markdown', 370 | ], 371 | // ... 372 | }, 373 | }, 374 | }, 375 | }, 376 | // ... 377 | }; 378 | ``` 379 | 380 | ## LICENSE 381 | 382 | ©2022-2025 by Logue. 383 | Licensed under the [MIT License](LICENSE). 384 | -------------------------------------------------------------------------------- /env.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | /// 3 | 4 | declare module '*.vue' { 5 | import Vue from 'vue'; 6 | export default Vue; 7 | } 8 | interface ImportMetaEnv { 9 | // see https://vitejs.dev/guide/env-and-mode.html#env-files 10 | // add .env variables. 11 | } 12 | 13 | interface ImportMeta { 14 | readonly env: ImportMetaEnv; 15 | } 16 | -------------------------------------------------------------------------------- /eslint.config.ts: -------------------------------------------------------------------------------- 1 | import configPrettier from '@vue/eslint-config-prettier'; 2 | import { 3 | defineConfigWithVueTs, 4 | vueTsConfigs, 5 | } from '@vue/eslint-config-typescript'; 6 | 7 | // @ts-ignore 8 | import pluginImport from 'eslint-plugin-import'; 9 | import pluginVue from 'eslint-plugin-vue'; 10 | import pluginVueA11y from 'eslint-plugin-vuejs-accessibility'; 11 | 12 | // To allow more languages other than `ts` in `.vue` files, uncomment the following lines: 13 | // import { configureVueProject } from '@vue/eslint-config-typescript' 14 | // configureVueProject({ scriptLangs: ['ts', 'tsx'] }) 15 | // More info at https://github.com/vuejs/eslint-config-typescript/#advanced-setup 16 | 17 | /** 18 | * ESLint Config 19 | */ 20 | export default defineConfigWithVueTs( 21 | { 22 | name: 'app/files-to-lint', 23 | files: ['**/*.{ts,mts,tsx,vue}'], 24 | }, 25 | { 26 | name: 'app/files-to-ignore', 27 | ignores: [ 28 | '.vscode/', 29 | '.yarn/', 30 | '**/dist/**', 31 | '**/dist-ssr/**', 32 | '**/coverage/**', 33 | 'eslint.config.js', 34 | 'pnpm-lock.yaml', 35 | 'playwright-report', 36 | 'test-results', 37 | 'public/', 38 | 'src/**/*.generated.*', 39 | 'docs', 40 | ], 41 | }, 42 | pluginVue.configs['flat/recommended'], 43 | ...pluginVueA11y.configs['flat/recommended'], 44 | vueTsConfigs.recommended, 45 | { 46 | plugins: { 47 | import: pluginImport, 48 | }, 49 | 50 | settings: { 51 | // This will do the trick 52 | 'import/parsers': { 53 | espree: ['.js', '.cjs', '.mjs', '.jsx'], 54 | '@typescript-eslint/parser': ['.ts', '.tsx'], 55 | 'vue-eslint-parser': ['.vue'], 56 | }, 57 | 'import/resolver': { 58 | typescript: true, 59 | node: true, 60 | 'eslint-import-resolver-custom-alias': { 61 | alias: { 62 | '@': './src', 63 | '~': './node_modules', 64 | }, 65 | extensions: ['.js', '.ts', '.jsx', '.tsx', '.vue'], 66 | }, 67 | }, 68 | vite: { 69 | configPath: './vite.config.ts', 70 | }, 71 | }, 72 | rules: { 73 | // ...importPlugin.configs["recommended"].rules, 74 | 'no-unused-vars': 'warn', 75 | // const lines: string[] = []; style 76 | '@typescript-eslint/array-type': [ 77 | 'error', 78 | { 79 | default: 'array', 80 | }, 81 | ], 82 | // Enable @ts-ignore etc. 83 | '@typescript-eslint/ban-ts-comment': 'off', 84 | // Left-hand side style 85 | '@typescript-eslint/consistent-generic-constructors': [ 86 | 'error', 87 | 'type-annotation', 88 | ], 89 | // Enable import sort order, see bellow. 90 | '@typescript-eslint/consistent-type-imports': [ 91 | 'off', 92 | { 93 | prefer: 'type-imports', 94 | }, 95 | ], 96 | // Fix for pinia 97 | '@typescript-eslint/explicit-function-return-type': 'off', 98 | '@typescript-eslint/no-explicit-any': 'off', 99 | // Exclude variables with leading underscores 100 | '@typescript-eslint/no-unused-vars': [ 101 | 'error', 102 | { 103 | args: 'all', 104 | argsIgnorePattern: '^_', 105 | caughtErrors: 'all', 106 | caughtErrorsIgnorePattern: '^_', 107 | destructuredArrayIgnorePattern: '^_', 108 | varsIgnorePattern: '^_', 109 | ignoreRestSiblings: true, 110 | }, 111 | ], 112 | // Fix for vite import.meta.env 113 | '@typescript-eslint/strict-boolean-expressions': 'off', 114 | // Fix for vite env.d.ts. 115 | '@typescript-eslint/triple-slash-reference': 'off', 116 | // Fix for Vue setup style 117 | 'import/default': 'off', 118 | // Fix for Vue setup style 119 | 'import/no-default-export': 'off', 120 | // Sort Import Order. 121 | // see https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/order.md#importorder-enforce-a-convention-in-module-import-order 122 | 'import/order': [ 123 | 'error', 124 | { 125 | groups: [ 126 | 'builtin', 127 | 'external', 128 | 'parent', 129 | 'sibling', 130 | 'index', 131 | 'object', 132 | 'type', 133 | ], 134 | pathGroups: [ 135 | // Vue Core 136 | { 137 | pattern: 138 | '{vue,vue-router,vuex,@/store,vue-i18n,pinia,vite,vitest,vitest/**,@vitejs/**,@vue/**}', 139 | group: 'external', 140 | position: 'before', 141 | }, 142 | // Internal Codes 143 | { 144 | pattern: '{@/**}', 145 | group: 'internal', 146 | position: 'before', 147 | }, 148 | ], 149 | pathGroupsExcludedImportTypes: ['builtin'], 150 | alphabetize: { 151 | order: 'asc', 152 | }, 153 | 'newlines-between': 'always', 154 | }, 155 | ], 156 | // A tag with no content should be written like
. 157 | 'vue/html-self-closing': [ 158 | 'error', 159 | { 160 | html: { 161 | void: 'always', 162 | }, 163 | }, 164 | ], 165 | // Mitigate non-multiword component name errors to warnings. 166 | 'vue/multi-word-component-names': 'warn', 167 | // allow model-value 168 | 'vue/no-deprecated-model-definition': [ 169 | 'error', 170 | { 171 | allowVue3Compat: true, 172 | }, 173 | ], 174 | }, 175 | }, 176 | configPrettier 177 | ); 178 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |Vue CodeMirror6 Demo 9 | 10 | 14 | 22 | 23 | 24 | 25 |26 | We're sorry but this site doesn't work properly without JavaScript 27 | enabled. Please enable it to continue. 28 |29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/package.json", 3 | "name": "vue-codemirror6", 4 | "version": "1.3.17", 5 | "license": "MIT", 6 | "description": "CodeMirror6 Component for vue2 and vue3.", 7 | "keywords": [ 8 | "vuejs", 9 | "vue", 10 | "vue-components", 11 | "vue-codemirror", 12 | "code-editor", 13 | "text-editor", 14 | "vue2", 15 | "vue3", 16 | "web-editor", 17 | "vue-plugin", 18 | "vue-component", 19 | "codemirror-editor", 20 | "vue-resource", 21 | "codemirror6" 22 | ], 23 | "type": "module", 24 | "author": { 25 | "name": "Logue", 26 | "email": "logue@hotmail.co.jp", 27 | "url": "https://logue.dev/" 28 | }, 29 | "homepage": "https://github.com/logue/vue-codemirror6", 30 | "repository": { 31 | "type": "git", 32 | "url": "git+ssh://git@github.com/logue/vue-codemirror6.git" 33 | }, 34 | "bugs": { 35 | "url": "https://github.com/logue/vue-codemirror6/issues" 36 | }, 37 | "main": "dist/index.umd.js", 38 | "module": "dist/index.es.js", 39 | "jsdelivr": "dist/index.iife.js", 40 | "unpkg": "dist/index.iife.js", 41 | "types": "dist/index.d.ts", 42 | "exports": { 43 | ".": { 44 | "import": "./dist/index.es.js", 45 | "types": "./dist/index.d.ts" 46 | } 47 | }, 48 | "files": [ 49 | "CHANGELOG.md", 50 | "/dist", 51 | "./src/components/CodeMirror.ts" 52 | ], 53 | "browser": { 54 | "./sfc": "./src/components/CodeMirror.ts" 55 | }, 56 | "engines": { 57 | "pnpm": ">=10.3.0" 58 | }, 59 | "packageManager": "pnpm@10.11.0", 60 | "sideEffects": false, 61 | "scripts": { 62 | "dev": "vite", 63 | "clean": "rimraf node_modules/.vite", 64 | "build": "run-p type-check \"build-only {@}\" --", 65 | "build:analyze": "vite build --mode=analyze", 66 | "build:clean": "rimraf dist docs", 67 | "build:docs": "vite build --mode=docs", 68 | "lint": "eslint . --fix --cache --cache-location ./node_modules/.vite/vite-plugin-eslint && prettier . --write", 69 | "preview": "vite preview --mode=docs", 70 | "build-only": "vite build", 71 | "type-check": "vue-tsc --declaration --emitDeclarationOnly", 72 | "prepare": "husky", 73 | "version": "auto-changelog -p && git add CHANGELOG.md" 74 | }, 75 | "dependencies": { 76 | "@codemirror/autocomplete": "^6.18.6", 77 | "@codemirror/commands": "^6.8.1", 78 | "@codemirror/language": "^6.11.0", 79 | "@codemirror/lint": "^6.8.5", 80 | "@codemirror/search": "^6.5.11", 81 | "@codemirror/state": "^6.5.2", 82 | "@codemirror/view": "^6.37.1", 83 | "codemirror": "^6.0.1", 84 | "style-mod": "^4.1.2", 85 | "vue-demi": "latest" 86 | }, 87 | "peerDependencies": { 88 | "vue": "^2.7.14 || ^3.4" 89 | }, 90 | "devDependencies": { 91 | "@codemirror/lang-javascript": "^6.2.4", 92 | "@codemirror/lang-json": "^6.0.1", 93 | "@codemirror/lang-markdown": "^6.3.2", 94 | "@codemirror/lang-vue": "^0.1.3", 95 | "@tsconfig/node-lts": "^22.0.1", 96 | "@types/node": "^22.15.29", 97 | "@vitejs/plugin-vue": "^5.2.4", 98 | "@vue/compiler-sfc": "^3.5.16", 99 | "@vue/eslint-config-prettier": "^10.2.0", 100 | "@vue/eslint-config-typescript": "^14.5.0", 101 | "@vue/test-utils": "^2.4.6", 102 | "@vue/tsconfig": "^0.7.0", 103 | "@vueuse/core": "^13.3.0", 104 | "bootstrap": "^5.3.6", 105 | "eslint": "^9.28.0", 106 | "eslint-import-resolver-custom-alias": "^1.3.2", 107 | "eslint-import-resolver-typescript": "^4.4.2", 108 | "eslint-linter-browserify": "^9.28.0", 109 | "eslint-plugin-import": "^2.31.0", 110 | "eslint-plugin-playwright": "^2.2.0", 111 | "eslint-plugin-vue": "^10.1.0", 112 | "eslint-plugin-vuejs-accessibility": "^2.4.1", 113 | "husky": "^9.1.7", 114 | "jiti": "^2.4.2", 115 | "lint-staged": "^16.1.0", 116 | "npm-run-all2": "^8.0.4", 117 | "prettier": "^3.5.3", 118 | "rimraf": "^6.0.1", 119 | "rollup-plugin-visualizer": "^6.0.1", 120 | "sass": "^1.89.1", 121 | "supports-color": "^10.0.0", 122 | "typescript": "^5.8.3", 123 | "typescript-eslint": "^8.33.0", 124 | "vite": "^6.3.5", 125 | "vite-plugin-banner": "^0.8.1", 126 | "vite-plugin-checker": "^0.9.3", 127 | "vite-plugin-dts": "^4.5.4", 128 | "vue": "^3.5.16", 129 | "vue-eslint-parser": "^10.1.3", 130 | "vue-markdown-wasm": "^0.5.1", 131 | "vue-tsc": "^2.2.10" 132 | }, 133 | "husky": { 134 | "hooks": { 135 | "pre-commit": "lint-staged" 136 | } 137 | }, 138 | "lint-staged": { 139 | "*.{js,ts,json,htm,html,vue}": "eslint --fix --cache --cache-location ./node_modules/.vite/vite-plugin-eslint", 140 | "*": "prettier -w -u" 141 | }, 142 | "resolutions": { 143 | "json5": ">=2.2.3", 144 | "yaml": ">=2.6.0" 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | onlyBuiltDependencies: 2 | - esbuild 3 | - unrs-resolver 4 | - vue-demi 5 | -------------------------------------------------------------------------------- /public/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /src-docs/App.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 47 |48 | 58 | 59 |49 |57 |Vue CodeMirror6 Demo
50 |51 | A rough demo of Vue CodeMirror6 in action. You can switch between dark 52 | modes from the 53 | 54 | icon in the upper right. 55 |
56 |60 | 62 | 63 | 72 | 73 | 74 | 79 | -------------------------------------------------------------------------------- /src-docs/DemoPage.vue: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 |61 | 27 |215 | 216 | -------------------------------------------------------------------------------- /src-docs/components/LinterAndCrossBindingDemo.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 47 | 48 |28 | 90 |Markdown Editor Demo
29 |30 | This is an example of simply pouring text into CodeMirror using 31 |
34 |v-model
32 | . 33 |35 |
49 |basic
36 | is an alias for loading 37 | 41 | basic-setup 42 | 43 | . 44 |
45 | Use 46 |wrap
47 | when you want to use columns. (Enable text wrapping) 48 |57 | Demo
58 |59 | 60 |89 |61 | 76 |77 |78 | The process of converting Markdown to HTML uses 79 | 80 | vue-markdown-wasm 81 | 82 | . 83 |88 |
84 | Full demo is 85 | here 86 | . 87 |91 | 115 |Slot Method
92 |93 | In this sample, the text is put directly inside the 94 |
99 |<code-mirror>
95 | tag to make it the initial string. On the Vue side, it is evaluated as a 96 | DOM node and only the text node is used as the value. In addition, it 97 | does not work with Vue2.7. 98 |100 | It's just for simple syntax highlighting. Do not use with 101 |
104 |v-model
102 | . 103 |112 | Sample
113 |114 | 116 | 169 |Linter and cross binding demo
117 |This is a sample using JavaScript and linter.
118 |119 | When using 120 |
123 |gutter
121 | prop, 🔴 is displayed on the line with the error. 122 |124 | This sample uses 125 | 129 | eslint-linter-browserify 130 | 131 | for the eslint linter. 132 |
133 |141 | Sample
142 |Make sure you see 🔴 when you change the value to get an error.
143 |144 | The value of 145 |
155 |@update
146 | gets the 147 | 151 | ViewUpdate 152 | 153 | object at that time when there is any update in the target form. 154 |156 | In this demo code, the 157 | 161 | diagnosticCount 162 | 163 | function is used to display the count of locations where grammatical 164 | errors are found. 165 |
166 |167 | Also, make sure that changing either value reflects that value.
168 |170 | 214 |171 | Toggle 172 |
177 |readonly
173 | and 174 |disabled
175 | a demo 176 |178 | 182 |
197 |readonly
183 | 184 | a specifies whether the state is rewritable or not. Similar to 185 |disabled
186 | (Inverse value of 187 | 191 |editable
192 | 193 | ) , except that it is focusable. In short, add 194 |disabled
195 | prop to if you want to use it as a simple syntax highlighter. 196 |198 |213 |199 |208 |207 | 209 |212 |Demo
210 |211 | 49 |109 |50 |104 |62 | 63 |103 |64 |75 |65 | 66 | 73 |74 |76 |89 |77 | 80 | 87 |88 |90 |102 |91 | 99 | 100 |101 |105 | 106 | 107 |108 |110 | Ctrl-Shift-m 111 | ( 112 | Cmd-Shift-m 113 | on macOS) to show lint panel. 114 | F8 115 | key shows the next error. 116 |
117 | 118 | -------------------------------------------------------------------------------- /src-docs/components/MarkdownDemo.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 25 |26 |40 | 41 | 42 | 95 | -------------------------------------------------------------------------------- /src-docs/components/ReadonlyAndDisabledDemo.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 16 | 17 | 18 |27 |36 |35 | 37 |39 |38 | 19 | 27 | 28 |29 |30 | 38 | 39 |40 |41 | 48 | 49 | -------------------------------------------------------------------------------- /src-docs/components/SlotDemo.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 |42 | 色は匂へど 散りぬるを 43 | 我が世誰そ 常ならむ 44 | 有為の奥山 今日越えて 45 | 浅き夢見じ 酔ひもせず47 |19 | 29 | 30 | -------------------------------------------------------------------------------- /src-docs/components/ToggleTheme.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | 22 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src-docs/main.ts: -------------------------------------------------------------------------------- 1 | import './style.scss'; 2 | 3 | /** Demo Code */ 4 | import { createApp } from 'vue'; 5 | 6 | import App from './App.vue'; 7 | 8 | createApp(App).mount('#app'); 9 | -------------------------------------------------------------------------------- /src-docs/style.scss: -------------------------------------------------------------------------------- 1 | // 1. Include functions first (so you can manipulate colors, SVGs, calc, etc) 2 | @import '~/bootstrap/scss/functions'; 3 | 4 | // 2. Include any default variable overrides here 5 | 6 | // 3. Include remainder of required Bootstrap stylesheets (including any separate color mode stylesheets) 7 | @import '~/bootstrap/scss/variables'; 8 | @import '~/bootstrap/scss/variables-dark'; 9 | 10 | // 4. Include any default map overrides here 11 | 12 | // 5. Include remainder of required parts 13 | @import '~/bootstrap/scss/maps'; 14 | @import '~/bootstrap/scss/mixins'; 15 | @import '~/bootstrap/scss/root'; 16 | 17 | // 6. Optionally include any other parts as needed 18 | @import '~/bootstrap/scss/utilities'; 19 | @import '~/bootstrap/scss/reboot'; 20 | // @import '~/bootstrap/scss/type'; 21 | @import '~/bootstrap/scss/forms'; 22 | // @import '~/bootstrap/scss/dropdown'; 23 | @import '~/bootstrap/scss/alert'; 24 | @import '~/bootstrap/scss/nav'; 25 | @import '~/bootstrap/scss/navbar'; 26 | @import '~/bootstrap/scss/containers'; 27 | @import '~/bootstrap/scss/grid'; 28 | @import '~/bootstrap/scss/helpers'; 29 | 30 | // 7. Optionally include utilities API last to generate classes based on the Sass map in `_utilities.scss` 31 | @import '~/bootstrap/scss/utilities/api'; 32 | 33 | // 8. Add additional custom code here 34 | .vue-codemirror * { 35 | font-family: var(--bs-font-monospace); 36 | } 37 | -------------------------------------------------------------------------------- /src/components/CodeMirror.ts: -------------------------------------------------------------------------------- 1 | import { indentWithTab } from '@codemirror/commands'; 2 | import { indentUnit, type LanguageSupport } from '@codemirror/language'; 3 | import { 4 | diagnosticCount as linterDiagnosticCount, 5 | forceLinting, 6 | linter, 7 | lintGutter, 8 | type Diagnostic, 9 | type LintSource, 10 | } from '@codemirror/lint'; 11 | import { 12 | Compartment, 13 | EditorSelection, 14 | EditorState, 15 | StateEffect, 16 | type Transaction, 17 | type Extension, 18 | type SelectionRange, 19 | type StateField, 20 | type Text, 21 | } from '@codemirror/state'; 22 | import { 23 | EditorView, 24 | keymap, 25 | placeholder, 26 | type ViewUpdate, 27 | } from '@codemirror/view'; 28 | import { basicSetup, minimalSetup } from 'codemirror'; 29 | import { 30 | computed, 31 | defineComponent, 32 | nextTick, 33 | onMounted, 34 | onUnmounted, 35 | ref, 36 | shallowRef, 37 | watch, 38 | type ComputedRef, 39 | type PropType, 40 | type Ref, 41 | type ShallowRef, 42 | type WritableComputedRef, 43 | } from 'vue-demi'; 44 | 45 | import type { StyleSpec } from 'style-mod'; 46 | 47 | import h, { slot } from '@/helpers/h-demi'; 48 | 49 | /** CodeMirror Component */ 50 | export default defineComponent({ 51 | /** Component Name */ 52 | name: 'CodeMirror', 53 | /** Model Definition */ 54 | model: { 55 | prop: 'modelValue', 56 | event: 'update:modelValue', 57 | }, 58 | /** Props Definition */ 59 | props: { 60 | /** Model value */ 61 | modelValue: { 62 | type: String as PropType{ 20 | "@schema": "https://json.schemastore.org/jsonld.json", 21 | "@context": "http://schema.org", 22 | "@type": "WebSite", 23 | "name": "vue-codemirror6 Demo", 24 | "url": "https://github.com/logue/vue-codemirror6", 25 | "description": "CodeMirror6 for Vue3 and Vue2 component" 26 | }28 |, 63 | default: '', 64 | }, 65 | /** 66 | * Theme 67 | * 68 | * @see {@link https://codemirror.net/docs/ref/#view.EditorView^theme} 69 | */ 70 | theme: { 71 | type: Object as PropType >, 72 | default: () => { 73 | return {}; 74 | }, 75 | }, 76 | /** Dark Mode */ 77 | dark: { 78 | type: Boolean, 79 | default: false, 80 | }, 81 | /** 82 | * Use Basic Setup 83 | * 84 | * @see {@link https://codemirror.net/docs/ref/#codemirror.basicSetup} 85 | */ 86 | basic: { 87 | type: Boolean, 88 | default: false, 89 | }, 90 | /** 91 | * Use Minimal Setup (The basic setting has priority.) 92 | * 93 | * @see {@link https://codemirror.net/docs/ref/#codemirror.minimalSetup} 94 | */ 95 | minimal: { 96 | type: Boolean, 97 | default: false, 98 | }, 99 | /** 100 | * Placeholder 101 | * 102 | * @see {@link https://codemirror.net/docs/ref/#view.placeholder} 103 | */ 104 | placeholder: { 105 | type: String as PropType , 106 | default: undefined, 107 | }, 108 | /** 109 | * Line wrapping 110 | * 111 | * An extension that enables line wrapping in the editor (by setting CSS white-space to pre-wrap in the content). 112 | * 113 | * @see {@link https://codemirror.net/docs/ref/#view.EditorView%5ElineWrapping} 114 | */ 115 | wrap: { 116 | type: Boolean, 117 | default: false, 118 | }, 119 | /** 120 | * Allow tab key indent. 121 | * 122 | * @see {@link https://codemirror.net/examples/tab/} 123 | */ 124 | tab: { 125 | type: Boolean, 126 | default: false, 127 | }, 128 | /** 129 | * Tab character 130 | */ 131 | indentUnit: { 132 | type: String, 133 | default: undefined, 134 | }, 135 | /** 136 | * Allow Multiple Selection. 137 | * 138 | * @see {@link https://codemirror.net/docs/ref/#state.EditorState^allowMultipleSelections} 139 | */ 140 | allowMultipleSelections: { 141 | type: Boolean, 142 | default: false, 143 | }, 144 | /** 145 | * Tab size 146 | * 147 | * @see {@link https://codemirror.net/docs/ref/#state.EditorState^tabSize} 148 | */ 149 | tabSize: { 150 | type: Number, 151 | default: undefined, 152 | }, 153 | /** 154 | * Set line break (separetor) char. 155 | * 156 | * @see {@link https://codemirror.net/docs/ref/#state.EditorState^lineSeparator} 157 | */ 158 | lineSeparator: { 159 | type: String, 160 | default: undefined, 161 | }, 162 | /** 163 | * Readonly 164 | * 165 | * @see {@link https://codemirror.net/docs/ref/#state.EditorState^readOnly} 166 | */ 167 | readonly: { 168 | type: Boolean, 169 | default: false, 170 | }, 171 | /** 172 | * Disable input. 173 | * 174 | * This is the reversed value of the CodeMirror editable. 175 | * Similar to `readonly`, but setting this value to true disables dragging. 176 | * 177 | * @see {@link https://codemirror.net/docs/ref/#view.EditorView^editable} 178 | */ 179 | disabled: { 180 | type: Boolean, 181 | default: false, 182 | }, 183 | /** 184 | * Additional Extension 185 | * 186 | * @see {@link https://codemirror.net/docs/ref/#state.Extension} 187 | */ 188 | extensions: { 189 | type: Array as PropType , 190 | default: () => { 191 | return []; 192 | }, 193 | }, 194 | /** 195 | * Language Phreses 196 | * 197 | * @see {@link https://codemirror.net/examples/translate/} 198 | */ 199 | phrases: { 200 | type: Object as PropType >, 201 | default: undefined, 202 | }, 203 | /** 204 | * CodeMirror Language 205 | * 206 | * @see {@link https://codemirror.net/docs/ref/#language} 207 | */ 208 | lang: { 209 | type: Object as PropType , 210 | default: undefined, 211 | }, 212 | /** 213 | * CodeMirror Linter 214 | * 215 | * @see {@link https://codemirror.net/docs/ref/#lint.linter} 216 | */ 217 | linter: { 218 | type: Function as PropType , 219 | default: undefined, 220 | }, 221 | /** 222 | * Linter Config 223 | * 224 | * @see {@link https://codemirror.net/docs/ref/#lint.linter^config} 225 | */ 226 | linterConfig: { 227 | type: Object, 228 | default: () => { 229 | return {}; 230 | }, 231 | }, 232 | /** 233 | * Forces any linters configured to run when the editor is idle to run right away. 234 | * 235 | * @see {@link https://codemirror.net/docs/ref/#lint.forceLinting} 236 | */ 237 | forceLinting: { 238 | type: Boolean, 239 | default: false, 240 | }, 241 | /** 242 | * Show Linter Gutter 243 | * 244 | * An area to 🔴 the lines with errors will be displayed. 245 | * This feature is not enabled if `linter` is not specified. 246 | * 247 | * @see {@link https://codemirror.net/docs/ref/#lint.lintGutter} 248 | */ 249 | gutter: { 250 | type: Boolean, 251 | default: false, 252 | }, 253 | /** 254 | * Gutter Config 255 | * 256 | * @see {@link https://codemirror.net/docs/ref/#lint.lintGutter^config} 257 | */ 258 | gutterConfig: { 259 | type: Object, 260 | default: undefined, 261 | }, 262 | /** 263 | * Using tag 264 | */ 265 | tag: { 266 | type: String, 267 | default: 'div', 268 | }, 269 | /** 270 | * Allows an external update to scroll the form. 271 | * @see {@link https://codemirror.net/docs/ref/#state.TransactionSpec.scrollIntoView} 272 | */ 273 | scrollIntoView: { 274 | type: Boolean, 275 | default: true, 276 | }, 277 | }, 278 | /** Emits */ 279 | emits: { 280 | /** Model Update */ 281 | 'update:modelValue': (_value: string | Text = '') => true, 282 | /** CodeMirror ViewUpdate */ 283 | update: (_value: ViewUpdate) => true, 284 | /** CodeMirror onReady */ 285 | ready: (_value: { 286 | view: EditorView; 287 | state: EditorState; 288 | container: HTMLElement; 289 | }) => true, 290 | /** CodeMirror onFocus */ 291 | focus: (_value: boolean) => true, 292 | /** State Changed */ 293 | change: (_value: EditorState) => true, 294 | /** CodeMirror onDestroy */ 295 | destroy: () => true, 296 | }, 297 | /** 298 | * Setup 299 | * 300 | * @param props - Props 301 | * @param context - Context 302 | */ 303 | setup(props, context) { 304 | /** Editor DOM */ 305 | const editor: Ref = ref(); 306 | 307 | /** Internal value */ 308 | const doc: Ref = ref(props.modelValue); 309 | 310 | /** 311 | * CodeMirror Editor View 312 | * 313 | * @see {@link https://codemirror.net/docs/ref/#view.EditorView} 314 | */ 315 | const view: ShallowRef = shallowRef(new EditorView()); 316 | 317 | /** 318 | * Focus 319 | * 320 | * @see {@link https://codemirror.net/docs/ref/#view.EditorView.hasFocus} 321 | */ 322 | const focus: WritableComputedRef = computed({ 323 | get: () => view.value.hasFocus, 324 | set: f => { 325 | if (f) { 326 | view.value.focus(); 327 | } 328 | }, 329 | }); 330 | 331 | /** 332 | * Editor Selection 333 | * 334 | * @see {@link https://codemirror.net/docs/ref/#state.EditorSelection} 335 | */ 336 | const selection: WritableComputedRef = computed({ 337 | get: () => view.value.state.selection, 338 | set: s => view.value.dispatch({ selection: s }), 339 | }); 340 | 341 | /** Cursor Position */ 342 | const cursor: WritableComputedRef = computed({ 343 | get: () => view.value.state.selection.main.head, 344 | set: a => view.value.dispatch({ selection: { anchor: a } }), 345 | }); 346 | 347 | /** JSON */ 348 | const json: WritableComputedRef >> = computed( 349 | { 350 | get: () => view.value.state.toJSON(), 351 | set: j => view.value.setState(EditorState.fromJSON(j)), 352 | } 353 | ); 354 | 355 | /** Text length */ 356 | const length: Ref = ref(0); 357 | 358 | /** 359 | * Returns the number of active lint diagnostics in the given state. 360 | * 361 | * @see {@link https://codemirror.net/docs/ref/#lint.diagnosticCount} 362 | */ 363 | const diagnosticCount: Ref = ref(0); 364 | 365 | /** Get CodeMirror Extension */ 366 | const extensions: ComputedRef = computed(() => { 367 | // Synamic Reconfiguration 368 | // @see https://codemirror.net/examples/config/ 369 | const language = new Compartment(); 370 | const tabSize = new Compartment(); 371 | if (props.basic && props.minimal) { 372 | throw new Error( 373 | '[Vue CodeMirror] Both basic and minimal cannot be specified.' 374 | ); 375 | } 376 | // TODO: Ignore previous prop was not changed. 377 | return [ 378 | // Toggle basic setup 379 | props.basic && !props.minimal ? basicSetup : undefined, 380 | // Toggle minimal setup 381 | props.minimal && !props.basic ? minimalSetup : undefined, 382 | // ViewUpdate event listener 383 | EditorView.updateListener.of((update: ViewUpdate): void => { 384 | // Emit focus status 385 | context.emit('focus', view.value.hasFocus); 386 | 387 | // Update count 388 | length.value = view.value.state.doc?.length; 389 | 390 | if (update.changes.empty || !update.docChanged) { 391 | // Suppress event firing if no change 392 | return; 393 | } 394 | if (props.linter) { 395 | // Linter process 396 | if (props.forceLinting) { 397 | // If forceLinting enabled, first liting. 398 | forceLinting(view.value); 399 | } 400 | // Count diagnostics. 401 | diagnosticCount.value = ( 402 | props.linter(view.value) as readonly Diagnostic[] 403 | ).length; 404 | } 405 | context.emit('update', update); 406 | }), 407 | // Toggle light/dark mode. 408 | EditorView.theme(props.theme, { dark: props.dark }), 409 | // Toggle line wrapping 410 | props.wrap ? EditorView.lineWrapping : undefined, 411 | // Indent with tab 412 | props.tab ? keymap.of([indentWithTab]) : undefined, 413 | // Tab character 414 | props.indentUnit ? indentUnit.of(props.indentUnit) : undefined, 415 | // Allow Multiple Selections 416 | EditorState.allowMultipleSelections.of(props.allowMultipleSelections), 417 | // Indent tab size 418 | props.tabSize 419 | ? tabSize.of(EditorState.tabSize.of(props.tabSize)) 420 | : undefined, 421 | // locale settings 422 | props.phrases ? EditorState.phrases.of(props.phrases) : undefined, 423 | // Readonly option 424 | EditorState.readOnly.of(props.readonly), 425 | // Editable option 426 | EditorView.editable.of(!props.disabled), 427 | // Set Line break char 428 | props.lineSeparator 429 | ? EditorState.lineSeparator.of(props.lineSeparator) 430 | : undefined, 431 | // Lang 432 | props.lang ? language.of(props.lang) : undefined, 433 | // Append Linter settings 434 | props.linter ? linter(props.linter, props.linterConfig) : undefined, 435 | // Show 🔴 to error line when linter enabled. 436 | props.linter && props.gutter 437 | ? lintGutter(props.gutterConfig) 438 | : undefined, 439 | // Placeholder 440 | props.placeholder ? placeholder(props.placeholder) : undefined, 441 | // Append Extensions 442 | ...props.extensions, 443 | ].filter((extension): extension is Extension => !!extension); // Filter undefined 444 | }); 445 | 446 | // Extension (mostly props) Changed 447 | watch( 448 | extensions, 449 | exts => 450 | view.value?.dispatch({ effects: StateEffect.reconfigure.of(exts) }), 451 | { immediate: true } 452 | ); 453 | 454 | // for parent-to-child binding. 455 | watch( 456 | () => props.modelValue, 457 | async value => { 458 | if ( 459 | view.value.composing || // IME fix 460 | view.value.state.doc.toJSON().join(props.lineSeparator ?? '\n') === 461 | value // don't need to update 462 | ) { 463 | // Do not commit CodeMirror's store. 464 | return; 465 | } 466 | 467 | // Range Fix ? 468 | // https://github.com/logue/vue-codemirror6/issues/27 469 | const isSelectionOutOfRange = !view.value.state.selection.ranges.every( 470 | range => range.anchor < value.length && range.head < value.length 471 | ); 472 | 473 | // Update 474 | view.value.dispatch({ 475 | changes: { from: 0, to: view.value.state.doc.length, insert: value }, 476 | selection: isSelectionOutOfRange 477 | ? { anchor: 0, head: 0 } 478 | : view.value.state.selection, 479 | scrollIntoView: props.scrollIntoView, 480 | }); 481 | }, 482 | { immediate: true } 483 | ); 484 | 485 | /** When loaded */ 486 | onMounted(async () => { 487 | /** Initial value */ 488 | let value: string | Text = doc.value; 489 | if (!editor.value) { 490 | return; 491 | } 492 | if (editor.value.childNodes[0]) { 493 | // when slot mode, overwrite initial value 494 | if (doc.value !== '') { 495 | console.warn( 496 | '[CodeMirror.vue] The tag contains child elements that overwrite the `v-model` values.' 497 | ); 498 | } 499 | value = (editor.value.childNodes[0] as HTMLElement).innerText.trim(); 500 | } 501 | 502 | // Register Codemirror 503 | view.value = new EditorView({ 504 | parent: editor.value, 505 | state: EditorState.create({ doc: value, extensions: extensions.value }), 506 | dispatch: (tr: Transaction) => { 507 | view.value.update([tr]); 508 | if (tr.changes.empty || !tr.docChanged) { 509 | // if not change value, no fire emit event 510 | return; 511 | } 512 | 513 | // console.log(view.state.doc.toString(), tr); 514 | // state.toString() is not defined, so use toJSON and toText function to convert string. 515 | context.emit('update:modelValue', tr.state.doc.toString()); 516 | // Emit EditorState 517 | context.emit('change', tr.state); 518 | }, 519 | }); 520 | 521 | await nextTick(); 522 | 523 | context.emit('ready', { 524 | view: view.value, 525 | state: view.value.state, 526 | container: editor.value, 527 | }); 528 | }); 529 | 530 | /** Destroy */ 531 | onUnmounted(() => { 532 | view.value.destroy(); 533 | context.emit('destroy'); 534 | }); 535 | 536 | /** 537 | * Forces any linters configured to run when the editor is idle to run right away. 538 | * 539 | * @see {@link https://codemirror.net/docs/ref/#lint.forceLinting} 540 | */ 541 | const lint = (): void => { 542 | if (!props.linter || !view.value) { 543 | return; 544 | } 545 | if (props.forceLinting) { 546 | forceLinting(view.value); 547 | } 548 | diagnosticCount.value = linterDiagnosticCount(view.value.state); 549 | }; 550 | 551 | /** 552 | * Force Reconfigure Extension 553 | * 554 | * @see {@link https://codemirror.net/examples/config/#top-level-reconfiguration} 555 | */ 556 | const forceReconfigure = (): void => { 557 | // Deconfigure all Extensions 558 | view.value?.dispatch({ 559 | effects: StateEffect.reconfigure.of([]), 560 | }); 561 | // Register extensions 562 | view.value?.dispatch({ 563 | effects: StateEffect.appendConfig.of(extensions.value), 564 | }); 565 | }; 566 | 567 | /* ----- Bellow is experimental. ------ */ 568 | 569 | /** 570 | * Get the text between the given points in the editor. 571 | * 572 | * @param from - start line number 573 | * @param to - end line number 574 | */ 575 | const getRange = (from?: number, to?: number): string | undefined => 576 | view.value.state.sliceDoc(from, to); 577 | /** 578 | * Get the content of line. 579 | * 580 | * @param number - line number 581 | */ 582 | const getLine = (number: number): string => 583 | view.value.state.doc.line(number + 1).text; 584 | /** Get the number of lines in the editor. */ 585 | const lineCount = (): number => view.value.state.doc.lines; 586 | /** Retrieve one end of the primary selection. */ 587 | const getCursor = (): number => view.value.state.selection.main.head; 588 | /** Retrieves a list of all current selections. */ 589 | const listSelections = (): readonly SelectionRange[] => { 590 | let _view$value$state$sel; 591 | return (_view$value$state$sel = view.value.state.selection.ranges) !== 592 | null && _view$value$state$sel !== undefined 593 | ? _view$value$state$sel 594 | : []; 595 | }; 596 | /** Get the currently selected code. */ 597 | const getSelection = (): string => { 598 | let _view$value$state$sli; 599 | return (_view$value$state$sli = view.value.state.sliceDoc( 600 | view.value.state.selection.main.from, 601 | view.value.state.selection.main.to 602 | )) !== null && _view$value$state$sli !== undefined 603 | ? _view$value$state$sli 604 | : ''; 605 | }; 606 | /** 607 | * The length of the given array should be the same as the number of active selections. 608 | * Replaces the content of the selections with the strings in the array. 609 | */ 610 | const getSelections = (): string[] => { 611 | const s = view.value.state; 612 | if (!s) { 613 | return []; 614 | } 615 | 616 | return s.selection.ranges.map((r: { from: number; to: number }) => 617 | s.sliceDoc(r.from, r.to) 618 | ); 619 | }; 620 | /** Return true if any text is selected. */ 621 | const somethingSelected = (): boolean => 622 | view.value.state.selection.ranges.some( 623 | (r: { empty: boolean }) => !r.empty 624 | ); 625 | 626 | /** 627 | * Replace the part of the document between from and to with the given string. 628 | * 629 | * @param replacement - replacement text 630 | * @param from - start string at position 631 | * @param to - insert the string at position 632 | */ 633 | const replaceRange = ( 634 | replacement: string | Text, 635 | from: number, 636 | to: number 637 | ): void => 638 | view.value.dispatch({ 639 | changes: { from, to, insert: replacement }, 640 | }); 641 | /** 642 | * Replace the selection(s) with the given string. 643 | * By default, the new selection ends up after the inserted text. 644 | * 645 | * @param replacement - replacement text 646 | */ 647 | const replaceSelection = (replacement: string | Text): void => 648 | view.value.dispatch(view.value.state.replaceSelection(replacement)); 649 | /** 650 | * Set the cursor position. 651 | * 652 | * @param position - position. 653 | */ 654 | const setCursor = (position: number): void => 655 | view.value.dispatch({ selection: { anchor: position } }); 656 | /** 657 | * Set a single selection range. 658 | * 659 | * @param anchor - anchor position 660 | * @param head - 661 | */ 662 | const setSelection = (anchor: number, head?: number): void => 663 | view.value.dispatch({ selection: { anchor, head } }); 664 | /** 665 | * Sets a new set of selections. There must be at least one selection in the given array. 666 | * 667 | * @param ranges - Selection range 668 | * @param primary - 669 | */ 670 | const setSelections = ( 671 | ranges: readonly SelectionRange[], 672 | primary?: number 673 | ): void => 674 | view.value.dispatch({ 675 | selection: EditorSelection.create(ranges, primary), 676 | }); 677 | /** 678 | * Applies the given function to all existing selections, and calls extendSelections on the result. 679 | * 680 | * @param f - function 681 | */ 682 | const extendSelectionsBy = (f: any): void => 683 | view.value.dispatch({ 684 | selection: EditorSelection.create( 685 | selection.value.ranges.map((r: SelectionRange) => r.extend(f(r))) 686 | ), 687 | }); 688 | 689 | const exposed = { 690 | editor, 691 | view, 692 | cursor, 693 | selection, 694 | focus, 695 | length, 696 | json, 697 | diagnosticCount, 698 | dom: view.value.contentDOM, 699 | lint, 700 | forceReconfigure, 701 | // Bellow is CodeMirror5's function 702 | getRange, 703 | getLine, 704 | lineCount, 705 | getCursor, 706 | listSelections, 707 | getSelection, 708 | getSelections, 709 | somethingSelected, 710 | replaceRange, 711 | replaceSelection, 712 | setCursor, 713 | setSelection, 714 | setSelections, 715 | extendSelectionsBy, 716 | }; 717 | 718 | /** Export properties and functions */ 719 | context.expose(exposed); 720 | return exposed; 721 | }, 722 | render() { 723 | // 724 | // 725 | // 726 | //727 | // 728 | return h( 729 | this.$props.tag, 730 | { 731 | ref: 'editor', 732 | class: 'vue-codemirror', 733 | }, 734 | this.$slots.default 735 | ? // Hide original content 736 | h( 737 | 'aside', 738 | { style: 'display: none;', 'aria-hidden': 'true' }, 739 | slot(this.$slots.default) 740 | ) 741 | : undefined 742 | ); 743 | }, 744 | }); 745 | -------------------------------------------------------------------------------- /src/helpers/h-demi.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * h-demi - h function for Vue 2 and 3 3 | * 4 | * @see {@link https://github.com/vueuse/vue-demi/issues/65} 5 | */ 6 | 7 | import { 8 | h as hDemi, 9 | isVue2, 10 | type Slots, 11 | type VNode, 12 | type VNodeProps, 13 | } from 'vue-demi'; 14 | 15 | interface Options extends VNodeProps { 16 | class?: string; 17 | domProps?: VNodeProps; 18 | on?: Recordvoid>; 19 | props?: VNodeProps; 20 | style?: string; 21 | 'aria-hidden'?: string; 22 | } 23 | 24 | const adaptOnsV3 = ( 25 | ons: Record void> 26 | ): Record void> => { 27 | if (!ons) return {}; 28 | return Object.entries(ons).reduce((ret, [key, handler]) => { 29 | key = key.charAt(0).toUpperCase() + key.slice(1); 30 | key = `on${key}`; 31 | return { ...ret, [key]: handler }; 32 | }, {}); 33 | }; 34 | 35 | /** 36 | * hDemi function. 37 | */ 38 | export default function h( 39 | type: string | Record , 40 | options: Options = {}, 41 | chidren?: any 42 | ): VNode { 43 | if (isVue2) { 44 | // Makeshift support :( 45 | // Since Vue2.7 includes the Composition API, the functions in vue-demi are not used. 46 | return hDemi(type, options, chidren); 47 | } 48 | const { props, domProps, on, ...extraOptions } = options; 49 | const ons = on ? adaptOnsV3(on) : {}; 50 | 51 | return hDemi( 52 | type, 53 | { ...extraOptions, ...props, ...domProps, ...ons }, 54 | chidren 55 | ); 56 | } 57 | 58 | export const slot = (defaultSlots: any): Slots => 59 | typeof defaultSlots === 'function' ? defaultSlots() : defaultSlots; 60 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import Meta from '@/Meta'; 2 | import CodeMirror from '@/components/CodeMirror'; 3 | 4 | // TODO: Move phrases props to option. 5 | const installCodeMirror = (app: any): void => 6 | app.component('CodeMirror', CodeMirror); 7 | 8 | export { CodeMirror as default, installCodeMirror as install, Meta }; 9 | -------------------------------------------------------------------------------- /src/interfaces/MetaInterface.ts: -------------------------------------------------------------------------------- 1 | /** Build information meta data */ 2 | export default interface MetaInterface { 3 | /** Version */ 4 | version: string; 5 | /** Build date */ 6 | date: string; 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.dom.json", 3 | "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], 4 | "exclude": ["src/**/__tests__/*"], 5 | "compilerOptions": { 6 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 7 | 8 | "paths": { 9 | "@/*": ["./src/*"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tsconfig.docs.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig.json", 3 | "extends": "./tsconfig.app.json", 4 | "include": [ 5 | "./env.d.ts", 6 | "./src/**/*", 7 | "./src/**/*.vue", 8 | "./src-docs/**/*", 9 | "./src-docs/**/*.vue" 10 | ], 11 | "compilerOptions": { 12 | "composite": true, 13 | "declarationMap": true, 14 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 15 | "baseUrl": ".", 16 | "paths": { 17 | "@/*": ["./src/*"], 18 | "vue-codemirror6": ["./src/index.ts"] 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig.json", 3 | "files": [], 4 | "references": [ 5 | { "path": "./tsconfig.app.json" }, 6 | { "path": "./tsconfig.docs.json" }, 7 | { "path": "./tsconfig.node.json" } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/node-lts/tsconfig.json", 3 | "include": [ 4 | "vite.config.*", 5 | "vitest.config.*", 6 | "cypress.config.*", 7 | "nightwatch.conf.*", 8 | "playwright.config.*", 9 | "eslint.config.*" 10 | ], 11 | "compilerOptions": { 12 | "noEmit": true, 13 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 14 | 15 | "module": "ESNext", 16 | "moduleResolution": "Bundler", 17 | "types": ["node"] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { writeFileSync } from 'node:fs'; 2 | import { fileURLToPath, URL } from 'node:url'; 3 | 4 | import Vue from '@vitejs/plugin-vue'; 5 | import { defineConfig, type UserConfig } from 'vite'; 6 | 7 | import { visualizer } from 'rollup-plugin-visualizer'; 8 | import banner from 'vite-plugin-banner'; 9 | import { checker } from 'vite-plugin-checker'; 10 | import dts from 'vite-plugin-dts'; 11 | 12 | import pkg from './package.json'; 13 | 14 | // https://vitejs.dev/config/ 15 | export default defineConfig(({ mode, command }): UserConfig => { 16 | const config: UserConfig = { 17 | base: './', 18 | publicDir: command === 'serve' ? 'public' : false, 19 | // Resolver 20 | resolve: { 21 | // https://vitejs.dev/config/shared-options.html#resolve-alias 22 | alias: { 23 | '@': fileURLToPath(new URL('./src', import.meta.url)), 24 | '~': fileURLToPath(new URL('./node_modules', import.meta.url)), 25 | 'vue-codemirror6': fileURLToPath(new URL('./src', import.meta.url)), 26 | }, 27 | }, 28 | plugins: [ 29 | Vue(), 30 | // vite-plugin-checker 31 | // https://github.com/fi3ework/vite-plugin-checker 32 | checker({ 33 | typescript: true, 34 | // vueTsc: true, 35 | // eslint: { lintCommand: 'eslint' }, 36 | }), 37 | // vite-plugin-banner 38 | // https://github.com/chengpeiquan/vite-plugin-banner 39 | banner(`/** 40 | * ${pkg.name} 41 | * 42 | * @description ${pkg.description} 43 | * @author ${pkg.author.name} <${pkg.author.email}> 44 | * @copyright 2022-2025 By Masashi Yoshikawa All rights reserved. 45 | * @license ${pkg.license} 46 | * @version ${pkg.version} 47 | * @see {@link ${pkg.homepage}} 48 | */ 49 | `), 50 | // vite-plugin-dts 51 | // https://github.com/qmhc/vite-plugin-dts 52 | mode === 'docs' 53 | ? undefined 54 | : dts({ tsconfigPath: './tsconfig.app.json' }), 55 | ], 56 | optimizeDeps: { 57 | exclude: [ 58 | 'vue-demi', 59 | // https://github.com/codemirror/dev/issues/608 60 | '@codemirror/state', 61 | ], 62 | }, 63 | // Build Options 64 | // https://vitejs.dev/config/#build-options 65 | build: { 66 | outDir: mode === 'docs' ? 'docs' : undefined, 67 | lib: 68 | mode === 'docs' 69 | ? undefined 70 | : { 71 | entry: fileURLToPath(new URL('./src/index.ts', import.meta.url)), 72 | name: 'CodeMirror', 73 | formats: ['umd', 'es', 'iife'], 74 | fileName: format => `index.${format}.js`, 75 | }, 76 | 77 | rollupOptions: { 78 | plugins: [ 79 | mode === 'analyze' 80 | ? // rollup-plugin-visualizer 81 | // https://github.com/btd/rollup-plugin-visualizer 82 | visualizer({ 83 | open: true, 84 | filename: 'stats.html', 85 | gzipSize: false, 86 | brotliSize: false, 87 | }) 88 | : undefined, 89 | ], 90 | external: 91 | mode === 'docs' 92 | ? undefined 93 | : [ 94 | 'vue', 95 | 'vue-demi', 96 | 'codemirror', 97 | '@codemirror/autocomplete', 98 | '@codemirror/commands', 99 | '@codemirror/language', 100 | '@codemirror/lint', 101 | '@codemirror/search', 102 | '@codemirror/state', 103 | '@codemirror/view', 104 | ], 105 | output: { 106 | esModule: true, 107 | generatedCode: { 108 | reservedNamesAsProps: false, 109 | }, 110 | interop: 'compat', 111 | systemNullSetters: false, 112 | exports: 'named', 113 | globals: { 114 | codemirror: 'codemirror', 115 | '@codemirror/commands': 'commands', 116 | '@codemirror/language': 'language', 117 | '@codemirror/lint': 'lint', 118 | '@codemirror/state': 'state', 119 | '@codemirror/view': 'view', 120 | 'vue-demi': 'VueDemi', 121 | vue: 'Vue', 122 | }, 123 | manualChunks: 124 | mode !== 'docs' 125 | ? undefined 126 | : { 127 | vue: ['vue'], 128 | eslint: ['eslint-linter-browserify'], 129 | codemirror: [ 130 | 'codemirror', 131 | '@codemirror/autocomplete', 132 | '@codemirror/commands', 133 | '@codemirror/language', 134 | '@codemirror/lint', 135 | '@codemirror/search', 136 | '@codemirror/state', 137 | '@codemirror/view', 138 | ], 139 | // Add the following as needed. 140 | 'codemirror-lang': [ 141 | '@codemirror/lang-markdown', 142 | '@codemirror/lang-javascript', 143 | '@codemirror/lang-json', 144 | '@codemirror/lang-vue', 145 | ], 146 | }, 147 | }, 148 | }, 149 | // Minify option 150 | target: 'esnext', 151 | // minify: mode === 'docs', 152 | }, 153 | }; 154 | 155 | // Write meta data. 156 | writeFileSync( 157 | fileURLToPath(new URL('./src/Meta.ts', import.meta.url)), 158 | `import type MetaInterface from '@/interfaces/MetaInterface'; 159 | 160 | // This file is auto-generated by the build system. 161 | const meta: MetaInterface = { 162 | version: '${pkg.version}', 163 | date: '${new Date().toISOString()}', 164 | }; 165 | export default meta; 166 | ` 167 | ); 168 | 169 | // Export vite config 170 | return config; 171 | }); 172 | --------------------------------------------------------------------------------