Van 6 lat temu
rodzic
commit
8034b09bca

+ 23 - 0
package-lock.json

@@ -2921,6 +2921,29 @@
       "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==",
       "dev": true
     },
+    "file-loader": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-3.0.1.tgz",
+      "integrity": "sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw==",
+      "dev": true,
+      "requires": {
+        "loader-utils": "^1.0.2",
+        "schema-utils": "^1.0.0"
+      },
+      "dependencies": {
+        "schema-utils": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
+          "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
+          "dev": true,
+          "requires": {
+            "ajv": "^6.1.0",
+            "ajv-errors": "^1.0.0",
+            "ajv-keywords": "^3.1.0"
+          }
+        }
+      }
+    },
     "fill-range": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",

+ 1 - 0
package.json

@@ -20,6 +20,7 @@
     "babel-loader": "^8.0.5",
     "clean-webpack-plugin": "^1.0.1",
     "css-loader": "^2.1.0",
+    "file-loader": "^3.0.1",
     "html-loader": "^0.5.5",
     "http-server": "^0.11.1",
     "mini-css-extract-plugin": "^0.5.0",

BIN
src/assets/images/c.png


BIN
src/assets/images/d.png


BIN
src/assets/images/e50a.png


BIN
src/assets/images/f.png


BIN
src/assets/images/g.png


BIN
src/assets/images/i.png


BIN
src/assets/images/j.png


BIN
src/assets/images/k.png


BIN
src/assets/images/octocat.png


BIN
src/assets/images/r.png


BIN
src/assets/images/trollface.png


BIN
src/assets/images/u.png


+ 17 - 6
src/index.ts

@@ -4,9 +4,11 @@ import {OptionsClass} from "./ts/util/OptionsClass";
 import {Ui} from "./ts/ui/Ui";
 import {Editor} from "./ts/editor/index";
 import {Hotkey} from "./ts/hotkey/index";
+import {Markdown} from "./ts/markdown/index";
 
 class Vditor {
     readonly version: string;
+    vditor: any
 
     constructor(id: string, options?: Options) {
         this.version = VDITOR_VERSION;
@@ -14,15 +16,24 @@ class Vditor {
         const getOptions = new OptionsClass(options)
         const mergedOptions = getOptions.merge()
 
-        const editor = new Editor()
-        const editorElement: HTMLTextAreaElement = editor.genElement()
+        this.vditor = {
+            id,
+            options: mergedOptions,
+            timeId: -1
+        }
 
-        const toolbar = new Toolbar(mergedOptions, editorElement)
-        const toolbarElements = toolbar.genElement()
+        const editor = new Editor(this.vditor)
+        this.vditor.editor = editor
 
-        new Hotkey(toolbarElements, editorElement, mergedOptions)
+        const toolbar = new Toolbar(this.vditor)
+        this.vditor.toolbar = toolbar
 
-        new Ui(id, toolbarElements, editorElement)
+        const markdown = new Markdown(this.vditor)
+        this.vditor.markdown = markdown
+
+        new Hotkey(this.vditor)
+
+        new Ui(this.vditor)
     }
 }
 

+ 41 - 34
src/ts/editor/index.ts

@@ -3,18 +3,13 @@ import {commandable} from '../util/commandable'
 class Editor {
     element: HTMLTextAreaElement
 
-    constructor() {
+    constructor(vditor: Vditor) {
         this.element = document.createElement('textarea')
     }
-
-    genElement(): HTMLTextAreaElement {
-        return this.element
-    }
 }
 
-const insertTextAtCaret = (textarea: HTMLTextAreaElement, prefix: string, suffix: string, replace?: string) => {
-    if (typeof textarea.selectionStart === 'number' &&
-        typeof textarea.selectionEnd === 'number') {
+const insertText = (textarea: HTMLTextAreaElement, prefix: string, suffix: string, replace?: boolean) => {
+    if (typeof textarea.selectionStart === 'number' && typeof textarea.selectionEnd === 'number') {
         const startPos = textarea.selectionStart
         const endPos = textarea.selectionEnd
         const tmpStr = textarea.value
@@ -49,40 +44,52 @@ const insertTextAtCaret = (textarea: HTMLTextAreaElement, prefix: string, suffix
                     }
                 }
             }
-            return
-        }
-        if (startPos === endPos) {
-            // no selection
-            document.execCommand('insertText', false, prefix + suffix)
-            textarea.selectionStart = textarea.selectionEnd = textarea.selectionStart - suffix.length
         } else {
-            if (replace) {
+            if (startPos === endPos) {
+                // no selection
                 document.execCommand('insertText', false, prefix + suffix)
+                textarea.selectionStart = textarea.selectionEnd = textarea.selectionStart - suffix.length
             } else {
-                if (tmpStr.substring(startPos - prefix.length, startPos) === prefix &&
-                    tmpStr.substring(endPos, endPos + suffix.length) === suffix) {
-                    // broke circle, avoid repeat
-                    document.execCommand('delete', false)
-                    for (let i = 0, iMax = prefix.length; i < iMax; i++) {
+                if (replace) {
+                    document.execCommand('insertText', false, prefix + suffix)
+                } else {
+                    if (tmpStr.substring(startPos - prefix.length, startPos) === prefix &&
+                        tmpStr.substring(endPos, endPos + suffix.length) === suffix) {
+                        // broke circle, avoid repeat
                         document.execCommand('delete', false)
+                        for (let i = 0, iMax = prefix.length; i < iMax; i++) {
+                            document.execCommand('delete', false)
+                        }
+                        for (let j = 0, jMax = suffix.length; j < jMax; j++) {
+                            document.execCommand('forwardDelete', false)
+                        }
+                        document.execCommand('insertText', false,
+                            tmpStr.substring(startPos, endPos))
+                        textarea.selectionStart = startPos - prefix.length
+                        textarea.selectionEnd = endPos - prefix.length
+                    } else {
+                        // insert
+                        document.execCommand('insertText', false,
+                            prefix + tmpStr.substring(startPos, endPos) + suffix)
+                        textarea.selectionStart = startPos + prefix.length
+                        textarea.selectionEnd = endPos + prefix.length
                     }
-                    for (let j = 0, jMax = suffix.length; j < jMax; j++) {
-                        document.execCommand('forwardDelete', false)
-                    }
-                    document.execCommand('insertText', false,
-                        tmpStr.substring(startPos, endPos))
-                    textarea.selectionStart = startPos - prefix.length
-                    textarea.selectionEnd = endPos - prefix.length
-                } else {
-                    // insert
-                    document.execCommand('insertText', false,
-                        prefix + tmpStr.substring(startPos, endPos) + suffix)
-                    textarea.selectionStart = startPos + prefix.length
-                    textarea.selectionEnd = endPos + prefix.length
                 }
             }
         }
     }
 }
 
-export {Editor, insertTextAtCaret}
+// const debounceChange = (timerId: number, change: ChangeFunction, $editor) => {
+//     if (timerId !== undefined) {
+//         clearTimeout(timerId)
+//     }
+//     return setTimeout(() => {
+//         change && change($editor.find('textarea').val(),
+//             $editor.find('.b3log-editor__icon--current').length === 0
+//                 ? undefined
+//                 : $editor.find('.b3log-editor__markdown'))
+//     }, 500)
+// }
+
+export {Editor, insertText}

+ 892 - 0
src/ts/emoji/emoji.js

@@ -0,0 +1,892 @@
+/**
+ * @fileoverview all emoji.
+ *
+ * @author <a href="http://vanessa.b3log.org">Liyuan Li</a>
+ * @version 0.1.0.0, Jan 28, 2019
+ */
+
+import cPng from '../../assets/images/c.png'
+import dPng from '../../assets/images/d.png'
+import e50aPng from '../../assets/images/e50a.png'
+import fPng from '../../assets/images/f.png'
+import gPng from '../../assets/images/g.png'
+import iPng from '../../assets/images/i.png'
+import jPng from '../../assets/images/j.png'
+import kPng from '../../assets/images/k.png'
+import octocatPng from '../../assets/images/octocat.png'
+import rPng from '../../assets/images/r.png'
+import trollfacePng from '../../assets/images/trollface.png'
+import uPng from '../../assets/images/u.png'
+
+export default {
+  '+1': '👍',
+  '-1': '👎',
+  '100': '💯',
+  '1234': '🔢',
+  '8ball': '🎱',
+  'a': '🅰',
+  'ab': '🆎',
+  'abc': '🔤',
+  'abcd': '🔡',
+  'accept': '🉑',
+  'aerial_tramway': '🚡',
+  'airplane': '✈',
+  'alarm_clock': '⏰',
+  'alien': '👽',
+  'ambulance': '🚑',
+  'anchor': '⚓',
+  'angel': '👼',
+  'anger': '💢',
+  'angry': '😠',
+  'anguished': '😧',
+  'ant': '🐜',
+  'apple': '🍎',
+  'aquarius': '♒',
+  'aries': '♈',
+  'arrows_clockwise': '🔃',
+  'arrows_counterclockwise': '🔄',
+  'arrow_backward': '◀',
+  'arrow_double_down': '⏬',
+  'arrow_double_up': '⏫',
+  'arrow_down': '⬇',
+  'arrow_down_small': '🔽',
+  'arrow_forward': '▶',
+  'arrow_heading_down': '⤵',
+  'arrow_heading_up': '⤴',
+  'arrow_left': '⬅',
+  'arrow_lower_left': '↙',
+  'arrow_lower_right': '↘',
+  'arrow_right': '➡',
+  'arrow_right_hook': '↪',
+  'arrow_up': '⬆',
+  'arrow_upper_left': '↖',
+  'arrow_upper_right': '↗',
+  'arrow_up_down': '↕',
+  'arrow_up_small': '🔼',
+  'art': '🎨',
+  'articulated_lorry': '🚛',
+  'astonished': '😲',
+  'atm': '🏧',
+  'b': '🅱',
+  'baby': '👶',
+  'baby_bottle': '🍼',
+  'baby_chick': '🐤',
+  'baby_symbol': '🚼',
+  'back': '🔙',
+  'baggage_claim': '🛄',
+  'balloon': '🎈',
+  'ballot_box_with_check': '☑',
+  'bamboo': '🎍',
+  'banana': '🍌',
+  'bangbang': '‼',
+  'bank': '🏦',
+  'barber': '💈',
+  'bar_chart': '📊',
+  'baseball': '⚾',
+  'basketball': '🏀',
+  'bath': '🛀',
+  'bathtub': '🛁',
+  'battery': '🔋',
+  'bear': '🐻',
+  'bee': '🐝',
+  'beer': '🍺',
+  'beers': '🍻',
+  'beetle': '🐞',
+  'beginner': '🔰',
+  'bell': '🔔',
+  'bento': '🍱',
+  'bicyclist': '🚴',
+  'bike': '🚲',
+  'bikini': '👙',
+  'bird': '🐦',
+  'birthday': '🎂',
+  'black_circle': '⚫',
+  'black_joker': '🃏',
+  'black_large_square': '⬛',
+  'black_medium_small_square': '◾',
+  'black_medium_square': '◼',
+  'black_nib': '✒',
+  'black_small_square': '▪',
+  'black_square_button': '🔲',
+  'blossom': '🌼',
+  'blowfish': '🐡',
+  'blue_book': '📘',
+  'blue_car': '🚙',
+  'blue_heart': '💙',
+  'blush': '😊',
+  'boar': '🐗',
+  'boat': '⛵',
+  'bomb': '💣',
+  'book': '📖',
+  'bookmark': '🔖',
+  'bookmark_tabs': '📑',
+  'books': '📚',
+  'boom': '💥',
+  'boot': '👢',
+  'bouquet': '💐',
+  'bow': '🙇',
+  'bowling': '🎳',
+  'boy': '👦',
+  'bread': '🍞',
+  'bride_with_veil': '👰',
+  'bridge_at_night': '🌉',
+  'briefcase': '💼',
+  'broken_heart': '💔',
+  'bug': '🐛',
+  'bulb': '💡',
+  'bullettrain_front': '🚅',
+  'bullettrain_side': '🚄',
+  'bus': '🚌',
+  'busstop': '🚏',
+  'busts_in_silhouette': '👥',
+  'bust_in_silhouette': '👤',
+  'c': cPng,
+  'cactus': '🌵',
+  'cake': '🍰',
+  'calendar': '📆',
+  'calling': '📲',
+  'camel': '🐫',
+  'camera': '📷',
+  'cancer': '🦀',
+  'candy': '🍬',
+  'capital_abcd': '🔠',
+  'capricorn': '♑',
+  'car': '🚗',
+  'card_index': '📇',
+  'carousel_horse': '🎠',
+  'cat': '🐱',
+  'cat2': '🐈',
+  'cd': '🇨🇩',
+  'chart': '💹',
+  'chart_with_downwards_trend': '📉',
+  'chart_with_upwards_trend': '📈',
+  'checkered_flag': '🏁',
+  'cherries': '🍒',
+  'cherry_blossom': '🌸',
+  'chestnut': '🌰',
+  'chicken': '🐔',
+  'children_crossing': '🚸',
+  'chocolate_bar': '🍫',
+  'christmas_tree': '🎄',
+  'church': '⛪',
+  'cinema': '🎦',
+  'circus_tent': '🎪',
+  'city_sunrise': '🌇',
+  'city_sunset': '🌆',
+  'cl': '🇨🇱',
+  'clap': '👏',
+  'clapper': '🎬',
+  'clipboard': '📋',
+  'clock1': '🕐',
+  'clock10': '🕙',
+  'clock1030': '🕥',
+  'clock11': '🕚',
+  'clock1130': '🕦',
+  'clock12': '🕛',
+  'clock1230': '🕧',
+  'clock130': '🕜',
+  'clock2': '🕑',
+  'clock230': '🕝',
+  'clock3': '🕒',
+  'clock330': '🕞',
+  'clock4': '🕓',
+  'clock430': '🕟',
+  'clock5': '🕔',
+  'clock530': '🕠',
+  'clock6': '🕕',
+  'clock630': '🕡',
+  'clock7': '🕖',
+  'clock730': '🕢',
+  'clock8': '🕗',
+  'clock830': '🕣',
+  'clock9': '🕘',
+  'clock930': '🕤',
+  'closed_book': '📕',
+  'closed_lock_with_key': '🔐',
+  'closed_umbrella': '🌂',
+  'cloud': '☁',
+  'clubs': '♣',
+  'cn': '🇨🇳',
+  'cocktail': '🍸',
+  'coffee': '☕',
+  'cold_sweat': '😰',
+  'collision': '💥',
+  'computer': '💻',
+  'confetti_ball': '🎊',
+  'confounded': '😖',
+  'confused': '😕',
+  'congratulations': '㊗',
+  'construction': '🚧',
+  'construction_worker': '👷',
+  'convenience_store': '🏪',
+  'cookie': '🍪',
+  'cool': '🆒',
+  'cop': '👮',
+  'copyright': '©',
+  'corn': '🌽',
+  'couple': '👫',
+  'couplekiss': '💏',
+  'couple_with_heart': '💑',
+  'cow': '🐮',
+  'cow2': '🐄',
+  'credit_card': '💳',
+  'crescent_moon': '🌙',
+  'crocodile': '🐊',
+  'crossed_flags': '🎌',
+  'crown': '👑',
+  'cry': '😢',
+  'crying_cat_face': '😿',
+  'crystal_ball': '🔮',
+  'cupid': '💘',
+  'curly_loop': '➰',
+  'currency_exchange': '💱',
+  'curry': '🍛',
+  'custard': '🍮',
+  'customs': '🛃',
+  'cyclone': '🌀',
+  'd': dPng,
+  'dancer': '💃',
+  'dancers': '👯',
+  'dango': '🍡',
+  'dart': '🎯',
+  'dash': '💨',
+  'date': '📅',
+  'de': '🇩🇪',
+  'deciduous_tree': '🌳',
+  'department_store': '🏬',
+  'diamonds': '♦',
+  'diamond_shape_with_a_dot_inside': '💠',
+  'disappointed': '😞',
+  'disappointed_relieved': '😥',
+  'dizzy': '💫',
+  'dizzy_face': '😵',
+  'dog': '🐶',
+  'dog2': '🐕',
+  'dollar': '💵',
+  'dolls': '🎎',
+  'dolphin': '🐬',
+  'door': '🚪',
+  'doughnut': '🍩',
+  'do_not_litter': '🚯',
+  'dragon': '🐉',
+  'dragon_face': '🐲',
+  'dress': '👗',
+  'dromedary_camel': '🐪',
+  'droplet': '💧',
+  'dvd': '📀',
+  'e-mail': '📧',
+  'e50a': e50aPng,
+  'ear': '👂',
+  'earth_africa': '🌍',
+  'earth_americas': '🌎',
+  'earth_asia': '🌏',
+  'ear_of_rice': '🌾',
+  'egg': '🥚',
+  'eggplant': '🍆',
+  'eight': '8⃣',
+  'eight_pointed_black_star': '✴',
+  'eight_spoked_asterisk': '✳',
+  'electric_plug': '🔌',
+  'elephant': '🐘',
+  'email': '✉',
+  'end': '🔚',
+  'envelope': '✉',
+  'es': '🇪🇸',
+  'euro': '💶',
+  'european_castle': '🏰',
+  'european_post_office': '🏤',
+  'evergreen_tree': '🌲',
+  'exclamation': '❗',
+  'expressionless': '😑',
+  'eyeglasses': '👓',
+  'eyes': '👀',
+  'f': fPng,
+  'facepunch': '👊',
+  'factory': '🏭',
+  'fallen_leaf': '🍂',
+  'family': '👪',
+  'fast_forward': '⏩',
+  'fax': '📠',
+  'fearful': '😨',
+  'feet': '🐾',
+  'ferris_wheel': '🎡',
+  'file_folder': '📁',
+  'fire': '🔥',
+  'fireworks': '🎆',
+  'fire_engine': '🚒',
+  'first_quarter_moon': '🌓',
+  'first_quarter_moon_with_face': '🌛',
+  'fish': '🐟',
+  'fishing_pole_and_fish': '🎣',
+  'fish_cake': '🍥',
+  'fist': '✊',
+  'five': '5⃣',
+  'flags': '🎏',
+  'flashlight': '🔦',
+  'floppy_disk': '💾',
+  'flower_playing_cards': '🎴',
+  'flushed': '😳',
+  'foggy': '🌁',
+  'football': '🏈',
+  'fork_and_knife': '🍴',
+  'fountain': '⛲',
+  'four': '4⃣',
+  'four_leaf_clover': '🍀',
+  'fr': '🇫🇷',
+  'free': '🆓',
+  'fried_shrimp': '🍤',
+  'fries': '🍟',
+  'frog': '🐸',
+  'frowning': '😦',
+  'fuelpump': '⛽',
+  'full_moon': '🌕',
+  'full_moon_with_face': '🌝',
+  'g': gPng,
+  'game_die': '🎲',
+  'gb': '🇬🇧',
+  'gem': '💎',
+  'gemini': '♊',
+  'ghost': '👻',
+  'gift': '🎁',
+  'gift_heart': '💝',
+  'girl': '👧',
+  'globe_with_meridians': '🌐',
+  'goat': '🐐',
+  'golf': '⛳',
+  'grapes': '🍇',
+  'green_apple': '🍏',
+  'green_book': '📗',
+  'green_heart': '💚',
+  'grey_exclamation': '❕',
+  'grey_question': '❔',
+  'grimacing': '😬',
+  'grin': '😁',
+  'grinning': '😀',
+  'guardsman': '💂',
+  'guitar': '🎸',
+  'gun': '🔫',
+  'haircut': '💇',
+  'hamburger': '🍔',
+  'hammer': '🔨',
+  'hamster': '🐹',
+  'hand': '✋',
+  'handbag': '👜',
+  'hankey': '💩',
+  'hash': '#⃣',
+  'hatched_chick': '🐥',
+  'hatching_chick': '🐣',
+  'headphones': '🎧',
+  'heart': '❤️',
+  'heartbeat': '💓',
+  'heartpulse': '💗',
+  'hearts': '♥️',
+  'heart_decoration': '💟',
+  'heart_eyes': '😍',
+  'heart_eyes_cat': '😻',
+  'hear_no_evil': '🙉',
+  'heavy_check_mark': '✔',
+  'heavy_division_sign': '➗',
+  'heavy_dollar_sign': '💲',
+  'heavy_exclamation_mark': '❗',
+  'heavy_minus_sign': '➖',
+  'heavy_multiplication_x': '✖',
+  'heavy_plus_sign': '➕',
+  'helicopter': '🚁',
+  'herb': '🌿',
+  'hibiscus': '🌺',
+  'high_brightness': '🔆',
+  'high_heel': '👠',
+  'hocho': '🔪',
+  'honeybee': '🐝',
+  'honey_pot': '🍯',
+  'horse': '🐴',
+  'horse_racing': '🏇',
+  'hospital': '🏥',
+  'hotel': '🏨',
+  'hotsprings': '♨',
+  'hourglass': '⌛',
+  'hourglass_flowing_sand': '⏳',
+  'house': '🏠',
+  'house_with_garden': '🏡',
+  'hushed': '😯',
+  'i': iPng,
+  'icecream': '🍦',
+  'ice_cream': '🍨',
+  'id': '🇮🇩',
+  'ideograph_advantage': '🉐',
+  'imp': '👿',
+  'inbox_tray': '📥',
+  'incoming_envelope': '📨',
+  'information_desk_person': '💁',
+  'information_source': 'ℹ',
+  'innocent': '😇',
+  'interrobang': '⁉',
+  'iphone': '📱',
+  'it': '🇮🇹',
+  'izakaya_lantern': '🏮',
+  'j': jPng,
+  'jack_o_lantern': '🎃',
+  'japan': '🗾',
+  'japanese_castle': '🏯',
+  'japanese_goblin': '👺',
+  'japanese_ogre': '👹',
+  'jeans': '👖',
+  'joy': '😂',
+  'joy_cat': '😹',
+  'jp': '🇯🇵',
+  'k': kPng,
+  'key': '🔑',
+  'keycap_ten': '🔟',
+  'kimono': '👘',
+  'kiss': '💋',
+  'kissing': '😗',
+  'kissing_cat': '😽',
+  'kissing_closed_eyes': '😚',
+  'kissing_heart': '😘',
+  'kissing_smiling_eyes': '😙',
+  'koala': '🐨',
+  'koko': '🈁',
+  'kr': '🇰🇷',
+  'large_blue_circle': '🔵',
+  'large_blue_diamond': '🔷',
+  'large_orange_diamond': '🔶',
+  'last_quarter_moon': '🌗',
+  'last_quarter_moon_with_face': '🌜',
+  'laughing': '😆',
+  'leaves': '🍃',
+  'ledger': '📒',
+  'leftwards_arrow_with_hook': '↩',
+  'left_luggage': '🛅',
+  'left_right_arrow': '↔',
+  'lemon': '🍋',
+  'leo': '♌',
+  'leopard': '🐆',
+  'libra': '♎',
+  'light_rail': '🚈',
+  'link': '🔗',
+  'lips': '👄',
+  'lipstick': '💄',
+  'lock': '🔒',
+  'lock_with_ink_pen': '🔏',
+  'lollipop': '🍭',
+  'loop': '➿',
+  'loudspeaker': '📢',
+  'love_hotel': '🏩',
+  'love_letter': '💌',
+  'low_brightness': '🔅',
+  'm': 'Ⓜ',
+  'mag': '🔍',
+  'mag_right': '🔎',
+  'mahjong': '🀄',
+  'mailbox': '📫',
+  'mailbox_closed': '📪',
+  'mailbox_with_mail': '📬',
+  'mailbox_with_no_mail': '📭',
+  'man': '👨',
+  'mans_shoe': '👞',
+  'man_with_gua_pi_mao': '👲',
+  'man_with_turban': '👳',
+  'maple_leaf': '🍁',
+  'mask': '😷',
+  'massage': '💆',
+  'meat_on_bone': '🍖',
+  'mega': '📣',
+  'melon': '🍈',
+  'memo': '📝',
+  'mens': '🚹',
+  'metro': '🚇',
+  'microphone': '🎤',
+  'microscope': '🔬',
+  'milky_way': '🌌',
+  'minibus': '🚐',
+  'minidisc': '💽',
+  'mobile_phone_off': '📴',
+  'moneybag': '💰',
+  'money_with_wings': '💸',
+  'monkey': '🐒',
+  'monkey_face': '🐵',
+  'monorail': '🚝',
+  'mortar_board': '🎓',
+  'mountain_bicyclist': '🚵',
+  'mountain_cableway': '🚠',
+  'mountain_railway': '🚞',
+  'mount_fuji': '🗻',
+  'mouse': '🐭',
+  'mouse2': '🐁',
+  'movie_camera': '🎥',
+  'moyai': '🗿',
+  'muscle': '💪',
+  'mushroom': '🍄',
+  'musical_keyboard': '🎹',
+  'musical_note': '🎵',
+  'musical_score': '🎼',
+  'mute': '🔇',
+  'nail_care': '💅',
+  'name_badge': '📛',
+  'necktie': '👔',
+  'negative_squared_cross_mark': '❎',
+  'neutral_face': '😐',
+  'new': '🆕',
+  'newspaper': '📰',
+  'new_moon': '🌑',
+  'new_moon_with_face': '🌚',
+  'ng': '🇳🇬',
+  'nine': '9⃣',
+  'non-potable_water': '🚱',
+  'nose': '👃',
+  'notebook': '📓',
+  'notebook_with_decorative_cover': '📔',
+  'notes': '🎶',
+  'no_bell': '🔕',
+  'no_bicycles': '🚳',
+  'no_entry': '⛔',
+  'no_entry_sign': '🚫',
+  'no_good': '🙅',
+  'no_mobile_phones': '📵',
+  'no_mouth': '😶',
+  'no_pedestrians': '🚷',
+  'no_smoking': '🚭',
+  'nut_and_bolt': '🔩',
+  'o': '⭕',
+  'o2': '🅾',
+  'ocean': '🌊',
+  'octocat': octocatPng,
+  'octopus': '🐙',
+  'oden': '🍢',
+  'office': '🏢',
+  'ok': '🆗',
+  'ok_hand': '👌',
+  'ok_woman': '🙆',
+  'older_man': '👴',
+  'older_woman': '👵',
+  'on': '🔛',
+  'oncoming_automobile': '🚘',
+  'oncoming_bus': '🚍',
+  'oncoming_police_car': '🚔',
+  'oncoming_taxi': '🚖',
+  'one': '1⃣',
+  'open_file_folder': '📂',
+  'open_hands': '👐',
+  'open_mouth': '😮',
+  'ophiuchus': '⛎',
+  'orange_book': '📙',
+  'outbox_tray': '📤',
+  'ox': '🐂',
+  'package': '📦',
+  'pager': '📟',
+  'page_facing_up': '📄',
+  'page_with_curl': '📃',
+  'palm_tree': '🌴',
+  'panda_face': '🐼',
+  'paperclip': '📎',
+  'parking': '🅿',
+  'partly_sunny': '⛅',
+  'part_alternation_mark': '〽',
+  'passport_control': '🛂',
+  'paw_prints': '🐾',
+  'peach': '🍑',
+  'pear': '🍐',
+  'pencil': '📝',
+  'pencil2': '✏',
+  'penguin': '🐧',
+  'pensive': '😔',
+  'performing_arts': '🎭',
+  'persevere': '😣',
+  'person_frowning': '🙍',
+  'person_with_blond_hair': '👱',
+  'person_with_pouting_face': '🙎',
+  'phone': '☎',
+  'pig': '🐷',
+  'pig2': '🐖',
+  'pig_nose': '🐽',
+  'pill': '💊',
+  'pineapple': '🍍',
+  'pisces': '♓',
+  'pizza': '🍕',
+  'point_down': '👇',
+  'point_left': '👈',
+  'point_right': '👉',
+  'point_up': '☝',
+  'point_up_2': '👆',
+  'police_car': '🚓',
+  'poodle': '🐩',
+  'poop': '💩',
+  'postal_horn': '📯',
+  'postbox': '📮',
+  'potable_water': '🚰',
+  'pouch': '👝',
+  'poultry_leg': '🍗',
+  'pound': '💷',
+  'pouting_cat': '😾',
+  'pray': '🙏',
+  'princess': '👸',
+  'punch': '👊',
+  'purple_heart': '💜',
+  'purse': '👛',
+  'pushpin': '📌',
+  'put_litter_in_its_place': '🚮',
+  'question': '❓',
+  'r': rPng,
+  'rabbit': '🐰',
+  'rabbit2': '🐇',
+  'racehorse': '🐎',
+  'radio': '📻',
+  'radio_button': '🔘',
+  'rage': '😡',
+  'railway_car': '🚃',
+  'rainbow': '🌈',
+  'raised_hand': '✋',
+  'raised_hands': '🙌',
+  'raising_hand': '🙋',
+  'ram': '🐏',
+  'ramen': '🍜',
+  'rat': '🐀',
+  'recycle': '♻',
+  'red_car': '🚗',
+  'red_circle': '🔴',
+  'registered': '®',
+  'relaxed': '☺',
+  'relieved': '😌',
+  'repeat': '🔁',
+  'repeat_one': '🔂',
+  'restroom': '🚻',
+  'revolving_hearts': '💞',
+  'rewind': '⏪',
+  'ribbon': '🎀',
+  'rice': '🍚',
+  'rice_ball': '🍙',
+  'rice_cracker': '🍘',
+  'rice_scene': '🎑',
+  'ring': '💍',
+  'rocket': '🚀',
+  'roller_coaster': '🎢',
+  'rooster': '🐓',
+  'rose': '🌹',
+  'rotating_light': '🚨',
+  'round_pushpin': '📍',
+  'rowboat': '🚣',
+  'ru': '🇷🇺',
+  'rugby_football': '🏉',
+  'running': '🏃',
+  'running_shirt_with_sash': '🎽',
+  'sa': '🇸🇦',
+  'sagittarius': '♐',
+  'sailboat': '⛵',
+  'sake': '🍶',
+  'sandal': '👡',
+  'santa': '🎅',
+  'satellite': '🛰',
+  'satisfied': '😆',
+  'saxophone': '🎷',
+  'school': '🏫',
+  'school_satchel': '🎒',
+  'scissors': '✂',
+  'scorpius': '♏',
+  'scream': '😱',
+  'scream_cat': '🙀',
+  'scroll': '📜',
+  'seat': '💺',
+  'secret': '㊙',
+  'seedling': '🌱',
+  'see_no_evil': '🙈',
+  'seven': '7⃣',
+  'shaved_ice': '🍧',
+  'sheep': '🐑',
+  'shell': '🐚',
+  'ship': '🚢',
+  'shirt': '👕',
+  'shoe': '👞',
+  'shower': '🚿',
+  'signal_strength': '📶',
+  'six': '6⃣',
+  'six_pointed_star': '🔯',
+  'ski': '🎿',
+  'skull': '💀',
+  'sleeping': '😴',
+  'sleepy': '😪',
+  'slot_machine': '🎰',
+  'small_blue_diamond': '🔹',
+  'small_orange_diamond': '🔸',
+  'small_red_triangle': '🔺',
+  'small_red_triangle_down': '🔻',
+  'smile': '😄',
+  'smiley': '😃',
+  'smiley_cat': '😺',
+  'smile_cat': '😸',
+  'smiling_imp': '😈',
+  'smirk': '😏',
+  'smirk_cat': '😼',
+  'smoking': '🚬',
+  'snail': '🐌',
+  'snake': '🐍',
+  'snowboarder': '🏂',
+  'snowflake': '❄',
+  'snowman': '⛄',
+  'sob': '😭',
+  'soccer': '⚽',
+  'soon': '🔜',
+  'sos': '🆘',
+  'sound': '🔉',
+  'space_invader': '👾',
+  'spades': '♠',
+  'spaghetti': '🍝',
+  'sparkle': '❇',
+  'sparkler': '🎇',
+  'sparkles': '✨',
+  'sparkling_heart': '💖',
+  'speaker': '🔈',
+  'speak_no_evil': '🙊',
+  'speech_balloon': '💬',
+  'speedboat': '🚤',
+  'squirrel': '🐿',
+  'star': '⭐',
+  'star2': '🌟',
+  'stars': '🌠',
+  'station': '🚉',
+  'statue_of_liberty': '🗽',
+  'steam_locomotive': '🚂',
+  'stew': '🍲',
+  'straight_ruler': '📏',
+  'strawberry': '🍓',
+  'stuck_out_tongue': '😛',
+  'stuck_out_tongue_closed_eyes': '😝',
+  'stuck_out_tongue_winking_eye': '😜',
+  'sunflower': '🌻',
+  'sunglasses': '😎',
+  'sunny': '☀',
+  'sunrise': '🌅',
+  'sunrise_over_mountains': '🌄',
+  'sun_with_face': '🌞',
+  'surfer': '🏄',
+  'sushi': '🍣',
+  'suspension_railway': '🚟',
+  'sweat': '😓',
+  'sweat_drops': '💦',
+  'sweat_smile': '😅',
+  'sweet_potato': '🍠',
+  'swimmer': '🏊',
+  'symbols': '🔣',
+  'syringe': '💉',
+  'tada': '🎉',
+  'tanabata_tree': '🎋',
+  'tangerine': '🍊',
+  'taurus': '♉',
+  'taxi': '🚕',
+  'tea': '🍵',
+  'telephone': '☎',
+  'telephone_receiver': '📞',
+  'telescope': '🔭',
+  'tennis': '🎾',
+  'tent': '🏕',
+  'thought_balloon': '💭',
+  'three': '3⃣',
+  'thumbsdown': '👎',
+  'thumbsup': '👍',
+  'ticket': '🎫',
+  'tiger': '🐯',
+  'tiger2': '🐅',
+  'tired_face': '😫',
+  'tm': '🇹🇲',
+  'toilet': '🚽',
+  'tokyo_tower': '🗼',
+  'tomato': '🍅',
+  'tongue': '👅',
+  'top': '🔝',
+  'tophat': '🎩',
+  'tractor': '🚜',
+  'traffic_light': '🚥',
+  'train': '🚋',
+  'train2': '🚆',
+  'tram': '🚊',
+  'triangular_flag_on_post': '🚩',
+  'triangular_ruler': '📐',
+  'trident': '🔱',
+  'triumph': '😤',
+  'trolleybus': '🚎',
+  'trollface': trollfacePng,
+  'trophy': '🏆',
+  'tropical_drink': '🍹',
+  'tropical_fish': '🐠',
+  'truck': '🚚',
+  'trumpet': '🎺',
+  'tshirt': '👕',
+  'tulip': '🌷',
+  'turtle': '🐢',
+  'tv': '🇹🇻',
+  'twisted_rightwards_arrows': '🔀',
+  'two': '2⃣',
+  'two_hearts': '💕',
+  'two_men_holding_hands': '👬',
+  'two_women_holding_hands': '👭',
+  'u': uPng,
+  'u5272': '🈹',
+  'u5408': '🈴',
+  'u55b6': '🈺',
+  'u6307': '🈯',
+  'u6708': '🈷',
+  'u6709': '🈶',
+  'u6e80': '🈵',
+  'u7121': '🈚',
+  'u7533': '🈸',
+  'u7981': '🈲',
+  'u7a7a': '🈳',
+  'umbrella': '☔',
+  'unamused': '😒',
+  'underage': '🔞',
+  'unicorn_face': '🦄',
+  'unlock': '🔓',
+  'up': '🆙',
+  'us': '🇺🇸',
+  'v': '✌',
+  'vertical_traffic_light': '🚦',
+  'vhs': '📼',
+  'vibration_mode': '📳',
+  'video_camera': '📹',
+  'video_game': '🎮',
+  'violin': '🎻',
+  'virgo': '♍',
+  'volcano': '🌋',
+  'vs': '🆚',
+  'walking': '🚶',
+  'waning_crescent_moon': '🌘',
+  'waning_gibbous_moon': '🌖',
+  'warning': '⚠',
+  'watch': '⌚',
+  'watermelon': '🍉',
+  'water_buffalo': '🐃',
+  'wave': '👋',
+  'wavy_dash': '〰',
+  'waxing_crescent_moon': '🌒',
+  'waxing_gibbous_moon': '🌔',
+  'wc': '🚾',
+  'weary': '😩',
+  'wedding': '💒',
+  'whale': '🐳',
+  'whale2': '🐋',
+  'wheelchair': '♿',
+  'white_check_mark': '✅',
+  'white_circle': '⚪',
+  'white_flower': '💮',
+  'white_large_square': '⬜',
+  'white_medium_small_square': '◽',
+  'white_medium_square': '◻',
+  'white_small_square': '▫',
+  'white_square_button': '🔳',
+  'wind_chime': '🎐',
+  'wine_glass': '🍷',
+  'wink': '😉',
+  'wolf': '🐺',
+  'woman': '👩',
+  'womans_clothes': '👚',
+  'womans_hat': '👒',
+  'womens': '🚺',
+  'worried': '😟',
+  'wrench': '🔧',
+  'x': '❌',
+  'yellow_heart': '💛',
+  'yen': '💴',
+  'yum': '😋',
+  'zap': '⚡',
+  'zero': '0⃣',
+  'zzz': '💤',
+}

+ 4 - 4
src/ts/hotkey/index.ts

@@ -3,10 +3,10 @@ export class Hotkey {
     toolbarElements: any
     options: Options
 
-    constructor(toolbarElements: any, editorElement: HTMLTextAreaElement, options: Options) {
-        this.editorElement = editorElement
-        this.toolbarElements = toolbarElements
-        this.options = options
+    constructor(vditor:Vditor) {
+        this.editorElement = vditor.editor.element
+        this.toolbarElements = vditor.toolbar.elements
+        this.options = vditor.options
         this.bindHotkey()
     }
 

+ 14 - 2
src/ts/markdown/index.ts

@@ -1,8 +1,20 @@
-
 import(/* webpackChunkName: "marked" */ 'marked')
     .then(marked => {
         console.log(marked.parse('# Marked in the browser.'));
     })
     .catch(err => {
         console.log('Failed to load marked', err);
-    });
+    });
+
+export class Markdown {
+    element: HTMLElement
+
+    constructor(vditor: Vditor) {
+        this.element = document.createElement('div')
+        this.element.className = 'vditor-preview'
+    }
+
+    renderPreview(html: string) {
+        this.element.innerHTML = html
+    }
+}

+ 8 - 2
src/ts/toolbar/Bold.ts

@@ -2,7 +2,13 @@ import boldSVG from "../../assets/icons/bold.svg";
 import {MenuItemClass} from "./MenuItemClass";
 
 export class Bold extends MenuItemClass {
-    genElement(menuItem: MenuItem, lang: string, editorElement: HTMLTextAreaElement): HTMLElement {
-        return super.genElement(Object.assign({}, menuItem, {icon: menuItem.icon || boldSVG}), lang, editorElement)
+    constructor(vditor: Vditor, menuItem: MenuItem) {
+        super(vditor, menuItem)
+        this.element.children[0].innerHTML = menuItem.icon || boldSVG
+        this.bindEvent()
+    }
+
+    bindEvent() {
+        super.bindEvent()
     }
 }

+ 31 - 12
src/ts/toolbar/Emoji.ts

@@ -1,28 +1,47 @@
 import emojiSVG from "../../assets/icons/emoji.svg";
 import {MenuItemClass} from "./MenuItemClass";
-import {i18n} from "../i18n/index";
+import {insertText} from "../editor/index";
 
 export class Emoji extends MenuItemClass {
     element: HTMLElement
 
-    genElement(menuItem: MenuItem, lang: string, editorElement: HTMLTextAreaElement): HTMLElement {
-        this.element = document.createElement('div')
+    constructor(vditor: Vditor, menuItem: MenuItem) {
+        super(vditor, menuItem)
+        this.element.children[0].innerHTML = menuItem.icon || emojiSVG
 
-        this.element.className = 'vditor-tooltipped vditor-tooltipped__e'
-        this.element.setAttribute('aria-label', menuItem.tip || i18n[lang][menuItem.name])
-        this.element.innerHTML = menuItem.icon || emojiSVG
         const emojiPanelElement = document.createElement('div')
         emojiPanelElement.className = 'vditor-panel'
 
-        if (menuItem.tail) {
-            emojiPanelElement.innerHTML = `<div>${menuItem.tail}</div>`
-            this.element.appendChild(emojiPanelElement)
-        }
+        let commonEmojiHTML = ''
+        Object.keys(vditor.options.commonEmoji).forEach((key) => {
+            const emojiValue = vditor.options.commonEmoji[key]
+            if (emojiValue.indexOf('.') > -1) {
+                commonEmojiHTML += `<span data-value=":${key}: "><img data-value=":${key}: " src="${emojiValue}"/></span>`
+            } else {
+                commonEmojiHTML += `<span data-value="${emojiValue} ">${emojiValue}</span>`
+            }
+        })
+
+        const tailHTML = menuItem.tail ? `<div>${menuItem.tail}</div>` : ''
+
+        emojiPanelElement.innerHTML = `<div class="vditor-emojis">${commonEmojiHTML}</div>${tailHTML}`
+
+        this.element.appendChild(emojiPanelElement)
 
-        this.element.addEventListener('click', () => {
+        this._bindEvent(emojiPanelElement, vditor)
+    }
+
+    _bindEvent(emojiPanelElement: HTMLElement, vditor: Vditor) {
+        this.element.children[0].addEventListener('click', () => {
             emojiPanelElement.style.display = emojiPanelElement.style.display === 'block' ? 'none' : 'block'
         })
 
-        return this.element
+        emojiPanelElement.querySelectorAll('.vditor-emojis span').forEach((element) => {
+            element.addEventListener('click', (event: any) => {
+                insertText(vditor.editor.element, event.target.getAttribute('data-value'), '', true)
+                emojiPanelElement.style.display = 'none'
+
+            })
+        })
     }
 }

+ 11 - 13
src/ts/toolbar/MenuItemClass.ts

@@ -1,5 +1,5 @@
 import {i18n} from "../i18n/index";
-import {insertTextAtCaret} from "../editor/index";
+import {insertText} from "../editor/index";
 
 
 export class MenuItemClass {
@@ -7,22 +7,20 @@ export class MenuItemClass {
     menuItem: MenuItem
     editorElement: HTMLTextAreaElement
 
-    genElement(menuItem: MenuItem, lang: string, editorElement: HTMLTextAreaElement): HTMLElement {
+    constructor(vditor: Vditor, menuItem: MenuItem) {
         this.menuItem = menuItem
-        this.editorElement = editorElement
-        this.element = document.createElement('div')
-
-        this.element.className = 'vditor-tooltipped vditor-tooltipped__e'
-        this.element.setAttribute('aria-label', this.menuItem.tip || i18n[lang][this.menuItem.name])
-        this.element.innerHTML = this.menuItem.icon
+        this.editorElement = vditor.editor.element
 
-        this.bindEvent()
-        return this.element
+        this.element = document.createElement('div')
+        const iconElement = document.createElement('div')
+        iconElement.className = 'vditor-tooltipped vditor-tooltipped__e'
+        iconElement.setAttribute('aria-label', this.menuItem.tip || i18n[vditor.options.lang][this.menuItem.name])
+        this.element.appendChild(iconElement)
     }
 
-    private bindEvent() {
-        this.element.addEventListener('click', () => {
-            insertTextAtCaret(this.editorElement, this.menuItem.prefix || '', this.menuItem.suffix || '')
+    bindEvent() {
+        this.element.children[0].addEventListener('click', () => {
+            insertText(this.editorElement, this.menuItem.prefix || '', this.menuItem.suffix || '')
         })
     }
 }

+ 8 - 13
src/ts/toolbar/index.ts

@@ -2,31 +2,26 @@ import {Emoji} from './emoji'
 import {Bold} from './Bold'
 
 export class Toolbar {
-    menuElements: any
-    private options: Options
+    elements: any
 
-    constructor(options: Options, editorElement: HTMLTextAreaElement) {
-        this.options = options
-        this.menuElements = []
+    constructor(vditor: Vditor) {
+        const options = vditor.options
+        this.elements = {}
 
-        this.options.toolbar.forEach((menuItem: MenuItem) => {
+        options.toolbar.forEach((menuItem: MenuItem) => {
             let menuItemObj
             switch (menuItem.name) {
                 case 'emoji':
-                    menuItemObj = new Emoji()
+                    menuItemObj = new Emoji(vditor, menuItem)
                     break
                 case 'bold':
-                    menuItemObj = new Bold()
+                    menuItemObj = new Bold(vditor, menuItem)
                     break
                 default:
                     console.log('menu item no matched')
                     break
             }
-            this.menuElements[menuItem.name] = menuItemObj.genElement(menuItem, options.i18n, editorElement)
+            this.elements[menuItem.name] = menuItemObj.element
         })
     }
-
-    genElement() {
-        return this.menuElements
-    }
 }

+ 18 - 2
src/ts/types/custom.d.ts

@@ -3,6 +3,8 @@ declare module "*.svg" {
     export default content
 }
 
+declare module '*.png'
+
 interface Classes {
     previewContent: string
 }
@@ -28,7 +30,7 @@ interface Options {
     width?: number | string
     theme?: string
     placeholder?: string
-    i18n?: string
+    lang?: string
     draggable?: boolean
     previewShow?: boolean
     counter?: number
@@ -36,6 +38,20 @@ interface Options {
     classes?: Classes
     staticServePath?: string
     atUserCallback?: object | string
-    commonEmoji?: object
+    commonEmoji?: any
     toolbar?: Array<string | MenuItem>
+    change?: ChangeFunction
+}
+
+interface ChangeFunction {
+    (value: string, previewElement?: HTMLElement): void
 }
+
+interface Vditor {
+    id: string
+    options: Options
+    timeId: number
+    toolbar?: any
+    markdown?: any
+    editor?: any
+}

+ 5 - 5
src/ts/ui/Ui.ts

@@ -1,14 +1,14 @@
 export class Ui {
-    constructor(id: string, toolbar: any, editor: HTMLElement) {
-        const vditorElement = document.getElementById(id)
+    constructor(vditor:Vditor) {
+        const vditorElement = document.getElementById(vditor.id)
 
         const toolbarElement = document.createElement('div')
         // toolbarElement.className = 'vditor-toolbar'
-        Object.keys(toolbar).forEach((key) => {
-            toolbarElement.appendChild(toolbar[key])
+        Object.keys(vditor.toolbar.elements).forEach((key) => {
+            toolbarElement.appendChild(vditor.toolbar.elements[key])
         })
 
         vditorElement.appendChild(toolbarElement)
-        vditorElement.appendChild(editor)
+        vditorElement.appendChild(vditor.editor.element)
     }
 }

+ 8 - 6
src/ts/util/OptionsClass.ts

@@ -1,3 +1,7 @@
+
+import octocatPng from "../../assets/images/octocat.png"
+import trollfacePng from "../../assets/images/trollface.png"
+
 export class OptionsClass {
     options: Options;
     private defaultOptions: Options = {
@@ -5,7 +9,7 @@ export class OptionsClass {
         width: 'auto',
         theme: 'classic',
         placeholder: '',
-        i18n: 'zh_CN',
+        lang: 'zh_CN',
         draggable: false,
         previewShow: false,
         counter: 0,
@@ -17,15 +21,13 @@ export class OptionsClass {
         classes: {
             previewContent: ''
         },
-        staticServePath: '',
         atUserCallback: '',
         commonEmoji: {
             "+1": "👍",
             "-1": "👎",
             "100": "💯",
-            "1234": "🔢",
-            "8ball": "🎱",
-            "a": "🅰",
+            "octocat": octocatPng,
+            "trollface": trollfacePng,
         },
         toolbar: [{
             name: 'emoji',
@@ -35,7 +37,7 @@ export class OptionsClass {
             prefix: '**',
             suffix: '**',
             hotkey: '⌘ b'
-        }]
+        }],
     }
 
     constructor(options: Options) {

+ 8 - 1
webpack.config.js

@@ -59,10 +59,17 @@ const baseConfig = [
       'index.min': './src/index.ts',
     },
     resolve: {
-      extensions: ['.ts', '.svg'],
+      extensions: ['.ts', '.svg', 'png'],
     },
     module: {
       rules: [
+        {
+          test: /\.png$/,
+          include: [path.resolve(__dirname, './src/assets/images')],
+          use: [
+            'file-loader',
+          ],
+        },
         {
           test: /\.ts$/,
           use: 'ts-loader',

+ 8 - 1
webpack.demo.js

@@ -27,7 +27,7 @@ module.exports = {
     'demo.css': './demo/demo.scss',
   },
   resolve: {
-    extensions: ['.js', '.ts', '.scss', '.svg'],
+    extensions: ['.js', '.ts', '.scss', '.svg', '.png'],
   },
   module: {
     rules: [
@@ -98,6 +98,13 @@ module.exports = {
           },
         },
       },
+      {
+        test: /\.png$/,
+        include: [path.resolve(__dirname, './src/assets/images')],
+        use: [
+          'file-loader',
+        ],
+      },
     ],
   },
   plugins: [