├── docs
├── .nojekyll
├── remote.js
├── _coverpage.md
├── index.html
└── README.md
├── .babelrc
├── .gitignore
├── src
├── utils
│ ├── assign.js
│ ├── compiler.js
│ ├── require.js
│ ├── parser.js
│ └── transform.js
├── index.umd.js
├── index.js
├── index.cjs.js
├── components
│ ├── editor.js
│ ├── playground.js
│ └── preview.js
└── style
│ └── vuep.css
├── remote.js
├── .travis.yml
├── .eslintrc
├── __test__
├── mock.js
├── editor.spec.js
├── require.spec.js
├── playground.spec.js
├── preview.spec.js
├── parser.spec.js
└── compiler.spec.js
├── LICENSE
├── package.json
├── README.md
├── test.html
└── dist
├── vuep.min.css
├── vuep.common.js
└── vuep.css
/docs/.nojekyll:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-3"]
3 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | coverage
2 | node_modules
3 | .idea
4 | *log*
5 | .DS_Store
6 |
--------------------------------------------------------------------------------
/src/utils/assign.js:
--------------------------------------------------------------------------------
1 | import assign from 'simple-assign'
2 |
3 | export default Object.assign || assign
4 |
--------------------------------------------------------------------------------
/remote.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'remote',
3 | render () {
4 | return
from remote
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/docs/remote.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'remote',
3 | render () {
4 | return from remote
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | node_js: stable
4 | after_success:
5 | - yarn coveralls
6 | - yarn test:ci
7 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "vue",
3 | "globals": {
4 | "test": true,
5 | "expect": true
6 | },
7 | "env": {
8 | "mocha": true
9 | }
10 | }
--------------------------------------------------------------------------------
/src/index.umd.js:
--------------------------------------------------------------------------------
1 | export * from './'
2 | import 'codemirror/addon/mode/overlay'
3 | import 'codemirror/addon/mode/simple'
4 | import 'codemirror/mode/css/css'
5 | import 'codemirror/mode/htmlmixed/htmlmixed'
6 | import 'codemirror/mode/javascript/javascript'
7 | import 'codemirror/mode/vue/vue'
8 | import 'codemirror/mode/xml/xml'
9 | import 'codemirror/mode/jsx/jsx'
10 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import Vuep from './components/playground'
2 |
3 | Vuep.config = function (opts) {
4 | Vuep.props.options.default = () => opts
5 | }
6 |
7 | function install (Vue, opts) {
8 | Vuep.config(opts)
9 | Vue.component(Vuep.name, Vuep)
10 | }
11 |
12 | Vuep.install = install
13 |
14 | if (typeof Vue !== 'undefined') {
15 | Vue.use(install) // eslint-disable-line
16 | }
17 |
18 | export default Vuep
19 |
--------------------------------------------------------------------------------
/__test__/mock.js:
--------------------------------------------------------------------------------
1 | export default function () {
2 | // mock createTextRange function
3 | // https://discuss.codemirror.net/t/working-in-jsdom-or-node-js-natively/138/2
4 | document.body.createTextRange = function () {
5 | return {
6 | setEnd: () => {},
7 | setStart: () => {},
8 | getBoundingClientRect: () => ({ right: 0 }),
9 | getClientRects: () => ({ right: 0 })
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/index.cjs.js:
--------------------------------------------------------------------------------
1 | import Vuep from './'
2 |
3 | if (typeof require !== 'undefined') {
4 | require('codemirror/addon/mode/overlay')
5 | require('codemirror/addon/mode/simple')
6 | require('codemirror/mode/css/css')
7 | require('codemirror/mode/htmlmixed/htmlmixed')
8 | require('codemirror/mode/javascript/javascript')
9 | require('codemirror/mode/vue/vue')
10 | require('codemirror/mode/xml/xml')
11 | require('codemirror/mode/jsx/jsx')
12 | }
13 |
14 | export default Vuep
15 |
--------------------------------------------------------------------------------
/src/utils/compiler.js:
--------------------------------------------------------------------------------
1 | import evalJS from './transform'
2 |
3 | export default function ({ template, script = 'module.exports={}', styles }, scope = {}) {
4 | try {
5 | if (script === 'module.exports={}' && !template) throw Error('no data')
6 | const result = evalJS(script, scope)
7 | if (template) {
8 | result.template = template
9 | }
10 | return {
11 | result: result,
12 | styles: styles && styles.join(' ')
13 | }
14 | } catch (error) {
15 | return { error }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/docs/_coverpage.md:
--------------------------------------------------------------------------------
1 |
2 | # Vuep 0.7
3 |
4 | [](https://travis-ci.org/QingWei-Li/vuep)
5 | [](https://coveralls.io/github/QingWei-Li/vuep?branch=master)
6 | [](https://www.npmjs.com/package/vuep)
7 |
8 |
9 | > A component for rendering Vue components with live editor and preview.
10 |
11 |
12 | [GitHub](https://github.com/QingWei-Li/vuep/)
13 | [Get Started](#demo)
14 |
--------------------------------------------------------------------------------
/__test__/editor.spec.js:
--------------------------------------------------------------------------------
1 | import mock from './mock'
2 | import Vue from 'vue'
3 | import Editor from '../src/components/editor'
4 |
5 | const Ctor = Vue.extend(Editor)
6 |
7 | describe('editor', () => {
8 | mock()
9 |
10 | it('init editor', () => {
11 | const vm = new Ctor().$mount()
12 | expect(vm.$el.querySelector('.CodeMirror')).toBeDefined()
13 | })
14 |
15 | it('options', () => {
16 | const vm = new Ctor({
17 | propsData: {
18 | options: {
19 | theme: 'neo'
20 | }
21 | }
22 | }).$mount()
23 |
24 | expect(vm.currentOptions).toEqual({
25 | lineNumbers: true,
26 | mode: 'text/x-vue',
27 | theme: 'neo',
28 | tabSize: 2
29 | })
30 | })
31 | })
32 |
--------------------------------------------------------------------------------
/src/utils/require.js:
--------------------------------------------------------------------------------
1 | import evalJS from './transform.js'
2 |
3 | const JSMODULE_REG = /\.((js)|(jsx))$/
4 |
5 | export default function require (url) {
6 | if (JSMODULE_REG.test(url)) {
7 | return getAndCache(url)
8 | }
9 | }
10 |
11 | // modify from docsify: https://github.com/QingWei-Li/docsify/blob/master/src/core/fetch/ajax.js
12 |
13 | const cache = {}
14 |
15 | /**
16 | * Simple ajax get
17 | * @param {string} url
18 | * @return { then(resolve, reject), abort }
19 | */
20 | function getAndCache (url) {
21 | const xhr = new XMLHttpRequest() // eslint-disable-line
22 |
23 | if (cache[url]) {
24 | return cache[url]
25 | }
26 |
27 | xhr.open('GET', url, false)
28 | xhr.send()
29 | const script = xhr.responseText
30 | cache[url] = evalJS(script)
31 | return cache[url]
32 | }
33 |
--------------------------------------------------------------------------------
/__test__/require.spec.js:
--------------------------------------------------------------------------------
1 | import require from '../src/utils/require.js'
2 |
3 | let count = 0
4 | beforeAll(() => {
5 | global.XMLHttpRequest = () => {
6 | return {
7 | open (url) {
8 | count++
9 | },
10 | send () {
11 | },
12 | responseText: 'module.exports="from remote"'
13 | }
14 | }
15 | })
16 |
17 | test('require works', () => {
18 | global.XMLHttpRequest = () => {
19 | return {
20 | open (url) {
21 | count++
22 | },
23 | send () {
24 | },
25 | responseText: 'module.exports="from remote"'
26 | }
27 | }
28 | expect(require('test.js')).toEqual('from remote')
29 | })
30 |
31 | test('require cache works', () => {
32 | require('test.js')
33 | require('test.js')
34 | require('test.js')
35 | require('test.js')
36 | expect(count).toEqual(1)
37 | })
38 |
--------------------------------------------------------------------------------
/src/utils/parser.js:
--------------------------------------------------------------------------------
1 | export default function (input) {
2 | const html = document.createElement('div')
3 | const content = html.innerHTML = input.trim()
4 |
5 | try {
6 | const template = html.querySelector('template')
7 | const script = html.querySelector('script')
8 | const styles = Array.prototype.slice.call(html.querySelectorAll('style')).map(n => n.innerHTML)
9 |
10 | if (!template && !script && !styles.length) {
11 | return {
12 | content,
13 | script: content
14 | }
15 | }
16 |
17 | return {
18 | content: /<\/script>$/g.test(content) ? content : (content + '\n'),
19 | template: template ? template.innerHTML : '',
20 | script: script ? script.innerHTML : '',
21 | styles: styles
22 | }
23 | } catch (error) {
24 | /* istanbul ignore next */
25 | return { error }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/components/editor.js:
--------------------------------------------------------------------------------
1 | import CodeMirror from 'codemirror'
2 | import assign from '../utils/assign'
3 |
4 | const DEFAULT_OPTIONS = {
5 | lineNumbers: true,
6 | mode: 'text/x-vue',
7 | theme: 'material',
8 | tabSize: 2
9 | }
10 |
11 | export default {
12 | name: 'VueCodeMirror',
13 |
14 | props: ['value', 'options'],
15 |
16 | render (h) {
17 | return h('div', null, [
18 | h('textarea', { ref: 'textarea' }, this.value)
19 | ])
20 | },
21 |
22 | mounted () {
23 | this.currentOptions = assign({}, DEFAULT_OPTIONS, this.options)
24 | this.editor = CodeMirror.fromTextArea(this.$refs.textarea, this.currentOptions)
25 | this.editor.on('change', this.handleChange)
26 | },
27 |
28 | watch: {
29 | value (val) {
30 | val !== this.editor.getValue() && this.editor.setValue(val)
31 | }
32 | },
33 |
34 | methods: {
35 | handleChange () {
36 | /* istanbul ignore next */
37 | this.$emit('change', this.editor.getValue())
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016-2017 cinwell.li
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 |
--------------------------------------------------------------------------------
/__test__/playground.spec.js:
--------------------------------------------------------------------------------
1 | import mock from './mock'
2 | import Vue from 'vue'
3 | import Playground from '../src/components/playground'
4 |
5 | const Ctor = Vue.extend(Playground)
6 |
7 | describe('playground', () => {
8 | mock()
9 |
10 | it('element is not found', () => {
11 | expect(() => new Ctor({
12 | propsData: {
13 | template: '#app'
14 | }
15 | })).toThrowError('#app is not found')
16 | })
17 |
18 | it('work', () => {
19 | const vm = new Ctor({
20 | propsData: {
21 | template: `module.exports = { template: '123
' }`
22 | }
23 | }).$mount()
24 |
25 | vm.$nextTick(_ => {
26 | expect(vm.preview).toEqual({
27 | template: '123
'
28 | })
29 | expect(vm.content).toEqual(`module.exports = { template: '123
' }`)
30 | })
31 | })
32 |
33 | it('styles', () => {
34 | const vm = new Ctor({
35 | propsData: {
36 | template: ``
37 | }
38 | }).$mount()
39 |
40 | vm.$nextTick(_ => {
41 | expect(vm.preview).toEqual({})
42 | expect(vm.styles).toEqual('.main {}')
43 | })
44 | })
45 | })
46 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Vuep - A component for rendering Vue components with live editor and preview.
6 |
7 |
8 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
30 |
31 |
--------------------------------------------------------------------------------
/__test__/preview.spec.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Preview from '../src/components/preview'
3 |
4 | const Ctor = Vue.extend(Preview)
5 |
6 | test('scoped style', () => {
7 | const vm = new Ctor({
8 | propsData: {
9 | styles: '.main { color: red } #id { width: 10px } p { height: 20 } .wrapper input { background: url("");}'
10 | }
11 | }).$mount()
12 | const _uid = vm._uid
13 | const scoped = '.vuep-scoped-' + _uid
14 | const fixture = `${scoped} .main { color: red } ${scoped} #id { width: 10px } ${scoped} p { height: 20 } ${scoped} .wrapper input { background: url("");}`
15 |
16 | expect(vm.scopedStyle).toEqual(fixture)
17 | })
18 |
19 | describe('append new vm', () => {
20 | const vm = new Ctor({
21 | propsData: {
22 | value: {
23 | template: 'hello, {{ name }}
',
24 | data: {
25 | name: 'cinwell'
26 | }
27 | }
28 | }
29 | }).$mount()
30 |
31 | it('created', () => {
32 | expect(vm.codeVM).toBeDefined()
33 | expect(vm.codeVM.$el.textContent).toEqual('hello, cinwell')
34 | })
35 |
36 | it('updated', () => {
37 | vm.value = {
38 | template: '{{ name }}
',
39 | data: {
40 | name: 'cinwell'
41 | }
42 | }
43 |
44 | vm.$nextTick(_ => {
45 | expect(vm.codeVM.$el.textContent).toEqual('cinwell')
46 | })
47 | })
48 | })
49 |
--------------------------------------------------------------------------------
/src/utils/transform.js:
--------------------------------------------------------------------------------
1 | import require from './require.js'
2 | window.require = require
3 |
4 | export default function evalJS (script, scope = {}) {
5 | // https://www.npmjs.com/package/babel-standalone
6 | /* istanbul ignore next */
7 |
8 | if (typeof Babel !== 'undefined') {
9 | const plugins = []
10 |
11 | // Register jsx plugin
12 | if (window['babel-plugin-transform-vue-jsx']) {
13 | if (!Babel.availablePlugins['transform-vue-jsx']) { // eslint-disable-line
14 | Babel.registerPlugin('transform-vue-jsx', window['babel-plugin-transform-vue-jsx']) // eslint-disable-line
15 | }
16 | plugins.push('transform-vue-jsx')
17 | }
18 |
19 | script = Babel.transform(script, { // eslint-disable-line
20 | presets: [['es2015', { 'loose': true }], 'stage-2'],
21 | plugins,
22 | comments: false
23 | }).code
24 | }
25 |
26 | var scopeDecl = ''
27 | for (var variable in scope) {
28 | if (scope.hasOwnProperty(variable)) {
29 | scopeDecl += 'var ' + variable + ' = __vuep[\'' + variable + '\'];'
30 | }
31 | }
32 |
33 | script = `(function(exports){var module={};module.exports=exports;${scopeDecl};${script};return module.exports.__esModule?module.exports.default:module.exports;})({})`
34 | const result = new Function('__vuep', 'return ' + script)(scope) || {} // eslint-disable-line
35 | return result
36 | }
37 |
--------------------------------------------------------------------------------
/__test__/parser.spec.js:
--------------------------------------------------------------------------------
1 | import parser from '../src/utils/parser'
2 |
3 | test('script tag', () => {
4 | const fixture = `
5 |
6 |
7 | 123
8 |
9 |
12 | `
13 | const result = parser(fixture)
14 |
15 | expect(result.template).toContain('123
')
16 | expect(result.script).toContain('module.exports = {}')
17 | expect(Array.isArray(result.styles)).toBeTruthy()
18 | expect(result.styles.length).toEqual(1)
19 | expect(result.styles[0]).toContain('div { color: red }')
20 | })
21 |
22 | test('multiple style', () => {
23 | const fixture = `
24 |
25 |
26 |
27 | `
28 | const result = parser(fixture)
29 |
30 | expect(Array.isArray(result.styles)).toBeTruthy()
31 | expect(result.styles.length).toEqual(3)
32 | expect(result.styles[0]).toContain('div { color: red }')
33 | expect(result.styles[1]).toContain('div { color: green }')
34 | expect(result.styles[2]).toContain('div { color: blue }')
35 | })
36 |
37 | test('only JavaScript', () => {
38 | const fixture = 'module.exports = {}'
39 | const result = parser(fixture)
40 |
41 | expect(result.template).toBeUndefined()
42 | expect(result.script).toContain('module.exports = {}')
43 | expect(result.styles).toBeUndefined()
44 | })
45 |
--------------------------------------------------------------------------------
/src/style/vuep.css:
--------------------------------------------------------------------------------
1 | @import "codemirror/lib/codemirror.css";
2 | @import "codemirror/theme/material.css";
3 |
4 | .vuep {
5 | display: flex;
6 | font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
7 | height: 400px;
8 |
9 | ::-webkit-scrollbar-track {
10 | border-radius: 10px;
11 | background-color: #F5F5F5;
12 | }
13 |
14 | ::-webkit-scrollbar {
15 | width: 8px;
16 | height: 8px;
17 | background-color: #F5F5F5;
18 | }
19 |
20 | ::-webkit-scrollbar-thumb {
21 | border-radius: 8px;
22 | background-color: #bbb;
23 | transition: all 0.5s;
24 | }
25 |
26 | ::-webkit-scrollbar-thumb:hover {
27 | border-radius: 8px;
28 | background-color: #777;
29 | }
30 | }
31 |
32 | .vuep-editor, .vuep-preview, .vuep-error {
33 | border-radius: 2px;
34 | height: inherit;
35 | margin-right: 10px;
36 | overflow: auto;
37 | width: 50%;
38 |
39 | &:last-child {
40 | margin-right: 0;
41 | }
42 |
43 | .CodeMirror {
44 | height: inherit;
45 | }
46 | }
47 |
48 | .vuep-editor {
49 | line-height: 1.2em;
50 | }
51 |
52 | .vuep-error {
53 | color: #f66;
54 | }
55 |
56 | .vuep-preview, .vuep-error {
57 | border: 1px solid #eee;
58 | box-sizing: border-box;
59 | padding: 25px 35px;
60 | }
61 |
62 | @media (max-width: 600px) {
63 | .vuep {
64 | display: block;
65 | height: auto;
66 | }
67 |
68 | .vuep-editor, .vuep-preview, .vuep-error {
69 | margin: 0 0 15px 0;
70 | height: 400px;
71 | width: 100%;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/__test__/compiler.spec.js:
--------------------------------------------------------------------------------
1 | import compiler from '../src/utils/compiler'
2 |
3 | test('No data', () => {
4 | const compiled = compiler({})
5 |
6 | expect(compiled.error.name).toEqual('Error')
7 | expect(compiled.error.message).toEqual('no data')
8 | })
9 |
10 | test('only template', () => {
11 | const compiled = compiler({
12 | template: '
'
13 | })
14 |
15 | expect(compiled.result).toEqual({
16 | template: '
'
17 | })
18 | })
19 |
20 | test('only empty script', () => {
21 | const compiled = compiler({
22 | script: 'module.exports = {}'
23 | })
24 |
25 | expect(compiled.result).toEqual({})
26 | })
27 |
28 | test('only script', () => {
29 | const compiled = compiler({
30 | script: `module.exports = {template : '
'}`
31 | })
32 |
33 | expect(compiled.result).toEqual({
34 | template: '
'
35 | })
36 | })
37 |
38 | test('script and tempalte', () => {
39 | const compiled = compiler({
40 | template: '
cinwell ',
41 | script: 'module.exports = { b: {} }'
42 | })
43 |
44 | expect(compiled.result).toEqual({
45 | b: {},
46 | template: '
cinwell '
47 | })
48 | })
49 |
50 | test('multiple style tag', () => {
51 | const compiled = compiler({
52 | styles: [
53 | '.a { color: #ccc }',
54 | '.b { height: 100px; width: 200px }'
55 | ],
56 | template: '
'
57 | })
58 |
59 | expect(compiled.styles).toEqual('.a { color: #ccc } .b { height: 100px; width: 200px }')
60 | })
61 |
62 | test('no style', () => {
63 | const compiled = compiler({
64 | template: '
'
65 | })
66 |
67 | expect(compiled.styles).toBeUndefined()
68 | })
69 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vuep",
3 | "version": "0.8.1",
4 | "description": "A component for rendering Vue components with live editor and preview.",
5 | "main": "dist/vuep.common.js",
6 | "unpkg": "dist/vuep.js",
7 | "scripts": {
8 | "test": "eslint src && jest",
9 | "test:ci": "npm test && cat ./coverage/lcov.info | coveralls",
10 | "build": "node build/build.js && npm run build:css",
11 | "build:css": "node build/build-css.js",
12 | "dev": "rollup -wc build/watch.js"
13 | },
14 | "jest": {
15 | "browser": true,
16 | "collectCoverage": true,
17 | "transform": {
18 | "^.+\\.js$": "babel-jest"
19 | }
20 | },
21 | "repository": {
22 | "type": "git",
23 | "url": "git+https://github.com/QingWei-Li/vuep.git"
24 | },
25 | "keywords": [
26 | "vue",
27 | "playground",
28 | "preview",
29 | "editable",
30 | "component",
31 | "vuejs"
32 | ],
33 | "author": "qingwei-li (https://github.com/QingWei-Li)",
34 | "license": "MIT",
35 | "bugs": {
36 | "url": "https://github.com/QingWei-Li/vuep/issues"
37 | },
38 | "homepage": "https://qingwei-li.github.io/vuep/",
39 | "devDependencies": {
40 | "babel-jest": "^18.0.0",
41 | "babel-preset-es2015": "^6.18.0",
42 | "babel-preset-stage-3": "^6.22.0",
43 | "codemirror": "^5.22.0",
44 | "cssnano": "^3.9.1",
45 | "eslint": "^3.12.2",
46 | "eslint-config-vue": "^2.0.1",
47 | "eslint-plugin-vue": "^1.0.0",
48 | "jest": "^18.0.0",
49 | "postcss": "^5.2.7",
50 | "postcss-salad": "^1.0.6",
51 | "rollup": "^0.38.0",
52 | "rollup-plugin-buble": "^0.15.0",
53 | "rollup-plugin-commonjs": "^6.0.1",
54 | "rollup-plugin-node-resolve": "^2.0.0",
55 | "rollup-plugin-uglify": "^1.0.1",
56 | "rollup-watch": "^3.2.2",
57 | "vue": "^2.1.7"
58 | },
59 | "peerDependencies": {
60 | "codemirror": "^5.22.0"
61 | },
62 | "dependencies": {
63 | "simple-assign": "^0.1.0"
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/components/playground.js:
--------------------------------------------------------------------------------
1 | import Editor from './editor'
2 | import Preview from './preview'
3 | import parser from '../utils/parser'
4 | import compiler from '../utils/compiler'
5 |
6 | export default {
7 | name: 'Vuep',
8 |
9 | props: {
10 | template: String,
11 | options: {},
12 | keepData: Boolean,
13 | value: String,
14 | scope: Object,
15 | iframe: Boolean
16 | },
17 |
18 | data () {
19 | return {
20 | content: '',
21 | preview: '',
22 | styles: '',
23 | error: ''
24 | }
25 | },
26 |
27 | render (h) {
28 | let win
29 |
30 | /* istanbul ignore next */
31 | if (this.error) {
32 | win = h('div', {
33 | class: 'vuep-error'
34 | }, [this.error])
35 | } else {
36 | win = h(Preview, {
37 | class: 'vuep-preview',
38 | props: {
39 | value: this.preview,
40 | styles: this.styles,
41 | keepData: this.keepData,
42 | iframe: this.iframe
43 | },
44 | on: {
45 | error: this.handleError
46 | }
47 | })
48 | }
49 |
50 | return h('div', { class: 'vuep' }, [
51 | h(Editor, {
52 | class: 'vuep-editor',
53 | props: {
54 | value: this.content,
55 | options: this.options
56 | },
57 | on: {
58 | change: [this.executeCode, val => this.$emit('input', val)]
59 | }
60 | }),
61 | win
62 | ])
63 | },
64 |
65 | watch: {
66 | value: {
67 | immediate: true,
68 | handler (val) {
69 | val && this.executeCode(val)
70 | }
71 | }
72 | },
73 |
74 | created () {
75 | /* istanbul ignore next */
76 | if (this.$isServer) return
77 | let content = this.template
78 |
79 | if (/^[\.#]/.test(this.template)) {
80 | const html = document.querySelector(this.template)
81 | if (!html) throw Error(`${this.template} is not found`)
82 |
83 | /* istanbul ignore next */
84 | content = html.innerHTML
85 | }
86 |
87 | if (content) {
88 | this.executeCode(content)
89 | this.$emit('input', content)
90 | }
91 | },
92 |
93 | methods: {
94 | handleError (err) {
95 | /* istanbul ignore next */
96 | this.error = err
97 | },
98 |
99 | executeCode (code) {
100 | this.error = ''
101 | const result = parser(code)
102 |
103 | /* istanbul ignore next */
104 | if (result.error) {
105 | this.error = result.error.message
106 | return
107 | }
108 |
109 | const compiledCode = compiler(result, this.scope)
110 |
111 | /* istanbul ignore next */
112 | if (compiledCode.error) {
113 | this.error = compiledCode.error.message
114 | return
115 | }
116 |
117 | this.content = result.content
118 | this.preview = compiledCode.result
119 | if (compiledCode.styles) this.styles = compiledCode.styles
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/components/preview.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue/dist/vue.common'
2 | import assign from '../utils/assign' // eslint-disable-line
3 |
4 | export default {
5 | name: 'preview',
6 |
7 | props: ['value', 'styles', 'keepData', 'iframe'],
8 |
9 | render (h) {
10 | this.className = 'vuep-scoped-' + this._uid
11 |
12 | return h(this.iframe ? 'iframe' : 'div', {
13 | class: this.className
14 | }, [
15 | this.scopedStyle ? h('style', null, this.scopedStyle) : ''
16 | ])
17 | },
18 |
19 | computed: {
20 | scopedStyle () {
21 | return this.styles
22 | ? insertScope(this.styles, `.${this.className}`)
23 | : ''
24 | }
25 | },
26 |
27 | mounted () {
28 | this.$watch('value', this.renderCode, { immediate: true })
29 | if (this.iframe) {
30 | this.$el.addEventListener('load', this.renderCode)
31 | }
32 | },
33 | beforeDestroy () {
34 | if (this.iframe) {
35 | this.$el.removeEventListener('load', this.renderCode)
36 | }
37 | },
38 | methods: {
39 | renderCode () {
40 | // Firefox needs the iframe to be loaded
41 | if (this.iframe && this.$el.contentDocument.readyState !== 'complete') {
42 | return
43 | }
44 |
45 | const val = this.value
46 | const lastData = this.keepData && this.codeVM && assign({}, this.codeVM.$data)
47 | const container = this.iframe ? this.$el.contentDocument.body : this.$el
48 |
49 | if (this.codeVM) {
50 | this.codeVM.$destroy()
51 | container.removeChild(this.codeVM.$el)
52 | }
53 |
54 | this.codeEl = document.createElement('div')
55 | container.appendChild(this.codeEl)
56 |
57 | if (this.iframe) {
58 | const head = this.$el.contentDocument.head
59 | if (this.styleEl) {
60 | head.removeChild(this.styleEl)
61 | for (const key in this.styleNodes) {
62 | head.removeChild(this.styleNodes[key])
63 | }
64 | }
65 | this.styleEl = document.createElement('style')
66 | this.styleEl.appendChild(document.createTextNode(this.styles))
67 | this.styleNodes = []
68 | const documentStyles = getDocumentStyle()
69 | for (const key in documentStyles) {
70 | this.styleNodes[key] = documentStyles[key].cloneNode(true)
71 | head.appendChild(this.styleNodes[key])
72 | }
73 | head.appendChild(this.styleEl)
74 | }
75 |
76 | try {
77 | const parent = this
78 | this.codeVM = new Vue({ parent, ...val }).$mount(this.codeEl)
79 |
80 | if (lastData) {
81 | for (const key in lastData) {
82 | this.codeVM[key] = lastData[key]
83 | }
84 | }
85 | } catch (e) {
86 | /* istanbul ignore next */
87 | this.$emit('error', e)
88 | }
89 | }
90 | }
91 | }
92 |
93 | function insertScope (style, scope) {
94 | const regex = /(^|\})\s*([^{]+)/g
95 | return style.trim().replace(regex, (m, g1, g2) => {
96 | return g1 ? `${g1} ${scope} ${g2}` : `${scope} ${g2}`
97 | })
98 | }
99 |
100 | function getDocumentStyle () {
101 | const links = document.querySelectorAll('link[rel="stylesheet"]')
102 | const styles = document.querySelectorAll('style')
103 | return Array.from(links).concat(Array.from(styles))
104 | }
105 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Vuep (vue playground)
2 |
3 | [](https://travis-ci.org/QingWei-Li/vuep)
4 | [](https://coveralls.io/github/QingWei-Li/vuep?branch=master)
5 | [](https://www.npmjs.com/package/vuep)
6 |
7 |
8 | > 🎡 A component for rendering Vue components with live editor and preview.
9 |
10 |
11 |
12 | 
13 |
14 | ## Links
15 |
16 | - Docs: https://cinwell.com/vuep/
17 | - An online playgound: https://vuep.netlify.com
18 |
19 |
20 |
21 | ## Installation
22 |
23 | ### Yarn
24 | ```bash
25 | yarn add vuep codemirror
26 | # npm i vuep codemirror -S
27 | ```
28 |
29 | ### HTML tag
30 |
31 | ```html
32 |
33 |
34 |
35 |
36 |
37 |
38 | ```
39 |
40 | ## Quick start
41 |
42 | **Need the full (compiler-included) build of Vue**
43 |
44 | webpack config
45 | ```javascript
46 | {
47 | alias: {
48 | 'vue$': 'vue/dist/vue.common'
49 | }
50 | }
51 | ```
52 |
53 | ```javascript
54 | import Vue from 'vue'
55 | import Vuep from 'vuep'
56 | import 'vuep/dist/vuep.css'
57 |
58 | Vue.use(Vuep /*, { codemirror options } */)
59 | // or Vue.component('Vuep', Vuep)
60 |
61 | new Vue({
62 | el: '#app',
63 |
64 | created: function () {
65 | this.code = `
66 |
67 | Hello, {{ name }}!
68 |
69 |
70 |
77 | `
78 | }
79 | })
80 | ```
81 |
82 |
83 | ### Usage A
84 | ```html
85 |
86 |
87 |
88 | ```
89 |
90 |
91 | ### Usage B
92 | you can write in HTML file or even a markdown file.
93 |
94 | ```html
95 |
96 |
97 |
98 |
99 |
111 |
112 | ```
113 |
114 |
115 | ### Scope
116 |
117 | You can customize scope by passing an object to the scope property.
118 |
119 | This object can contain component available in main scope to include them into Vuep.
120 |
121 | - **features.js**: Component to showcase into Vuep
122 | ```javascript
123 | export default {
124 | props: {
125 | features: Array
126 | },
127 | template: `
128 |
Features
129 |
130 | {{ feature }}
131 |
132 |
`
133 | }
134 | ```
135 |
136 | - **app.js**: Application that needs to showcase Features component through Vuep
137 | ```javascript
138 | import Vue from 'vue'
139 |
140 | import Features from 'features' // Import component
141 |
142 | new Vue({
143 | el: '#app',
144 | data: function () {
145 | return {
146 | scope: { Features }, // Set the scope of vuep
147 | value: `
148 |
149 |
150 |
151 |
152 |
153 |
154 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
82 |
127 |
183 |
239 |
--------------------------------------------------------------------------------
/dist/vuep.min.css:
--------------------------------------------------------------------------------
1 | .CodeMirror{font-family:monospace;height:300px;color:#000}.CodeMirror-lines{padding:4px 0}.CodeMirror pre{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0!important;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-animate-fat-cursor{width:auto;border:0;-webkit-animation:a 1.06s steps(1) infinite;animation:a 1.06s steps(1) infinite;background-color:#7e7}@-webkit-keyframes a{50%{background-color:transparent}}@keyframes a{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-rulers{position:absolute;left:0;right:0;top:-50px;bottom:-20px;overflow:hidden}.CodeMirror-ruler{border-left:1px solid #ccc;top:0;bottom:0;position:absolute}.cm-s-default .cm-header{color:blue}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta,.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-invalidchar,.cm-s-default .cm-error{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0f0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#f22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:#fff}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-30px;margin-right:-30px;padding-bottom:30px;height:100%;outline:none;position:relative}.CodeMirror-sizer{position:relative;border-right:30px solid transparent}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:5;display:none}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;min-height:100%;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-30px}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:none!important;border:none!important}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-gutter-wrapper{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre{border-radius:0;border-width:0;background:transparent;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent;-webkit-font-variant-ligatures:contextual;font-variant-ligatures:contextual}.CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;overflow:auto}.CodeMirror-code{outline:none}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizer{box-sizing:content-box}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-cursor{position:absolute;pointer-events:none}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}.CodeMirror-focused div.CodeMirror-cursors,div.CodeMirror-dragcursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirror-line>span>span::-moz-selection{background:#d7d4f0}.cm-searching{background:#ffa;background:rgba(255,255,0,.4)}.cm-force-border{padding-right:.1px}@media print{.CodeMirror div.CodeMirror-cursors{visibility:hidden}}.cm-tab-wrap-hack:after{content:""}span.CodeMirror-selectedtext{background:none}.cm-s-material.CodeMirror{background-color:#263238;color:#e9eded}.cm-s-material .CodeMirror-gutters{background:#263238;color:#537f7e;border:none}.cm-s-material .CodeMirror-guttermarker,.cm-s-material .CodeMirror-guttermarker-subtle,.cm-s-material .CodeMirror-linenumber{color:#537f7e}.cm-s-material .CodeMirror-cursor{border-left:1px solid #f8f8f0}.cm-s-material div.CodeMirror-selected{background:hsla(0,0%,100%,.15)}.cm-s-material.CodeMirror-focused div.CodeMirror-selected{background:hsla(0,0%,100%,.1)}.cm-s-material .CodeMirror-line::selection,.cm-s-material .CodeMirror-line>span::selection,.cm-s-material .CodeMirror-line>span>span::selection{background:hsla(0,0%,100%,.1)}.cm-s-material .CodeMirror-line::-moz-selection,.cm-s-material .CodeMirror-line>span::-moz-selection,.cm-s-material .CodeMirror-line>span>span::-moz-selection{background:hsla(0,0%,100%,.1)}.cm-s-material .CodeMirror-activeline-background{background:transparent}.cm-s-material .cm-keyword{color:#c792ea}.cm-s-material .cm-operator{color:#e9eded}.cm-s-material .cm-variable-2{color:#80cbc4}.cm-s-material .cm-variable-3{color:#82b1ff}.cm-s-material .cm-builtin{color:#decb6b}.cm-s-material .cm-atom,.cm-s-material .cm-number{color:#f77669}.cm-s-material .cm-def{color:#e9eded}.cm-s-material .cm-string{color:#c3e88d}.cm-s-material .cm-string-2{color:#80cbc4}.cm-s-material .cm-comment{color:#546e7a}.cm-s-material .cm-variable{color:#82b1ff}.cm-s-material .cm-meta,.cm-s-material .cm-tag{color:#80cbc4}.cm-s-material .cm-attribute{color:#ffcb6b}.cm-s-material .cm-property{color:#80cbae}.cm-s-material .cm-qualifier,.cm-s-material .cm-variable-3{color:#decb6b}.cm-s-material .cm-tag{color:#ff5370}.cm-s-material .cm-error{color:#fff;background-color:#ec5f67}.cm-s-material .CodeMirror-matchingbracket{text-decoration:underline;color:#fff!important}.vuep{display:-webkit-box;display:-ms-flexbox;display:flex;font-family:Source Sans Pro,Helvetica Neue,Arial,sans-serif;height:400px}.vuep ::-webkit-scrollbar-track{border-radius:10px;background-color:#f5f5f5}.vuep ::-webkit-scrollbar{width:8px;height:8px;background-color:#f5f5f5}.vuep ::-webkit-scrollbar-thumb{border-radius:8px;background-color:#bbb;-webkit-transition:all .5s;transition:all .5s}.vuep ::-webkit-scrollbar-thumb:hover{border-radius:8px;background-color:#777}.vuep-editor,.vuep-error,.vuep-preview{border-radius:2px;height:inherit;margin-right:10px;overflow:auto;width:50%}.vuep-editor .CodeMirror,.vuep-error .CodeMirror,.vuep-preview .CodeMirror{height:inherit}.vuep-editor:last-child,.vuep-error:last-child,.vuep-preview:last-child{margin-right:0}.vuep-editor{line-height:1.2em}.vuep-error{color:#f66}.vuep-error,.vuep-preview{border:1px solid #eee;box-sizing:border-box;padding:25px 35px}@media (max-width:600px){.vuep{display:block;height:auto}.vuep-editor,.vuep-error,.vuep-preview{margin:0 0 15px;height:400px;width:100%}}
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Demo
2 |
3 |
4 |
39 |
40 |
41 |
42 |
43 | # Usage
44 |
45 | ## CommonJS
46 | **Need the full (compiler-included) build of Vue**
47 |
48 | webpack config
49 |
50 | ```javascript
51 | {
52 | alias: {
53 | 'vue$': 'vue/dist/vue.common'
54 | }
55 | }
56 | ```
57 |
58 | ```javascript
59 | import Vue from 'vue'
60 | import Vuep from 'vuep'
61 | import 'vuep/dist/vuep.css'
62 |
63 | Vue.use(Vuep /*, { codemirror options } */)
64 | // or Vue.component('Vuep', Vuep)
65 |
66 | new Vue({
67 | el: '#app',
68 |
69 | created: function () {
70 | this.code = `
71 |
72 | Hello, {{ name }}!
73 |
74 |
75 |
82 | `
83 | }
84 | })
85 | ```
86 |
87 | template
88 | ```html
89 |
90 |
91 |
92 | ```
93 |
94 | ## UMD
95 |
96 | index.html
97 | ```html
98 |
99 |
100 |
101 |
102 |
103 |
104 | ```
105 |
106 | template
107 | ```html
108 |
109 |
110 |
122 |
123 | ```
124 |
125 | The default is supported in docsify. such as https://qingwei-li.github.io/vuep/README.md
126 |
127 | # Options
128 |
129 | https://codemirror.net/index.html
130 |
131 | ## Global config
132 | ```javascript
133 | Vue.use(Vuep /*, { codemirror config }*/)
134 | ```
135 |
136 | ## Props
137 |
138 | ```html
139 |
140 | ```
141 |
142 | ### Default config
143 | ```json
144 | {
145 | "lineNumbers": true,
146 | "mode": "text/x-vue",
147 | "theme": "material",
148 | "tabSize": 2
149 | }
150 | ```
151 |
152 | ### example
153 |
154 | ```html
155 |
156 |
157 |
166 | ```
167 |
168 |
169 |
170 |
179 |
180 |
181 |
182 | ## v-model
183 |
184 | ```html
185 |
186 |
187 |
188 |
189 |
202 | ```
203 |
204 | ## JavaScript scope
205 |
206 | You can customize JavaScript scope by setting an object to the scope property.
207 |
208 | This object can contain component from your app scope to include them into Vuep scope.
209 |
210 | - **features.js**: Component to showcase into Vuep
211 |
212 | ```javascript
213 | export default {
214 | props: {
215 | features: Array
216 | },
217 | template: `
218 |
Features
219 |
220 | {{ feature }}
221 |
222 |
`
223 | }
224 | ```
225 |
226 | - **app.js**: Application that needs to showcase Features component through Vuep
227 |
228 | ```javascript
229 | import Vue from 'vue'
230 |
231 | import Features from 'features' // Import component
232 |
233 | new Vue({
234 | el: '#app',
235 | data: function () {
236 | return {
237 | scope: { Features }, // Set the scope of vuep
238 | value: `
239 |
240 |
241 |
242 |
243 |
244 |
245 |
310 |
311 |
312 | ## Can I use ES6?
313 |
314 | I know you will worry that some browsers do not support ES6, but we have [babel-standalone](https://www.npmjs.com/package/babel-standalone).
315 |
316 | > babel-standalone is a standalone build of Babel for use in non-Node.js environments, including browsers.
317 |
318 | How to use:
319 |
320 | In your HTML file
321 |
322 | ```html
323 |
324 | ```
325 |
326 | Done. Now you are free to use ES6, Vuep will compile them to ES5 through the babel.
327 |
328 |
329 |
330 |
331 |
349 |
350 |
351 | ## Can I use JSX?
352 |
353 | Sure.
354 |
355 | ```html
356 |
357 |
358 | ```
359 |
360 |
361 |
362 |
376 |
377 | ## Can I use `require`?
378 |
379 | Sure. if you use ES6 syntax you can even use `import`.
380 |
381 | vuep implement a nodejs like synchrounous require interface in browser, so you can directly require a js file.
382 |
383 | ```jsx
384 | /* remote.js */
385 | export default {
386 | name: 'remote',
387 | render () {
388 | return from remote
389 | }
390 | }
391 | ```
392 |
393 |
394 |
395 |
408 |
409 |
410 | # Warning
411 |
412 | If you use `script(type="text/x-template)"`, The script tag must be at the end, for example
413 |
414 | ```html
415 |
419 |
420 | ```
421 |
422 | These will be parsed incorrectly
423 | ```html
424 |
426 |
427 |
428 |
429 | ```
430 |
431 | ```html
432 |
435 |
436 |
437 | ```
438 |
--------------------------------------------------------------------------------
/dist/vuep.common.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
4 |
5 | var CodeMirror = _interopDefault(require('codemirror'));
6 | var Vue$1 = _interopDefault(require('vue/dist/vue.common'));
7 |
8 | var index = function (target) {
9 | var arguments$1 = arguments;
10 |
11 | for (var i = 1; i < arguments.length; i++) {
12 | var source = arguments$1[i];
13 | for (var key in source) {
14 | if (Object.prototype.hasOwnProperty.call(source, key)) {
15 | target[key] = source[key];
16 | }
17 | }
18 | }
19 | return target;
20 | };
21 |
22 | var assign = Object.assign || index;
23 |
24 | var DEFAULT_OPTIONS = {
25 | lineNumbers: true,
26 | mode: 'text/x-vue',
27 | theme: 'material',
28 | tabSize: 2
29 | };
30 |
31 | var Editor = {
32 | name: 'VueCodeMirror',
33 |
34 | props: ['value', 'options'],
35 |
36 | render: function render (h) {
37 | return h('div', null, [
38 | h('textarea', { ref: 'textarea' }, this.value)
39 | ])
40 | },
41 |
42 | mounted: function mounted () {
43 | this.currentOptions = assign({}, DEFAULT_OPTIONS, this.options);
44 | this.editor = CodeMirror.fromTextArea(this.$refs.textarea, this.currentOptions);
45 | this.editor.on('change', this.handleChange);
46 | },
47 |
48 | watch: {
49 | value: function value (val) {
50 | val !== this.editor.getValue() && this.editor.setValue(val);
51 | }
52 | },
53 |
54 | methods: {
55 | handleChange: function handleChange () {
56 | /* istanbul ignore next */
57 | this.$emit('change', this.editor.getValue());
58 | }
59 | }
60 | };
61 |
62 | var Preview = {
63 | name: 'preview',
64 |
65 | props: ['value', 'styles', 'keepData', 'iframe'],
66 |
67 | render: function render (h) {
68 | this.className = 'vuep-scoped-' + this._uid;
69 |
70 | return h(this.iframe ? 'iframe' : 'div', {
71 | class: this.className
72 | }, [
73 | this.scopedStyle ? h('style', null, this.scopedStyle) : ''
74 | ])
75 | },
76 |
77 | computed: {
78 | scopedStyle: function scopedStyle () {
79 | return this.styles
80 | ? insertScope(this.styles, ("." + (this.className)))
81 | : ''
82 | }
83 | },
84 |
85 | mounted: function mounted () {
86 | this.$watch('value', this.renderCode, { immediate: true });
87 | if (this.iframe) {
88 | this.$el.addEventListener('load', this.renderCode);
89 | }
90 | },
91 | beforeDestroy: function beforeDestroy () {
92 | if (this.iframe) {
93 | this.$el.removeEventListener('load', this.renderCode);
94 | }
95 | },
96 | methods: {
97 | renderCode: function renderCode () {
98 | var this$1 = this;
99 |
100 | // Firefox needs the iframe to be loaded
101 | if (this.iframe && this.$el.contentDocument.readyState !== 'complete') {
102 | return
103 | }
104 |
105 | var val = this.value;
106 | var lastData = this.keepData && this.codeVM && assign({}, this.codeVM.$data);
107 | var container = this.iframe ? this.$el.contentDocument.body : this.$el;
108 |
109 | if (this.codeVM) {
110 | this.codeVM.$destroy();
111 | container.removeChild(this.codeVM.$el);
112 | }
113 |
114 | this.codeEl = document.createElement('div');
115 | container.appendChild(this.codeEl);
116 |
117 | if (this.iframe) {
118 | var head = this.$el.contentDocument.head;
119 | if (this.styleEl) {
120 | head.removeChild(this.styleEl);
121 | for (var key in this$1.styleNodes) {
122 | head.removeChild(this$1.styleNodes[key]);
123 | }
124 | }
125 | this.styleEl = document.createElement('style');
126 | this.styleEl.appendChild(document.createTextNode(this.styles));
127 | this.styleNodes = [];
128 | var documentStyles = getDocumentStyle();
129 | for (var key$1 in documentStyles) {
130 | this$1.styleNodes[key$1] = documentStyles[key$1].cloneNode(true);
131 | head.appendChild(this$1.styleNodes[key$1]);
132 | }
133 | head.appendChild(this.styleEl);
134 | }
135 |
136 | try {
137 | var parent = this;
138 | this.codeVM = new Vue$1(assign({}, {parent: parent}, val)).$mount(this.codeEl);
139 |
140 | if (lastData) {
141 | for (var key$2 in lastData) {
142 | this$1.codeVM[key$2] = lastData[key$2];
143 | }
144 | }
145 | } catch (e) {
146 | /* istanbul ignore next */
147 | this.$emit('error', e);
148 | }
149 | }
150 | }
151 | };
152 |
153 | function insertScope (style, scope) {
154 | var regex = /(^|\})\s*([^{]+)/g;
155 | return style.trim().replace(regex, function (m, g1, g2) {
156 | return g1 ? (g1 + " " + scope + " " + g2) : (scope + " " + g2)
157 | })
158 | }
159 |
160 | function getDocumentStyle () {
161 | var links = document.querySelectorAll('link[rel="stylesheet"]');
162 | var styles = document.querySelectorAll('style');
163 | return Array.from(links).concat(Array.from(styles))
164 | }
165 |
166 | var parser = function (input) {
167 | var html = document.createElement('div');
168 | var content = html.innerHTML = input.trim();
169 |
170 | try {
171 | var template = html.querySelector('template');
172 | var script = html.querySelector('script');
173 | var styles = Array.prototype.slice.call(html.querySelectorAll('style')).map(function (n) { return n.innerHTML; });
174 |
175 | if (!template && !script && !styles.length) {
176 | return {
177 | content: content,
178 | script: content
179 | }
180 | }
181 |
182 | return {
183 | content: /<\/script>$/g.test(content) ? content : (content + '\n'),
184 | template: template ? template.innerHTML : '',
185 | script: script ? script.innerHTML : '',
186 | styles: styles
187 | }
188 | } catch (error) {
189 | /* istanbul ignore next */
190 | return { error: error }
191 | }
192 | };
193 |
194 | var JSMODULE_REG = /\.((js)|(jsx))$/;
195 |
196 | function require$1 (url) {
197 | if (JSMODULE_REG.test(url)) {
198 | return getAndCache(url)
199 | }
200 | }
201 |
202 | // modify from docsify: https://github.com/QingWei-Li/docsify/blob/master/src/core/fetch/ajax.js
203 |
204 | var cache = {};
205 |
206 | /**
207 | * Simple ajax get
208 | * @param {string} url
209 | * @return { then(resolve, reject), abort }
210 | */
211 | function getAndCache (url) {
212 | var xhr = new XMLHttpRequest(); // eslint-disable-line
213 |
214 | if (cache[url]) {
215 | return cache[url]
216 | }
217 |
218 | xhr.open('GET', url, false);
219 | xhr.send();
220 | var script = xhr.responseText;
221 | cache[url] = evalJS(script);
222 | return cache[url]
223 | }
224 |
225 | window.require = require$1;
226 |
227 | function evalJS (script, scope) {
228 | if ( scope === void 0 ) scope = {};
229 |
230 | // https://www.npmjs.com/package/babel-standalone
231 | /* istanbul ignore next */
232 |
233 | if (typeof Babel !== 'undefined') {
234 | var plugins = [];
235 |
236 | // Register jsx plugin
237 | if (window['babel-plugin-transform-vue-jsx']) {
238 | if (!Babel.availablePlugins['transform-vue-jsx']) { // eslint-disable-line
239 | Babel.registerPlugin('transform-vue-jsx', window['babel-plugin-transform-vue-jsx']); // eslint-disable-line
240 | }
241 | plugins.push('transform-vue-jsx');
242 | }
243 |
244 | script = Babel.transform(script, { // eslint-disable-line
245 | presets: [['es2015', { 'loose': true }], 'stage-2'],
246 | plugins: plugins,
247 | comments: false
248 | }).code;
249 | }
250 |
251 | var scopeDecl = '';
252 | for (var variable in scope) {
253 | if (scope.hasOwnProperty(variable)) {
254 | scopeDecl += 'var ' + variable + ' = __vuep[\'' + variable + '\'];';
255 | }
256 | }
257 |
258 | script = "(function(exports){var module={};module.exports=exports;" + scopeDecl + ";" + script + ";return module.exports.__esModule?module.exports.default:module.exports;})({})";
259 | var result = new Function('__vuep', 'return ' + script)(scope) || {}; // eslint-disable-line
260 | return result
261 | }
262 |
263 | var compiler = function (ref, scope) {
264 | var template = ref.template;
265 | var script = ref.script; if ( script === void 0 ) script = 'module.exports={}';
266 | var styles = ref.styles;
267 | if ( scope === void 0 ) scope = {};
268 |
269 | try {
270 | if (script === 'module.exports={}' && !template) { throw Error('no data') }
271 | var result = evalJS(script, scope);
272 | if (template) {
273 | result.template = template;
274 | }
275 | return {
276 | result: result,
277 | styles: styles && styles.join(' ')
278 | }
279 | } catch (error) {
280 | return { error: error }
281 | }
282 | };
283 |
284 | var Vuep$2 = {
285 | name: 'Vuep',
286 |
287 | props: {
288 | template: String,
289 | options: {},
290 | keepData: Boolean,
291 | value: String,
292 | scope: Object,
293 | iframe: Boolean
294 | },
295 |
296 | data: function data () {
297 | return {
298 | content: '',
299 | preview: '',
300 | styles: '',
301 | error: ''
302 | }
303 | },
304 |
305 | render: function render (h) {
306 | var this$1 = this;
307 |
308 | var win;
309 |
310 | /* istanbul ignore next */
311 | if (this.error) {
312 | win = h('div', {
313 | class: 'vuep-error'
314 | }, [this.error]);
315 | } else {
316 | win = h(Preview, {
317 | class: 'vuep-preview',
318 | props: {
319 | value: this.preview,
320 | styles: this.styles,
321 | keepData: this.keepData,
322 | iframe: this.iframe
323 | },
324 | on: {
325 | error: this.handleError
326 | }
327 | });
328 | }
329 |
330 | return h('div', { class: 'vuep' }, [
331 | h(Editor, {
332 | class: 'vuep-editor',
333 | props: {
334 | value: this.content,
335 | options: this.options
336 | },
337 | on: {
338 | change: [this.executeCode, function (val) { return this$1.$emit('input', val); }]
339 | }
340 | }),
341 | win
342 | ])
343 | },
344 |
345 | watch: {
346 | value: {
347 | immediate: true,
348 | handler: function handler (val) {
349 | val && this.executeCode(val);
350 | }
351 | }
352 | },
353 |
354 | created: function created () {
355 | /* istanbul ignore next */
356 | if (this.$isServer) { return }
357 | var content = this.template;
358 |
359 | if (/^[\.#]/.test(this.template)) {
360 | var html = document.querySelector(this.template);
361 | if (!html) { throw Error(((this.template) + " is not found")) }
362 |
363 | /* istanbul ignore next */
364 | content = html.innerHTML;
365 | }
366 |
367 | if (content) {
368 | this.executeCode(content);
369 | this.$emit('input', content);
370 | }
371 | },
372 |
373 | methods: {
374 | handleError: function handleError (err) {
375 | /* istanbul ignore next */
376 | this.error = err;
377 | },
378 |
379 | executeCode: function executeCode (code) {
380 | this.error = '';
381 | var result = parser(code);
382 |
383 | /* istanbul ignore next */
384 | if (result.error) {
385 | this.error = result.error.message;
386 | return
387 | }
388 |
389 | var compiledCode = compiler(result, this.scope);
390 |
391 | /* istanbul ignore next */
392 | if (compiledCode.error) {
393 | this.error = compiledCode.error.message;
394 | return
395 | }
396 |
397 | this.content = result.content;
398 | this.preview = compiledCode.result;
399 | if (compiledCode.styles) { this.styles = compiledCode.styles; }
400 | }
401 | }
402 | };
403 |
404 | Vuep$2.config = function (opts) {
405 | Vuep$2.props.options.default = function () { return opts; };
406 | };
407 |
408 | function install (Vue, opts) {
409 | Vuep$2.config(opts);
410 | Vue.component(Vuep$2.name, Vuep$2);
411 | }
412 |
413 | Vuep$2.install = install;
414 |
415 | if (typeof Vue !== 'undefined') {
416 | Vue.use(install); // eslint-disable-line
417 | }
418 |
419 | if (typeof require !== 'undefined') {
420 | require('codemirror/addon/mode/overlay');
421 | require('codemirror/addon/mode/simple');
422 | require('codemirror/mode/css/css');
423 | require('codemirror/mode/htmlmixed/htmlmixed');
424 | require('codemirror/mode/javascript/javascript');
425 | require('codemirror/mode/vue/vue');
426 | require('codemirror/mode/xml/xml');
427 | require('codemirror/mode/jsx/jsx');
428 | }
429 |
430 | module.exports = Vuep$2;
431 |
--------------------------------------------------------------------------------
/dist/vuep.css:
--------------------------------------------------------------------------------
1 | /* BASICS */
2 | .CodeMirror {
3 | /* Set height, width, borders, and global font properties here */
4 | font-family: monospace;
5 | height: 300px;
6 | color: black;
7 | }
8 | /* PADDING */
9 | .CodeMirror-lines {
10 | padding: 4px 0;
11 | /* Vertical padding around content */
12 | }
13 | .CodeMirror pre {
14 | padding: 0 4px;
15 | /* Horizontal padding of content */
16 | }
17 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
18 | background-color: white;
19 | /* The little square between H and V scrollbars */
20 | }
21 | /* GUTTER */
22 | .CodeMirror-gutters {
23 | border-right: 1px solid #ddd;
24 | background-color: #f7f7f7;
25 | white-space: nowrap;
26 | }
27 | .CodeMirror-linenumbers {}
28 | .CodeMirror-linenumber {
29 | padding: 0 3px 0 5px;
30 | min-width: 20px;
31 | text-align: right;
32 | color: #999;
33 | white-space: nowrap;
34 | }
35 | .CodeMirror-guttermarker {
36 | color: black;
37 | }
38 | .CodeMirror-guttermarker-subtle {
39 | color: #999;
40 | }
41 | /* CURSOR */
42 | .CodeMirror-cursor {
43 | border-left: 1px solid black;
44 | border-right: none;
45 | width: 0;
46 | }
47 | /* Shown when moving in bi-directional text */
48 | .CodeMirror div.CodeMirror-secondarycursor {
49 | border-left: 1px solid silver;
50 | }
51 | .cm-fat-cursor .CodeMirror-cursor {
52 | width: auto;
53 | border: 0 !important;
54 | background: #7e7;
55 | }
56 | .cm-fat-cursor div.CodeMirror-cursors {
57 | z-index: 1;
58 | }
59 | .cm-animate-fat-cursor {
60 | width: auto;
61 | border: 0;
62 | -webkit-animation: blink 1.06s steps(1) infinite;
63 | animation: blink 1.06s steps(1) infinite;
64 | background-color: #7e7;
65 | }
66 | @-webkit-keyframes blink {
67 | 0% {}
68 | 50% {
69 | background-color: transparent;
70 | }
71 | 100% {}
72 | }
73 | @keyframes blink {
74 | 0% {}
75 | 50% {
76 | background-color: transparent;
77 | }
78 | 100% {}
79 | }
80 | /* Can style cursor different in overwrite (non-insert) mode */
81 | .CodeMirror-overwrite .CodeMirror-cursor {}
82 | .cm-tab {
83 | display: inline-block;
84 | text-decoration: inherit;
85 | }
86 | .CodeMirror-rulers {
87 | position: absolute;
88 | left: 0;
89 | right: 0;
90 | top: -50px;
91 | bottom: -20px;
92 | overflow: hidden;
93 | }
94 | .CodeMirror-ruler {
95 | border-left: 1px solid #ccc;
96 | top: 0;
97 | bottom: 0;
98 | position: absolute;
99 | }
100 | /* DEFAULT THEME */
101 | .cm-s-default .cm-header {
102 | color: blue;
103 | }
104 | .cm-s-default .cm-quote {
105 | color: #090;
106 | }
107 | .cm-negative {
108 | color: #d44;
109 | }
110 | .cm-positive {
111 | color: #292;
112 | }
113 | .cm-header, .cm-strong {
114 | font-weight: 700;
115 | }
116 | .cm-em {
117 | font-style: italic;
118 | }
119 | .cm-link {
120 | text-decoration: underline;
121 | }
122 | .cm-strikethrough {
123 | text-decoration: line-through;
124 | }
125 | .cm-s-default .cm-keyword {
126 | color: #708;
127 | }
128 | .cm-s-default .cm-atom {
129 | color: #219;
130 | }
131 | .cm-s-default .cm-number {
132 | color: #164;
133 | }
134 | .cm-s-default .cm-def {
135 | color: #00f;
136 | }
137 | .cm-s-default .cm-variable, .cm-s-default .cm-punctuation, .cm-s-default .cm-property, .cm-s-default .cm-operator {}
138 | .cm-s-default .cm-variable-2 {
139 | color: #05a;
140 | }
141 | .cm-s-default .cm-variable-3 {
142 | color: #085;
143 | }
144 | .cm-s-default .cm-comment {
145 | color: #a50;
146 | }
147 | .cm-s-default .cm-string {
148 | color: #a11;
149 | }
150 | .cm-s-default .cm-string-2 {
151 | color: #f50;
152 | }
153 | .cm-s-default .cm-meta {
154 | color: #555;
155 | }
156 | .cm-s-default .cm-qualifier {
157 | color: #555;
158 | }
159 | .cm-s-default .cm-builtin {
160 | color: #30a;
161 | }
162 | .cm-s-default .cm-bracket {
163 | color: #997;
164 | }
165 | .cm-s-default .cm-tag {
166 | color: #170;
167 | }
168 | .cm-s-default .cm-attribute {
169 | color: #00c;
170 | }
171 | .cm-s-default .cm-hr {
172 | color: #999;
173 | }
174 | .cm-s-default .cm-link {
175 | color: #00c;
176 | }
177 | .cm-s-default .cm-error {
178 | color: #f00;
179 | }
180 | .cm-invalidchar {
181 | color: #f00;
182 | }
183 | .CodeMirror-composing {
184 | border-bottom: 2px solid;
185 | }
186 | /* Default styles for common addons */
187 | div.CodeMirror span.CodeMirror-matchingbracket {
188 | color: #0f0;
189 | }
190 | div.CodeMirror span.CodeMirror-nonmatchingbracket {
191 | color: #f22;
192 | }
193 | .CodeMirror-matchingtag {
194 | background: rgba(255, 150, 0, .3);
195 | }
196 | .CodeMirror-activeline-background {
197 | background: #e8f2ff;
198 | }
199 | /* STOP */
200 | /* The rest of this file contains styles related to the mechanics of
201 | the editor. You probably shouldn't touch them. */
202 | .CodeMirror {
203 | position: relative;
204 | overflow: hidden;
205 | background: white;
206 | }
207 | .CodeMirror-scroll {
208 | overflow: scroll !important;
209 | /* Things will break if this is overridden */
210 | /* 30px is the magic margin used to hide the element's real scrollbars */
211 | /* See overflow: hidden in .CodeMirror */
212 | margin-bottom: -30px;
213 | margin-right: -30px;
214 | padding-bottom: 30px;
215 | height: 100%;
216 | outline: none;
217 | /* Prevent dragging from highlighting the element */
218 | position: relative;
219 | }
220 | .CodeMirror-sizer {
221 | position: relative;
222 | border-right: 30px solid transparent;
223 | }
224 | /* The fake, visible scrollbars. Used to force redraw during scrolling
225 | before actual scrolling happens, thus preventing shaking and
226 | flickering artifacts. */
227 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
228 | position: absolute;
229 | z-index: 6;
230 | display: none;
231 | }
232 | .CodeMirror-vscrollbar {
233 | right: 0;
234 | top: 0;
235 | overflow-x: hidden;
236 | overflow-y: scroll;
237 | }
238 | .CodeMirror-hscrollbar {
239 | bottom: 0;
240 | left: 0;
241 | overflow-y: hidden;
242 | overflow-x: scroll;
243 | }
244 | .CodeMirror-scrollbar-filler {
245 | right: 0;
246 | bottom: 0;
247 | }
248 | .CodeMirror-gutter-filler {
249 | left: 0;
250 | bottom: 0;
251 | }
252 | .CodeMirror-gutters {
253 | position: absolute;
254 | left: 0;
255 | top: 0;
256 | min-height: 100%;
257 | z-index: 3;
258 | }
259 | .CodeMirror-gutter {
260 | white-space: normal;
261 | height: 100%;
262 | display: inline-block;
263 | vertical-align: top;
264 | margin-bottom: -30px;
265 | }
266 | .CodeMirror-gutter-wrapper {
267 | position: absolute;
268 | z-index: 4;
269 | background: none !important;
270 | border: none !important;
271 | }
272 | .CodeMirror-gutter-background {
273 | position: absolute;
274 | top: 0;
275 | bottom: 0;
276 | z-index: 4;
277 | }
278 | .CodeMirror-gutter-elt {
279 | position: absolute;
280 | cursor: default;
281 | z-index: 4;
282 | }
283 | .CodeMirror-gutter-wrapper {
284 | -webkit-user-select: none;
285 | -moz-user-select: none;
286 | -ms-user-select: none;
287 | user-select: none;
288 | }
289 | .CodeMirror-lines {
290 | cursor: text;
291 | min-height: 1px;
292 | /* prevents collapsing before first draw */
293 | }
294 | .CodeMirror pre {
295 | /* Reset some styles that the rest of the page might have set */
296 | border-radius: 0;
297 | border-width: 0;
298 | background: transparent;
299 | font-family: inherit;
300 | font-size: inherit;
301 | margin: 0;
302 | white-space: pre;
303 | word-wrap: normal;
304 | line-height: inherit;
305 | color: inherit;
306 | z-index: 2;
307 | position: relative;
308 | overflow: visible;
309 | -webkit-tap-highlight-color: transparent;
310 | -webkit-font-variant-ligatures: contextual;
311 | font-variant-ligatures: contextual;
312 | }
313 | .CodeMirror-wrap pre {
314 | word-wrap: break-word;
315 | white-space: pre-wrap;
316 | word-break: normal;
317 | }
318 | .CodeMirror-linebackground {
319 | position: absolute;
320 | left: 0;
321 | right: 0;
322 | top: 0;
323 | bottom: 0;
324 | z-index: 0;
325 | }
326 | .CodeMirror-linewidget {
327 | position: relative;
328 | z-index: 2;
329 | overflow: auto;
330 | }
331 | .CodeMirror-widget {}
332 | .CodeMirror-code {
333 | outline: none;
334 | }
335 | /* Force content-box sizing for the elements where we expect it */
336 | .CodeMirror-scroll, .CodeMirror-sizer, .CodeMirror-gutter, .CodeMirror-gutters, .CodeMirror-linenumber {
337 | box-sizing: content-box;
338 | }
339 | .CodeMirror-measure {
340 | position: absolute;
341 | width: 100%;
342 | height: 0;
343 | overflow: hidden;
344 | visibility: hidden;
345 | }
346 | .CodeMirror-cursor {
347 | position: absolute;
348 | pointer-events: none;
349 | }
350 | .CodeMirror-measure pre {
351 | position: static;
352 | }
353 | div.CodeMirror-cursors {
354 | visibility: hidden;
355 | position: relative;
356 | z-index: 3;
357 | }
358 | div.CodeMirror-dragcursors {
359 | visibility: visible;
360 | }
361 | .CodeMirror-focused div.CodeMirror-cursors {
362 | visibility: visible;
363 | }
364 | .CodeMirror-selected {
365 | background: #d9d9d9;
366 | }
367 | .CodeMirror-focused .CodeMirror-selected {
368 | background: #d7d4f0;
369 | }
370 | .CodeMirror-crosshair {
371 | cursor: crosshair;
372 | }
373 | .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection {
374 | background: #d7d4f0;
375 | }
376 | .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection {
377 | background: #d7d4f0;
378 | }
379 | .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection {
380 | background: #d7d4f0;
381 | }
382 | .cm-searching {
383 | background: #ffa;
384 | background: rgba(255, 255, 0, .4);
385 | }
386 | /* Used to force a border model for a node */
387 | .cm-force-border {
388 | padding-right: .1px;
389 | }
390 | @media print {
391 | /* Hide the cursor when printing */
392 | .CodeMirror div.CodeMirror-cursors {
393 | visibility: hidden;
394 | }
395 | }
396 | /* See issue #2901 */
397 | .cm-tab-wrap-hack:after {
398 | content: '';
399 | }
400 | /* Help users use markselection to safely style text background */
401 | span.CodeMirror-selectedtext {
402 | background: none;
403 | }
404 | /*
405 |
406 | Name: material
407 | Author: Michael Kaminsky (http://github.com/mkaminsky11)
408 |
409 | Original material color scheme by Mattia Astorino (https://github.com/equinusocio/material-theme)
410 |
411 | */
412 | .cm-s-material.CodeMirror {
413 | background-color: #263238;
414 | color: rgba(233, 237, 237, 1);
415 | }
416 | .cm-s-material .CodeMirror-gutters {
417 | background: #263238;
418 | color: rgb(83,127,126);
419 | border: none;
420 | }
421 | .cm-s-material .CodeMirror-guttermarker, .cm-s-material .CodeMirror-guttermarker-subtle, .cm-s-material .CodeMirror-linenumber {
422 | color: rgb(83,127,126);
423 | }
424 | .cm-s-material .CodeMirror-cursor {
425 | border-left: 1px solid #f8f8f0;
426 | }
427 | .cm-s-material div.CodeMirror-selected {
428 | background: rgba(255, 255, 255, 0.15);
429 | }
430 | .cm-s-material.CodeMirror-focused div.CodeMirror-selected {
431 | background: rgba(255, 255, 255, 0.10);
432 | }
433 | .cm-s-material .CodeMirror-line::-moz-selection, .cm-s-material .CodeMirror-line > span::-moz-selection, .cm-s-material .CodeMirror-line > span > span::-moz-selection {
434 | background: rgba(255, 255, 255, 0.10);
435 | }
436 | .cm-s-material .CodeMirror-line::selection, .cm-s-material .CodeMirror-line > span::selection, .cm-s-material .CodeMirror-line > span > span::selection {
437 | background: rgba(255, 255, 255, 0.10);
438 | }
439 | .cm-s-material .CodeMirror-line::-moz-selection, .cm-s-material .CodeMirror-line > span::-moz-selection, .cm-s-material .CodeMirror-line > span > span::-moz-selection {
440 | background: rgba(255, 255, 255, 0.10);
441 | }
442 | .cm-s-material .CodeMirror-activeline-background {
443 | background: rgba(0, 0, 0, 0);
444 | }
445 | .cm-s-material .cm-keyword {
446 | color: rgba(199, 146, 234, 1);
447 | }
448 | .cm-s-material .cm-operator {
449 | color: rgba(233, 237, 237, 1);
450 | }
451 | .cm-s-material .cm-variable-2 {
452 | color: #80CBC4;
453 | }
454 | .cm-s-material .cm-variable-3 {
455 | color: #82B1FF;
456 | }
457 | .cm-s-material .cm-builtin {
458 | color: #DECB6B;
459 | }
460 | .cm-s-material .cm-atom {
461 | color: #F77669;
462 | }
463 | .cm-s-material .cm-number {
464 | color: #F77669;
465 | }
466 | .cm-s-material .cm-def {
467 | color: rgba(233, 237, 237, 1);
468 | }
469 | .cm-s-material .cm-string {
470 | color: #C3E88D;
471 | }
472 | .cm-s-material .cm-string-2 {
473 | color: #80CBC4;
474 | }
475 | .cm-s-material .cm-comment {
476 | color: #546E7A;
477 | }
478 | .cm-s-material .cm-variable {
479 | color: #82B1FF;
480 | }
481 | .cm-s-material .cm-tag {
482 | color: #80CBC4;
483 | }
484 | .cm-s-material .cm-meta {
485 | color: #80CBC4;
486 | }
487 | .cm-s-material .cm-attribute {
488 | color: #FFCB6B;
489 | }
490 | .cm-s-material .cm-property {
491 | color: #80CBAE;
492 | }
493 | .cm-s-material .cm-qualifier {
494 | color: #DECB6B;
495 | }
496 | .cm-s-material .cm-variable-3 {
497 | color: #DECB6B;
498 | }
499 | .cm-s-material .cm-tag {
500 | color: rgba(255, 83, 112, 1);
501 | }
502 | .cm-s-material .cm-error {
503 | color: rgba(255, 255, 255, 1.0);
504 | background-color: #EC5F67;
505 | }
506 | .cm-s-material .CodeMirror-matchingbracket {
507 | text-decoration: underline;
508 | color: white !important;
509 | }
510 |
511 | .vuep {
512 | display: -webkit-box;
513 | display: -ms-flexbox;
514 | display: flex;
515 | font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
516 | height: 400px;
517 | }
518 |
519 | .vuep ::-webkit-scrollbar-track {
520 | border-radius: 10px;
521 | background-color: #F5F5F5;
522 | }
523 |
524 | .vuep ::-webkit-scrollbar {
525 | width: 8px;
526 | height: 8px;
527 | background-color: #F5F5F5;
528 | }
529 |
530 | .vuep ::-webkit-scrollbar-thumb {
531 | border-radius: 8px;
532 | background-color: #bbb;
533 | -webkit-transition: all 0.5s;
534 | transition: all 0.5s;
535 | }
536 |
537 | .vuep ::-webkit-scrollbar-thumb:hover {
538 | border-radius: 8px;
539 | background-color: #777;
540 | }
541 |
542 | .vuep-editor, .vuep-preview, .vuep-error {
543 | border-radius: 2px;
544 | height: inherit;
545 | margin-right: 10px;
546 | overflow: auto;
547 | width: 50%;
548 | }
549 |
550 | .vuep-editor .CodeMirror, .vuep-preview .CodeMirror, .vuep-error .CodeMirror {
551 | height: inherit;
552 | }
553 |
554 | .vuep-editor:last-child, .vuep-preview:last-child, .vuep-error:last-child {
555 | margin-right: 0;
556 | }
557 |
558 | .vuep-editor {
559 | line-height: 1.2em;
560 | }
561 |
562 | .vuep-error {
563 | color: #f66;
564 | }
565 |
566 | .vuep-preview, .vuep-error {
567 | border: 1px solid #eee;
568 | box-sizing: border-box;
569 | padding: 25px 35px;
570 | }
571 |
572 | @media (max-width: 600px) {
573 | .vuep {
574 | display: block;
575 | height: auto;
576 | }
577 |
578 | .vuep-editor, .vuep-preview, .vuep-error {
579 | margin: 0 0 15px 0;
580 | height: 400px;
581 | width: 100%;
582 | }
583 | }
584 |
--------------------------------------------------------------------------------