├── .babelrc
├── .eslintignore
├── .eslintrc
├── .gitignore
├── LICENSE.md
├── README.md
├── demo.gif
├── demo.html
├── dist
├── pell.css
├── pell.js
├── pell.min.css
└── pell.min.js
├── examples
├── react.md
└── vue.md
├── gulpfile.js
├── images
├── browserstack.png
└── logo.png
├── package-lock.json
├── package.json
└── src
├── pell.js
└── pell.scss
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["es2015", {"modules": false}],
4 | "stage-0"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "jared"
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Jared Reich
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 | #### [v2 working branch](https://github.com/jaredreich/pell/tree/v2) and [v2 project board](https://github.com/jaredreich/pell/projects/1)
2 |
3 | ---
4 |
5 |
6 |
7 | [](https://www.npmjs.com/package/pell)
8 | [](https://cdnjs.com/libraries/pell)
9 |
10 | > pell is the simplest and smallest WYSIWYG text editor for web, with no dependencies
11 |
12 | 
13 |
14 | ## Comparisons
15 |
16 | | library | size (min+gzip) | size (min) | jquery | bootstrap | react | link |
17 | |---------------|-----------------|------------|--------|-----------|-------|------|
18 | | pell | 1.38kB | 3.54kB | | | | https://github.com/jaredreich/pell |
19 | | squire | 16kB | 49kB | | | | https://github.com/neilj/Squire |
20 | | medium-editor | 27kB | 105kB | | | | https://github.com/yabwe/medium-editor |
21 | | quill | 43kB | 205kB | | | | https://github.com/quilljs/quill |
22 | | trix | 47kB | 204kB | | | | https://github.com/basecamp/trix |
23 | | ckeditor | 163kB | 551kB | | | | https://ckeditor.com |
24 | | trumbowyg | 8kB | 23kB | x | | | https://github.com/Alex-D/Trumbowyg |
25 | | summernote | 26kB | 93kB | x | x | | https://github.com/summernote/summernote |
26 | | draft | 46kB | 147kB | | | x | https://github.com/facebook/draft-js |
27 | | froala | 52kB | 186kB | x | | | https://github.com/froala/wysiwyg-editor |
28 | | tinymce | 157kB | 491kB | x | | | https://github.com/tinymce/tinymce |
29 |
30 | ## Features
31 |
32 | * Pure JavaScript, no dependencies, written in ES6
33 | * Easily customizable with the sass file (pell.scss) or overwrite the CSS
34 |
35 | Included actions:
36 | - Bold
37 | - Italic
38 | - Underline
39 | - Strike-through
40 | - Heading 1
41 | - Heading 2
42 | - Paragraph
43 | - Quote
44 | - Ordered List
45 | - Unordered List
46 | - Code
47 | - Horizontal Rule
48 | - Link
49 | - Image
50 |
51 | Other available actions (listed at https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand):
52 | - Justify Center
53 | - Justify Full
54 | - Justify Left
55 | - Justify Right
56 | - Subscript
57 | - Superscript
58 | - Font Name
59 | - Font Size
60 | - Indent
61 | - Outdent
62 | - Clear Formatting
63 | - Undo
64 | - Redo
65 |
66 | Or create any custom action!
67 |
68 | ## Browser Support
69 |
70 | * IE 9+ (theoretically, but good luck)
71 | * Chrome 5+
72 | * Firefox 4+
73 | * Safari 5+
74 | * Opera 11.6+
75 |
76 | ## Installation
77 |
78 | #### npm:
79 |
80 | ```bash
81 | npm install --save pell
82 | ```
83 |
84 | #### HTML:
85 |
86 | ```html
87 |
'); 92 | } 93 | }, 94 | quote: { 95 | icon: '“ ”', 96 | title: 'Quote', 97 | result: function result() { 98 | return exec(formatBlock, '
'); 99 | } 100 | }, 101 | olist: { 102 | icon: '#', 103 | title: 'Ordered List', 104 | result: function result() { 105 | return exec('insertOrderedList'); 106 | } 107 | }, 108 | ulist: { 109 | icon: '•', 110 | title: 'Unordered List', 111 | result: function result() { 112 | return exec('insertUnorderedList'); 113 | } 114 | }, 115 | code: { 116 | icon: '</>', 117 | title: 'Code', 118 | result: function result() { 119 | return exec(formatBlock, ''); 120 | } 121 | }, 122 | line: { 123 | icon: '―', 124 | title: 'Horizontal Line', 125 | result: function result() { 126 | return exec('insertHorizontalRule'); 127 | } 128 | }, 129 | link: { 130 | icon: '🔗', 131 | title: 'Link', 132 | result: function result() { 133 | var url = window.prompt('Enter the link URL'); 134 | if (url) exec('createLink', url); 135 | } 136 | }, 137 | image: { 138 | icon: '📷', 139 | title: 'Image', 140 | result: function result() { 141 | var url = window.prompt('Enter the image URL'); 142 | if (url) exec('insertImage', url); 143 | } 144 | } 145 | }; 146 | 147 | var defaultClasses = { 148 | actionbar: 'pell-actionbar', 149 | button: 'pell-button', 150 | content: 'pell-content', 151 | selected: 'pell-button-selected' 152 | }; 153 | 154 | var init = function init(settings) { 155 | var actions = settings.actions ? settings.actions.map(function (action) { 156 | if (typeof action === 'string') return defaultActions[action];else if (defaultActions[action.name]) return _extends({}, defaultActions[action.name], action); 157 | return action; 158 | }) : Object.keys(defaultActions).map(function (action) { 159 | return defaultActions[action]; 160 | }); 161 | 162 | var classes = _extends({}, defaultClasses, settings.classes); 163 | 164 | var defaultParagraphSeparator = settings[defaultParagraphSeparatorString] || 'div'; 165 | 166 | var actionbar = createElement('div'); 167 | actionbar.className = classes.actionbar; 168 | appendChild(settings.element, actionbar); 169 | 170 | var content = settings.element.content = createElement('div'); 171 | content.contentEditable = true; 172 | content.className = classes.content; 173 | content.oninput = function (_ref) { 174 | var firstChild = _ref.target.firstChild; 175 | 176 | if (firstChild && firstChild.nodeType === 3) exec(formatBlock, '<' + defaultParagraphSeparator + '>');else if (content.innerHTML === '
') content.innerHTML = ''; 177 | settings.onChange(content.innerHTML); 178 | }; 179 | content.onkeydown = function (event) { 180 | if (event.key === 'Enter' && queryCommandValue(formatBlock) === 'blockquote') { 181 | setTimeout(function () { 182 | return exec(formatBlock, '<' + defaultParagraphSeparator + '>'); 183 | }, 0); 184 | } 185 | }; 186 | appendChild(settings.element, content); 187 | 188 | actions.forEach(function (action) { 189 | var button = createElement('button'); 190 | button.className = classes.button; 191 | button.innerHTML = action.icon; 192 | button.title = action.title; 193 | button.setAttribute('type', 'button'); 194 | button.onclick = function () { 195 | return action.result() && content.focus(); 196 | }; 197 | 198 | if (action.state) { 199 | var handler = function handler() { 200 | return button.classList[action.state() ? 'add' : 'remove'](classes.selected); 201 | }; 202 | addEventListener(content, 'keyup', handler); 203 | addEventListener(content, 'mouseup', handler); 204 | addEventListener(button, 'click', handler); 205 | } 206 | 207 | appendChild(actionbar, button); 208 | }); 209 | 210 | if (settings.styleWithCSS) exec('styleWithCSS'); 211 | exec(defaultParagraphSeparatorString, defaultParagraphSeparator); 212 | 213 | return settings.element; 214 | }; 215 | 216 | var pell = { exec: exec, init: init }; 217 | 218 | exports.exec = exec; 219 | exports.init = init; 220 | exports['default'] = pell; 221 | 222 | Object.defineProperty(exports, '__esModule', { value: true }); 223 | 224 | }))); 225 | -------------------------------------------------------------------------------- /dist/pell.min.css: -------------------------------------------------------------------------------- 1 | .pell{border:1px solid hsla(0,0%,4%,.1)}.pell,.pell-content{box-sizing:border-box}.pell-content{height:300px;outline:0;overflow-y:auto;padding:10px}.pell-actionbar{background-color:#fff;border-bottom:1px solid hsla(0,0%,4%,.1)}.pell-button{background-color:transparent;border:none;cursor:pointer;height:30px;outline:0;width:30px;vertical-align:bottom}.pell-button-selected{background-color:#f0f0f0} -------------------------------------------------------------------------------- /dist/pell.min.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(t.pell={})}(this,function(t){"use strict";var e=Object.assign||function(t){for(var e=1;eB",title:"Bold",state:function(){return n("bold")},result:function(){return f("bold")}},italic:{icon:"I",title:"Italic",state:function(){return n("italic")},result:function(){return f("italic")}},underline:{icon:"U",title:"Underline",state:function(){return n("underline")},result:function(){return f("underline")}},strikethrough:{icon:" S",title:"Strike-through",state:function(){return n("strikeThrough")},result:function(){return f("strikeThrough")}},heading1:{icon:"H1",title:"Heading 1",result:function(){return f(l,"")}},heading2:{icon:"H2",title:"Heading 2",result:function(){return f(l,"
")}},paragraph:{icon:"¶",title:"Paragraph",result:function(){return f(l,"
")}},quote:{icon:"“ ”",title:"Quote",result:function(){return f(l,"
")}},olist:{icon:"#",title:"Ordered List",result:function(){return f("insertOrderedList")}},ulist:{icon:"•",title:"Unordered List",result:function(){return f("insertUnorderedList")}},code:{icon:"</>",title:"Code",result:function(){return f(l,"")}},line:{icon:"―",title:"Horizontal Line",result:function(){return f("insertHorizontalRule")}},link:{icon:"🔗",title:"Link",result:function(){var t=window.prompt("Enter the link URL");t&&f("createLink",t)}},image:{icon:"📷",title:"Image",result:function(){var t=window.prompt("Enter the image URL");t&&f("insertImage",t)}}},m={actionbar:"pell-actionbar",button:"pell-button",content:"pell-content",selected:"pell-button-selected"},r=function(n){var t=n.actions?n.actions.map(function(t){return"string"==typeof t?p[t]:p[t.name]?e({},p[t.name],t):t}):Object.keys(p).map(function(t){return p[t]}),r=e({},m,n.classes),i=n[c]||"div",o=d("div");o.className=r.actionbar,s(n.element,o);var u=n.element.content=d("div");return u.contentEditable=!0,u.className=r.content,u.oninput=function(t){var e=t.target.firstChild;e&&3===e.nodeType?f(l,"<"+i+">"):"
"===u.innerHTML&&(u.innerHTML=""),n.onChange(u.innerHTML)},u.onkeydown=function(t){var e;"Enter"===t.key&&"blockquote"===(e=l,document.queryCommandValue(e))&&setTimeout(function(){return f(l,"<"+i+">")},0)},s(n.element,u),t.forEach(function(t){var e=d("button");if(e.className=r.button,e.innerHTML=t.icon,e.title=t.title,e.setAttribute("type","button"),e.onclick=function(){return t.result()&&u.focus()},t.state){var n=function(){return e.classList[t.state()?"add":"remove"](r.selected)};a(u,"keyup",n),a(u,"mouseup",n),a(e,"click",n)}s(o,e)}),n.styleWithCSS&&f("styleWithCSS"),f(c,i),n.element},i={exec:f,init:r};t.exec=f,t.init=r,t.default=i,Object.defineProperty(t,"__esModule",{value:!0})}); 2 | -------------------------------------------------------------------------------- /examples/react.md: -------------------------------------------------------------------------------- 1 | ```js 2 | // App.js 3 | 4 | import React, { Component } from 'react'; 5 | import { init } from 'pell'; 6 | 7 | import 'pell/dist/pell.css' 8 | 9 | class App extends Component { 10 | editor = null 11 | 12 | constructor (props) { 13 | super(props) 14 | this.state = { html: null } 15 | } 16 | 17 | componentDidMount () { 18 | this.editor = init({ 19 | element: document.getElementById('editor'), 20 | onChange: html => this.setState({ html }), 21 | actions: ['bold', 'underline', 'italic'], 22 | }) 23 | } 24 | 25 | render() { 26 | return ( 27 |28 |33 | ); 34 | } 35 | } 36 | 37 | export default App; 38 | ``` 39 | -------------------------------------------------------------------------------- /examples/vue.md: -------------------------------------------------------------------------------- 1 | ```vue 2 | 3 |Editor:
29 | 30 |HTML Output:
31 |{this.state.html}32 |4 |9 | 10 | 11 | 56 | 57 | 69 | ``` 70 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const babel = require('rollup-plugin-babel') 2 | const cssnano = require('gulp-cssnano') 3 | const del = require('del') 4 | const gulp = require('gulp') 5 | const rename = require('gulp-rename') 6 | const Rollup = require('rollup') 7 | const rollup = require('gulp-rollup') 8 | const run = require('run-sequence') 9 | const sass = require('gulp-sass') 10 | const size = require('gulp-size') 11 | const uglify = require('rollup-plugin-uglify') 12 | 13 | gulp.task('clean', () => del(['./dist'])) 14 | 15 | const rollupConfig = minimize => ({ 16 | rollup: Rollup, 17 | entry: './src/pell.js', 18 | moduleName: 'pell', 19 | format: 'umd', 20 | exports: 'named', 21 | plugins: [babel({ exclude: 'node_modules/**' })].concat( 22 | minimize 23 | ? [ 24 | uglify({ 25 | compress: { warnings: false }, 26 | mangle: true, 27 | sourceMap: false 28 | }) 29 | ] 30 | : [] 31 | ) 32 | }) 33 | 34 | gulp.task('script', () => { 35 | gulp.src('./src/*.js') 36 | .pipe(rollup(rollupConfig(false))) 37 | .pipe(size({ showFiles: true })) 38 | .pipe(gulp.dest('./dist')) 39 | 40 | gulp.src('./src/*.js') 41 | .pipe(rollup(rollupConfig(true))) 42 | .pipe(rename('pell.min.js')) 43 | .pipe(size({ showFiles: true })) 44 | .pipe(size({ gzip: true, showFiles: true })) 45 | .pipe(gulp.dest('./dist')) 46 | }) 47 | 48 | gulp.task('style', () => { 49 | gulp.src(['./src/pell.scss']) 50 | .pipe(sass().on('error', sass.logError)) 51 | .pipe(gulp.dest('./dist')) 52 | .pipe(cssnano()) 53 | .pipe(rename('pell.min.css')) 54 | .pipe(gulp.dest('./dist')) 55 | }) 56 | 57 | gulp.task('default', ['clean'], () => { 58 | run('script', 'style') 59 | gulp.watch('./src/pell.scss', ['style']) 60 | gulp.watch('./src/pell.js', ['script']) 61 | }) 62 | -------------------------------------------------------------------------------- /images/browserstack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaredreich/pell/d5556baa2e0bfc1411621ee4d780752200b367fd/images/browserstack.png -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaredreich/pell/d5556baa2e0bfc1411621ee4d780752200b367fd/images/logo.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pell", 3 | "description": "pell - the simplest and smallest WYSIWYG text editor for web, with no dependencies", 4 | "author": "Jared Reich", 5 | "version": "1.0.6", 6 | "main": "./dist/pell.min.js", 7 | "scripts": { 8 | "dev": "gulp", 9 | "build": "gulp clean && gulp script && gulp style", 10 | "lint": "./node_modules/.bin/eslint .js ./" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/jaredreich/pell.git" 15 | }, 16 | "keywords": [ 17 | "text editor", 18 | "editor", 19 | "rich text", 20 | "wysiwyg", 21 | "contenteditable" 22 | ], 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/jaredreich/pell/issues" 26 | }, 27 | "homepage": "https://github.com/jaredreich/pell", 28 | "devDependencies": { 29 | "babel-core": "6.23.1", 30 | "babel-preset-es2015": "6.22.0", 31 | "babel-preset-stage-0": "6.22.0", 32 | "del": "2.2.2", 33 | "eslint-config-jared": "1.2.0", 34 | "gulp": "3.9.1", 35 | "gulp-cssnano": "2.1.2", 36 | "gulp-rename": "1.2.2", 37 | "gulp-rollup": "2.14.0", 38 | "gulp-sass": "3.1.0", 39 | "gulp-size": "2.1.0", 40 | "rollup": "0.45.1", 41 | "rollup-plugin-babel": "2.7.1", 42 | "rollup-plugin-uglify": "2.0.1", 43 | "run-sequence": "1.2.2" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/pell.js: -------------------------------------------------------------------------------- 1 | const defaultParagraphSeparatorString = 'defaultParagraphSeparator' 2 | const formatBlock = 'formatBlock' 3 | const addEventListener = (parent, type, listener) => parent.addEventListener(type, listener) 4 | const appendChild = (parent, child) => parent.appendChild(child) 5 | const createElement = tag => document.createElement(tag) 6 | const queryCommandState = command => document.queryCommandState(command) 7 | const queryCommandValue = command => document.queryCommandValue(command) 8 | 9 | export const exec = (command, value = null) => document.execCommand(command, false, value) 10 | 11 | const defaultActions = { 12 | bold: { 13 | icon: 'B', 14 | title: 'Bold', 15 | state: () => queryCommandState('bold'), 16 | result: () => exec('bold') 17 | }, 18 | italic: { 19 | icon: 'I', 20 | title: 'Italic', 21 | state: () => queryCommandState('italic'), 22 | result: () => exec('italic') 23 | }, 24 | underline: { 25 | icon: 'U', 26 | title: 'Underline', 27 | state: () => queryCommandState('underline'), 28 | result: () => exec('underline') 29 | }, 30 | strikethrough: { 31 | icon: 'Editor:
5 | 6 |HTML Output:
7 | 8 |S', 32 | title: 'Strike-through', 33 | state: () => queryCommandState('strikeThrough'), 34 | result: () => exec('strikeThrough') 35 | }, 36 | heading1: { 37 | icon: 'H1', 38 | title: 'Heading 1', 39 | result: () => exec(formatBlock, '') 40 | }, 41 | heading2: { 42 | icon: 'H2', 43 | title: 'Heading 2', 44 | result: () => exec(formatBlock, '
') 45 | }, 46 | paragraph: { 47 | icon: '¶', 48 | title: 'Paragraph', 49 | result: () => exec(formatBlock, '
') 50 | }, 51 | quote: { 52 | icon: '“ ”', 53 | title: 'Quote', 54 | result: () => exec(formatBlock, '
') 55 | }, 56 | olist: { 57 | icon: '#', 58 | title: 'Ordered List', 59 | result: () => exec('insertOrderedList') 60 | }, 61 | ulist: { 62 | icon: '•', 63 | title: 'Unordered List', 64 | result: () => exec('insertUnorderedList') 65 | }, 66 | code: { 67 | icon: '</>', 68 | title: 'Code', 69 | result: () => exec(formatBlock, '') 70 | }, 71 | line: { 72 | icon: '―', 73 | title: 'Horizontal Line', 74 | result: () => exec('insertHorizontalRule') 75 | }, 76 | link: { 77 | icon: '🔗', 78 | title: 'Link', 79 | result: () => { 80 | const url = window.prompt('Enter the link URL') 81 | if (url) exec('createLink', url) 82 | } 83 | }, 84 | image: { 85 | icon: '📷', 86 | title: 'Image', 87 | result: () => { 88 | const url = window.prompt('Enter the image URL') 89 | if (url) exec('insertImage', url) 90 | } 91 | } 92 | } 93 | 94 | const defaultClasses = { 95 | actionbar: 'pell-actionbar', 96 | button: 'pell-button', 97 | content: 'pell-content', 98 | selected: 'pell-button-selected' 99 | } 100 | 101 | export const init = settings => { 102 | const actions = settings.actions 103 | ? ( 104 | settings.actions.map(action => { 105 | if (typeof action === 'string') return defaultActions[action] 106 | else if (defaultActions[action.name]) return { ...defaultActions[action.name], ...action } 107 | return action 108 | }) 109 | ) 110 | : Object.keys(defaultActions).map(action => defaultActions[action]) 111 | 112 | const classes = { ...defaultClasses, ...settings.classes } 113 | 114 | const defaultParagraphSeparator = settings[defaultParagraphSeparatorString] || 'div' 115 | 116 | const actionbar = createElement('div') 117 | actionbar.className = classes.actionbar 118 | appendChild(settings.element, actionbar) 119 | 120 | const content = settings.element.content = createElement('div') 121 | content.contentEditable = true 122 | content.className = classes.content 123 | content.oninput = ({ target: { firstChild } }) => { 124 | if (firstChild && firstChild.nodeType === 3) exec(formatBlock, `<${defaultParagraphSeparator}>`) 125 | else if (content.innerHTML === '
') content.innerHTML = '' 126 | settings.onChange(content.innerHTML) 127 | } 128 | content.onkeydown = event => { 129 | if (event.key === 'Enter' && queryCommandValue(formatBlock) === 'blockquote') { 130 | setTimeout(() => exec(formatBlock, `<${defaultParagraphSeparator}>`), 0) 131 | } 132 | } 133 | appendChild(settings.element, content) 134 | 135 | actions.forEach(action => { 136 | const button = createElement('button') 137 | button.className = classes.button 138 | button.innerHTML = action.icon 139 | button.title = action.title 140 | button.setAttribute('type', 'button') 141 | button.onclick = () => action.result() && content.focus() 142 | 143 | if (action.state) { 144 | const handler = () => button.classList[action.state() ? 'add' : 'remove'](classes.selected) 145 | addEventListener(content, 'keyup', handler) 146 | addEventListener(content, 'mouseup', handler) 147 | addEventListener(button, 'click', handler) 148 | } 149 | 150 | appendChild(actionbar, button) 151 | }) 152 | 153 | if (settings.styleWithCSS) exec('styleWithCSS') 154 | exec(defaultParagraphSeparatorString, defaultParagraphSeparator) 155 | 156 | return settings.element 157 | } 158 | 159 | export default { exec, init } 160 | -------------------------------------------------------------------------------- /src/pell.scss: -------------------------------------------------------------------------------- 1 | $pell-actionbar-color: #FFF !default; 2 | $pell-border-color: rgba(10, 10, 10, 0.1) !default; 3 | $pell-border-style: solid !default; 4 | $pell-border-width: 1px !default; 5 | $pell-button-height: 30px !default; 6 | $pell-button-selected-color: #F0F0F0 !default; 7 | $pell-button-width: 30px !default; 8 | $pell-content-height: 300px !default; 9 | $pell-content-padding: 10px !default; 10 | 11 | .pell { 12 | border: $pell-border-width $pell-border-style $pell-border-color; 13 | box-sizing: border-box; 14 | } 15 | 16 | .pell-content { 17 | box-sizing: border-box; 18 | height: $pell-content-height; 19 | outline: 0; 20 | overflow-y: auto; 21 | padding: $pell-content-padding; 22 | } 23 | 24 | .pell-actionbar { 25 | background-color: $pell-actionbar-color; 26 | border-bottom: $pell-border-width $pell-border-style $pell-border-color; 27 | } 28 | 29 | .pell-button { 30 | background-color: transparent; 31 | border: none; 32 | cursor: pointer; 33 | height: $pell-button-height; 34 | outline: 0; 35 | width: $pell-button-width; 36 | vertical-align: bottom; 37 | } 38 | 39 | .pell-button-selected { 40 | background-color: $pell-button-selected-color; 41 | } 42 | --------------------------------------------------------------------------------