Repository: CarterLi/vue3-ace-editor
Branch: master
Commit: 68e4aef2e31b
Files: 9
Total size: 18.2 KB
Directory structure:
gitextract_hmq5fgcx/
├── .gitignore
├── LICENSE
├── README.md
├── index.d.ts
├── index.js
├── index.ts
├── package.json
├── tsconfig.json
└── types.d.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
/node_modules
/*.log
/demo-source
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2020 Carter Li
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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.
================================================
FILE: README.md
================================================
vue3-ace-editor
====================
[](https://www.npmjs.com/package/vue3-ace-editor)
A packaging of [ace](https://ace.c9.io/). Inspired by [vue2-ace-editor](https://github.com/chairuosen/vue2-ace-editor), but supports [Vue 3](https://github.com/vuejs/vue-next)
## Install
`ace-builds` must be installed alongside `vue3-ace-editor` using your favorite package manager.
* npm i vue3-ace-editor ace-builds
* yarn add vue3-ace-editor ace-builds
* pnpm i vue3-ace-editor ace-builds
## Usage
```vue
```
Property `v-model:value` is required. `` has no height by default. Its height must be specified manually, or set both `min-lines` and `max-lines` to make the editor's height auto-grow.
Property `lang`, `theme` is same as [ace-editor's doc](https://github.com/ajaxorg/ace)
## Load modes and themes (**REQUIRED**)
Using of `ace-builds/webpack-resolver` is removed due to bug https://github.com/CarterLi/vue3-ace-editor/issues/3. You **MUST** import `theme` and `mode` yourself. eg.
```js
// You MUST make sure that `ace-builds` or `vue3-ace-editor` (which imports `ace-builds` internally) is loaded before importing `mode` and `theme`
import 'ace-builds/src-noconflict/mode-json';
import 'ace-builds/src-noconflict/theme-chrome';
```
To use dynamic loading to avoid first-load overhead
```js
import ace from 'ace-builds';
import modeJsonUrl from 'ace-builds/src-noconflict/mode-json?url';
ace.config.setModuleUrl('ace/mode/json', modeJsonUrl);
import themeChromeUrl from 'ace-builds/src-noconflict/theme-chrome?url';
ace.config.setModuleUrl('ace/theme/chrome', themeChromeUrl);
```
Note that to make search box (`Ctrl+F` or `Command+F`) work, `ext-searchbox` must also be loaded.
```js
import extSearchboxUrl from 'ace-builds/src-noconflict/ext-searchbox?url';
ace.config.setModuleUrl('ace/ext/searchbox', extSearchboxUrl);
```
Find all supported themes and modes in `node_modules/ace-builds/src-noconflict`
## Deferences with [vue2-ace-editor](https://github.com/chairuosen/vue2-ace-editor)
1. This component uses [ace-builds](https://www.npmjs.com/package/ace-builds) directly, instead of the outdated wrapper [brace](https://www.npmjs.com/package/brace)
1. DOM size changes are detected automatically using [ResizeObserver](resize-observer-polyfill), thus no `width` / `height` props needed.
1. For easier usage, more props / events added / emitted.
1. Prop `readonly`: This Boolean attribute indicates that the user cannot modify the value of the control.
1. Prop `placeholder`: A hint to the user of what can be entered in the control.
1. Prop `wrap`: Indicates whether the control wraps text.
1. Prop `printMargin`: A short hand of `showPrintMargin` and `printMarginColumn`.
1. Prop `minLines` and `maxLines`: Specifiy the minimum and maximum number of lines.
1. All ace events emitted. Docs can be found here:
1. Some commonly used methods `focus`, `blur`, `selectAll` provided as shortcuts.
## Get raw ace instance
Use `getAceInstance`
```vue
```
`@init` is provided for `vue2-ace-editor` compatibility only but is not recommanded to use.
## Enable syntax checking
To enable syntax checking, module `ace/mode/lang_worker` must be registered, and option `useWorker: true` must be set.
Take JSON for example:
```ts
import workerJsonUrl from 'ace-builds/src-noconflict/worker-json?url'; // For vite
import workerJsonUrl from 'file-loader?esModule=false!ace-builds/src-noconflict/worker-json.js'; // For webpack / vue-cli
ace.config.setModuleUrl('ace/mode/json_worker', workerJsonUrl);
```
```html
```
See also https://github.com/CarterLi/vue3-ace-editor/issues/3#issuecomment-768190528 to load the worker file from CDN
## Minimal example using vite
* Preview:
* Source:
## Use it with Nuxt
Since ace doesn't support SSR, using it with Nuxt can be tricky. You must make sure that `ace` related things are loaded only at client side.
```vue
```
Full example:
## LICENSE
MIT
================================================
FILE: index.d.ts
================================================
import { type Ace } from 'ace-builds';
import type { VAceEditorInstance } from './types';
export declare const VAceEditor: import("vue").DefineComponent<{
value: {
type: StringConstructor;
required: true;
};
lang: {
type: StringConstructor;
default: string;
};
theme: {
type: StringConstructor;
default: string;
};
options: ObjectConstructor;
placeholder: StringConstructor;
readonly: BooleanConstructor;
wrap: BooleanConstructor;
printMargin: {
type: (BooleanConstructor | NumberConstructor)[];
default: boolean;
};
minLines: NumberConstructor;
maxLines: NumberConstructor;
}, unknown, unknown, {}, {
focus(this: VAceEditorInstance): void;
blur(this: VAceEditorInstance): void;
selectAll(this: VAceEditorInstance): void;
getAceInstance(this: VAceEditorInstance): Ace.Editor;
}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, string[], string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly> & {
[x: `on${Capitalize}`]: ((...args: any[]) => any) | undefined;
}, {
lang: string;
theme: string;
readonly: boolean;
wrap: boolean;
printMargin: number | boolean;
}, {}>;
================================================
FILE: index.js
================================================
import ace from 'ace-builds';
import { capitalize, defineComponent, markRaw, h } from 'vue';
import ResizeObserver from 'resize-observer-polyfill';
const Events = [
'blur',
'input',
'change',
'changeSelection',
'changeSelectionStyle',
'changeSession',
'copy',
'focus',
'paste',
];
export const VAceEditor = defineComponent({
name: 'VAceEditor',
props: {
value: {
type: String,
required: true,
},
lang: {
type: String,
default: 'text',
},
theme: {
type: String,
default: 'chrome',
},
options: Object,
placeholder: String,
readonly: Boolean,
wrap: Boolean,
printMargin: {
type: [Boolean, Number],
default: true,
},
minLines: Number,
maxLines: Number,
},
emits: ['update:value', 'init', ...Events],
render() {
return h('div');
},
mounted() {
const editor = this._editor = markRaw(ace.edit(this.$el, {
placeholder: this.placeholder,
readOnly: this.readonly,
value: this.value,
mode: 'ace/mode/' + this.lang,
theme: 'ace/theme/' + this.theme,
wrap: this.wrap,
printMargin: this.printMargin,
useWorker: false,
minLines: this.minLines,
maxLines: this.maxLines,
...this.options,
}));
this._contentBackup = this.value;
this._isSettingContent = false;
editor.on('change', () => {
// ref: https://github.com/CarterLi/vue3-ace-editor/issues/11
if (this._isSettingContent)
return;
const content = editor.getValue();
this._contentBackup = content;
this.$emit('update:value', content);
});
Events.forEach(x => {
const eventName = 'on' + capitalize(x);
if (typeof this.$.vnode.props[eventName] === 'function') {
editor.on(x, this.$emit.bind(this, x));
}
});
this._ro = new ResizeObserver(() => editor.resize());
this._ro.observe(this.$el);
this.$emit('init', editor);
},
beforeUnmount() {
var _a, _b;
(_a = this._ro) === null || _a === void 0 ? void 0 : _a.disconnect();
(_b = this._editor) === null || _b === void 0 ? void 0 : _b.destroy();
},
methods: {
focus() {
this._editor.focus();
},
blur() {
this._editor.blur();
},
selectAll() {
this._editor.selectAll();
},
getAceInstance() {
return this._editor;
},
},
watch: {
value(val) {
if (this._contentBackup !== val) {
try {
this._isSettingContent = true;
this._editor.setValue(val, 1);
}
finally {
this._isSettingContent = false;
}
this._contentBackup = val;
}
},
theme(val) {
this._editor.setTheme('ace/theme/' + val);
},
options(val) {
this._editor.setOptions(val);
},
readonly(val) {
this._editor.setReadOnly(val);
},
placeholder(val) {
this._editor.setOption('placeholder', val);
},
wrap(val) {
this._editor.setWrapBehavioursEnabled(val);
},
printMargin(val) {
this._editor.setOption('printMargin', val);
},
lang(val) {
this._editor.setOption('mode', 'ace/mode/' + val);
},
minLines(val) {
this._editor.setOption('minLines', val);
},
maxLines(val) {
this._editor.setOption('maxLines', val);
},
}
});
//# sourceMappingURL=index.js.map
================================================
FILE: index.ts
================================================
import ace, { type Ace } from 'ace-builds';
import { capitalize, defineComponent, markRaw, h } from 'vue';
import ResizeObserver from 'resize-observer-polyfill';
import type { VAceEditorInstance } from './types';
const Events = [
'blur',
'input',
'change',
'changeSelection',
'changeSelectionStyle',
'changeSession',
'copy',
'focus',
'paste',
];
export const VAceEditor = defineComponent({
name: 'VAceEditor',
props: {
value: {
type: String,
required: true,
},
lang: {
type: String,
default: 'text',
},
theme: {
type: String,
default: 'chrome',
},
options: Object,
placeholder: String,
readonly: Boolean,
wrap: Boolean,
printMargin: {
type: [Boolean, Number],
default: true,
},
minLines: Number,
maxLines: Number,
},
emits: ['update:value', 'init', ...Events],
render(this: VAceEditorInstance) {
return h('div');
},
mounted(this: VAceEditorInstance) {
const editor = this._editor = markRaw(ace.edit(this.$el, {
placeholder: this.placeholder,
readOnly: this.readonly,
value: this.value,
mode: 'ace/mode/' + this.lang,
theme: 'ace/theme/' + this.theme,
wrap: this.wrap,
printMargin: this.printMargin,
useWorker: false,
minLines: this.minLines,
maxLines: this.maxLines,
...this.options,
}));
this._contentBackup = this.value;
this._isSettingContent = false;
editor.on('change', () => {
// ref: https://github.com/CarterLi/vue3-ace-editor/issues/11
if (this._isSettingContent) return;
const content = editor.getValue();
this._contentBackup = content;
this.$emit('update:value', content);
});
Events.forEach(x => {
const eventName = 'on' + capitalize(x);
if (typeof this.$.vnode.props![eventName] === 'function') {
editor.on(x as any, this.$emit.bind(this, x));
}
});
this._ro = new ResizeObserver(() => editor.resize());
this._ro.observe(this.$el);
this.$emit('init', editor);
},
beforeUnmount(this: VAceEditorInstance) {
this._ro?.disconnect();
this._editor?.destroy();
},
methods: {
focus(this: VAceEditorInstance) {
this._editor.focus();
},
blur(this: VAceEditorInstance) {
this._editor.blur();
},
selectAll(this: VAceEditorInstance) {
this._editor.selectAll();
},
getAceInstance(this: VAceEditorInstance) {
return this._editor;
},
},
watch: {
value(this: VAceEditorInstance, val: string) {
if (this._contentBackup !== val) {
try {
this._isSettingContent = true;
this._editor.setValue(val, 1);
} finally {
this._isSettingContent = false;
}
this._contentBackup = val;
}
},
theme(this: VAceEditorInstance, val: string) {
this._editor.setTheme('ace/theme/' + val);
},
options(this: VAceEditorInstance, val: Partial) {
this._editor.setOptions(val);
},
readonly(this: VAceEditorInstance, val: boolean) {
this._editor.setReadOnly(val);
},
placeholder(this: VAceEditorInstance, val: string) {
this._editor.setOption('placeholder', val);
},
wrap(this: VAceEditorInstance, val: boolean) {
this._editor.setWrapBehavioursEnabled(val);
},
printMargin(this: VAceEditorInstance, val: boolean | number) {
this._editor.setOption('printMargin', val);
},
lang(this: VAceEditorInstance, val: string) {
this._editor.setOption('mode', 'ace/mode/' + val);
},
minLines(this: VAceEditorInstance, val: number) {
this._editor.setOption('minLines', val);
},
maxLines(this: VAceEditorInstance, val: number) {
this._editor.setOption('maxLines', val);
},
}
});
================================================
FILE: package.json
================================================
{
"name": "vue3-ace-editor",
"version": "2.2.4",
"description": "Like vue2-ace-editor but more functional and supports Vue 3",
"main": "index.js",
"module": "index.js",
"type": "module",
"types": "index.d.ts",
"repository": "git@github.com:CarterLi/vue3-ace-editor.git",
"author": "李通洲 ",
"license": "MIT",
"scripts": {
"build": "tsc -p ."
},
"dependencies": {
"resize-observer-polyfill": "^1.5.1"
},
"peerDependencies": {
"ace-builds": "*",
"vue": "^3"
},
"devDependencies": {
"typescript": "^5.2.2"
}
}
================================================
FILE: tsconfig.json
================================================
{
"compilerOptions": {
"target": "es2019",
"module": "esnext",
"strict": true,
"importHelpers": true,
"moduleResolution": "node",
"esModuleInterop": true,
"skipLibCheck": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"sourceMap": true,
"declaration": true,
"baseUrl": "./",
"lib": [
"esnext",
"dom",
"dom.iterable"
]
},
"exclude": [
"node_modules"
]
}
================================================
FILE: types.d.ts
================================================
import { ComponentPublicInstance } from 'vue';
import type { Ace } from 'ace-builds';
export interface VAceEditorPrivate {
_editor: Ace.Editor;
_contentBackup: string;
_isSettingContent: boolean;
_ro: ResizeObserver;
}
export interface VAceEditorProps {
readonly value: string;
readonly lang: string;
readonly theme: string;
readonly options: Partial;
readonly placeholder: string;
readonly readonly: boolean;
readonly wrap: boolean;
readonly printMargin: boolean | number;
readonly minLines: number;
readonly maxLines: number;
}
export interface VAceEditorMethods {
focus(): void;
blur(): void;
selectAll(): void;
getAceInstance(): Ace.Editor;
}
export interface VAceEditorInstance extends
ComponentPublicInstance,
VAceEditorPrivate,
VAceEditorProps,
VAceEditorMethods {}