UNPKG

typewriter-vue

Version:
505 lines (441 loc) 22.2 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('regenerator-runtime/runtime.js'), require('core-js/modules/es.number.constructor.js'), require('core-js/modules/es.string.trim.js'), require('core-js/modules/es.regexp.exec.js'), require('core-js/modules/es.string.replace.js'), require('core-js/modules/es.object.to-string.js'), require('core-js/modules/es.array.slice.js'), require('core-js/modules/es.string.split.js'), require('core-js/modules/es.regexp.constructor.js'), require('core-js/modules/es.regexp.to-string.js'), require('core-js/modules/es.string.match.js')) : typeof define === 'function' && define.amd ? define(['exports', 'regenerator-runtime/runtime.js', 'core-js/modules/es.number.constructor.js', 'core-js/modules/es.string.trim.js', 'core-js/modules/es.regexp.exec.js', 'core-js/modules/es.string.replace.js', 'core-js/modules/es.object.to-string.js', 'core-js/modules/es.array.slice.js', 'core-js/modules/es.string.split.js', 'core-js/modules/es.regexp.constructor.js', 'core-js/modules/es.regexp.to-string.js', 'core-js/modules/es.string.match.js'], factory) : (global = global || self, factory(global.Typewriter = {})); }(this, (function (exports) { 'use strict'; function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } // // // // // // var assert = function assert(condition, message) { if (!condition) { throw new Error(message || "Assertion failed"); } }; var script = { name: "Typewriter", props: { /** * Time to wait before typing first character (ms). */ startDelay: { type: Number, default: 0 }, /** * Interval between entering letters (ms). */ typeInterval: { type: Number, default: 75 }, /** * Array of objects with keys: * - from - @type {String} to be replaced (has to be present in currently displayed text), * - to - @type {String} that will replace 'from' text */ replace: { type: Array, default: function _default() { return []; } }, /** * Interval between replacing in (ms). */ replaceInterval: { type: Number, default: 2000 } }, mounted: function mounted() { this.init(); }, methods: { init: function init() { var _this = this; return _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() { var _this$$el, innerHTML, innerText; return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: _this$$el = _this.$el, innerHTML = _this$$el.innerHTML, innerText = _this$$el.innerText; _this.$el.innerHTML = innerHTML.trim() === innerText ? "<span>".concat(innerHTML, "</span>") : innerHTML; _context.next = 4; return _this.typewriter(_this.$el.innerHTML); case 4: if (_this.replace.length) { setTimeout(function () { _this.startReplacing(); }, _this.replaceInterval); } case 5: case "end": return _context.stop(); } } }, _callee); }))(); }, typewriter: function typewriter(str) { var _this2 = this; return new Promise(function (resolve) { _this2.$el.innerHTML = ""; var f = function f(index) { var current = str[index]; index = current === "<" ? str.indexOf(">", index) + 1 : ++index; _this2.$el.innerHTML = str.substr(0, index); if (index < str.length - 1) { setTimeout(f, _this2.typeInterval, index); return; } resolve(); }; f(0); }); }, removeString: function removeString(start, end) { var _this3 = this; return new Promise(function (resolve) { var elementCopy = _this3.$el; var f = function f(index) { elementCopy.innerHTML = elementCopy.innerHTML.slice(0, index); index--; if (start <= index) { setTimeout(f, _this3.typeInterval, index); return; } resolve(); }; f(end - 1); }); }, addString: function addString(start, str) { var _this4 = this; return new Promise(function (resolve) { var elementCopy = _this4.$el; var f = function f(index, start) { elementCopy.innerHTML = _this4.insert(elementCopy.innerHTML, start, str[index]); if (index < str.length - 1) { setTimeout(f, _this4.typeInterval, ++index, ++start); return; } resolve(); }; f(0, start); }); }, insert: function insert(text, index, newChar) { return text.substring(0, index) + newChar + text.substr(index); }, replaceLastWord: function replaceLastWord(to) { var _this5 = this; return _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() { var lastWord; return regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: lastWord = _this5.$el.innerText.split(" ").pop(); assert(lastWord, "Component`s current innerHTML is empty"); _context2.next = 4; return _this5.replaceText({ from: lastWord, to: to }); case 4: case "end": return _context2.stop(); } } }, _callee2); }))(); }, replaceText: function replaceText(changed) { var _this6 = this; return _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() { var from, to, str, regex, match, index; return regeneratorRuntime.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: assert(changed, "Changed parameter is needed"); from = changed.from, to = changed.to; str = _this6.$el.innerHTML; regex = new RegExp("\\b" + from + "\\b"); match = str.match(regex); assert(match, "Substring '".concat(from, "' not found in component` current innerHTML")); index = match.index; _context3.next = 9; return _this6.removeString(index, index + from.length); case 9: _context3.next = 11; return _this6.addString(index, to); case 11: case "end": return _context3.stop(); } } }, _callee3); }))(); }, startReplacing: function startReplacing() { var _this7 = this; var replace = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.replace; var replaceInterval = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.replaceInterval; if (!replace) { throw new Error("Replace parameter is needed"); } if (!replace) { throw new Error("Replace parameter has 0 length"); } return new Promise(function (resolve) { var func = /*#__PURE__*/function () { var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4(index) { return regeneratorRuntime.wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: _context4.next = 2; return _this7.replaceText(replace[index]); case 2: if (!(index < replace.length - 1)) { _context4.next = 5; break; } setTimeout(func, replaceInterval, ++index); return _context4.abrupt("return"); case 5: resolve(); case 6: case "end": return _context4.stop(); } } }, _callee4); })); return function func(_x) { return _ref.apply(this, arguments); }; }(); func(0); }); } } }; function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) { if (typeof shadowMode !== 'boolean') { createInjectorSSR = createInjector; createInjector = shadowMode; shadowMode = false; } // Vue.extend constructor export interop. const options = typeof script === 'function' ? script.options : script; // render functions if (template && template.render) { options.render = template.render; options.staticRenderFns = template.staticRenderFns; options._compiled = true; // functional template if (isFunctionalTemplate) { options.functional = true; } } // scopedId if (scopeId) { options._scopeId = scopeId; } let hook; if (moduleIdentifier) { // server build hook = function (context) { // 2.3 injection context = context || // cached call (this.$vnode && this.$vnode.ssrContext) || // stateful (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional // 2.2 with runInNewContext: true if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { context = __VUE_SSR_CONTEXT__; } // inject component styles if (style) { style.call(this, createInjectorSSR(context)); } // register component module identifier for async chunk inference if (context && context._registeredComponents) { context._registeredComponents.add(moduleIdentifier); } }; // used by ssr in case component is cached and beforeCreate // never gets called options._ssrRegister = hook; } else if (style) { hook = shadowMode ? function (context) { style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot)); } : function (context) { style.call(this, createInjector(context)); }; } if (hook) { if (options.functional) { // register for functional component in vue file const originalRender = options.render; options.render = function renderWithStyleInjection(h, context) { hook.call(context); return originalRender(h, context); }; } else { // inject component registration as beforeCreate hook const existing = options.beforeCreate; options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; } } return script; } const isOldIE = typeof navigator !== 'undefined' && /msie [6-9]\\b/.test(navigator.userAgent.toLowerCase()); function createInjector(context) { return (id, style) => addStyle(id, style); } let HEAD; const styles = {}; function addStyle(id, css) { const group = isOldIE ? css.media || 'default' : id; const style = styles[group] || (styles[group] = { ids: new Set(), styles: [] }); if (!style.ids.has(id)) { style.ids.add(id); let code = css.source; if (css.map) { // https://developer.chrome.com/devtools/docs/javascript-debugging // this makes source maps inside style tags work properly in Chrome code += '\n/*# sourceURL=' + css.map.sources[0] + ' */'; // http://stackoverflow.com/a/26603875 code += '\n/*# sourceMappingURL=data:application/json;base64,' + btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) + ' */'; } if (!style.element) { style.element = document.createElement('style'); style.element.type = 'text/css'; if (css.media) style.element.setAttribute('media', css.media); if (HEAD === undefined) { HEAD = document.head || document.getElementsByTagName('head')[0]; } HEAD.appendChild(style.element); } if ('styleSheet' in style.element) { style.styles.push(code); style.element.styleSheet.cssText = style.styles .filter(Boolean) .join('\n'); } else { const index = style.ids.size - 1; const textNode = document.createTextNode(code); const nodes = style.element.childNodes; if (nodes[index]) style.element.removeChild(nodes[index]); if (nodes.length) style.element.insertBefore(textNode, nodes[index]); else style.element.appendChild(textNode); } } } /* script */ const __vue_script__ = script; /* template */ var __vue_render__ = function() { var _vm = this; var _h = _vm.$createElement; var _c = _vm._self._c || _h; return _c("div", { staticClass: "content" }, [_vm._t("default")], 2) }; var __vue_staticRenderFns__ = []; __vue_render__._withStripped = true; /* style */ const __vue_inject_styles__ = function (inject) { if (!inject) return inject("data-v-b6673ec6_0", { source: "\n@keyframes blink {\nfrom,\n to {\n opacity: 0;\n}\n50% {\n opacity: 1;\n}\n}\n.content *:last-child::after {\n font-size: calc(1em + 2px);\n content: \"|\";\n animation: blink 0.75s step-end infinite;\n}\n", map: {"version":3,"sources":["/home/runner/work/typewriter-vue/typewriter-vue/src/components/Typewriter.vue"],"names":[],"mappings":";AAkKA;AACA;;IAEA,UAAA;AACA;AACA;IACA,UAAA;AACA;AACA;AAEA;EACA,0BAAA;EACA,YAAA;EACA,wCAAA;AACA","file":"Typewriter.vue","sourcesContent":["<template>\n <div class=\"content\">\n <slot></slot>\n </div>\n</template>\n\n<script>\nconst assert = (condition, message) => {\n if (!condition) {\n throw new Error(message || \"Assertion failed\");\n }\n};\n\nexport default {\n name: \"Typewriter\",\n props: {\n /**\n * Time to wait before typing first character (ms).\n */\n startDelay: {\n type: Number,\n default: 0,\n },\n /**\n * Interval between entering letters (ms).\n */\n typeInterval: {\n type: Number,\n default: 75,\n },\n /**\n * Array of objects with keys:\n * - from - @type {String} to be replaced (has to be present in currently displayed text),\n * - to - @type {String} that will replace 'from' text\n */\n replace: {\n type: Array,\n default: () => [],\n },\n /**\n * Interval between replacing in (ms).\n */\n replaceInterval: {\n type: Number,\n default: 2000,\n },\n },\n mounted() {\n this.init();\n },\n methods: {\n async init() {\n const { innerHTML, innerText } = this.$el;\n this.$el.innerHTML =\n innerHTML.trim() === innerText\n ? `<span>${innerHTML}</span>`\n : innerHTML;\n await this.typewriter(this.$el.innerHTML);\n if (this.replace.length) {\n setTimeout(() => {\n this.startReplacing();\n }, this.replaceInterval);\n }\n },\n typewriter(str) {\n return new Promise((resolve) => {\n this.$el.innerHTML = \"\";\n const f = (index) => {\n const current = str[index];\n index = current === \"<\" ? str.indexOf(\">\", index) + 1 : ++index;\n this.$el.innerHTML = str.substr(0, index);\n if (index < str.length - 1) {\n setTimeout(f, this.typeInterval, index);\n return;\n }\n resolve();\n };\n f(0);\n });\n },\n removeString(start, end) {\n return new Promise((resolve) => {\n const elementCopy = this.$el;\n const f = (index) => {\n elementCopy.innerHTML = elementCopy.innerHTML.slice(0, index);\n index--;\n if (start <= index) {\n setTimeout(f, this.typeInterval, index);\n return;\n }\n resolve();\n };\n f(end - 1);\n });\n },\n addString(start, str) {\n return new Promise((resolve) => {\n const elementCopy = this.$el;\n const f = (index, start) => {\n elementCopy.innerHTML = this.insert(\n elementCopy.innerHTML,\n start,\n str[index]\n );\n if (index < str.length - 1) {\n setTimeout(f, this.typeInterval, ++index, ++start);\n return;\n }\n resolve();\n };\n f(0, start);\n });\n },\n insert(text, index, newChar) {\n return text.substring(0, index) + newChar + text.substr(index);\n },\n async replaceLastWord(to) {\n const lastWord = this.$el.innerText.split(\" \").pop();\n assert(lastWord, \"Component`s current innerHTML is empty\");\n await this.replaceText({ from: lastWord, to });\n },\n async replaceText(changed) {\n assert(changed, \"Changed parameter is needed\");\n const { from, to } = changed;\n const str = this.$el.innerHTML;\n const regex = new RegExp(\"\\\\b\" + from + \"\\\\b\");\n const match = str.match(regex);\n assert(\n match,\n `Substring '${from}' not found in component\\` current innerHTML`\n );\n const { index } = match;\n await this.removeString(index, index + from.length);\n await this.addString(index, to);\n },\n startReplacing(\n replace = this.replace,\n replaceInterval = this.replaceInterval\n ) {\n if (!replace) {\n throw new Error(\"Replace parameter is needed\");\n }\n if (!replace) {\n throw new Error(\"Replace parameter has 0 length\");\n }\n return new Promise((resolve) => {\n const func = async (index) => {\n await this.replaceText(replace[index]);\n if (index < replace.length - 1) {\n setTimeout(func, replaceInterval, ++index);\n return;\n }\n resolve();\n };\n func(0);\n });\n },\n },\n};\n</script>\n\n<style>\n@keyframes blink {\n from,\n to {\n opacity: 0;\n }\n 50% {\n opacity: 1;\n }\n}\n\n.content *:last-child::after {\n font-size: calc(1em + 2px);\n content: \"|\";\n animation: blink 0.75s step-end infinite;\n}\n</style>\n"]}, media: undefined }); }; /* scoped */ const __vue_scope_id__ = undefined; /* module identifier */ const __vue_module_identifier__ = undefined; /* functional template */ const __vue_is_functional_template__ = false; /* style inject SSR */ /* style inject shadow dom */ const __vue_component__ = /*#__PURE__*/normalizeComponent( { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ }, __vue_inject_styles__, __vue_script__, __vue_scope_id__, __vue_is_functional_template__, __vue_module_identifier__, false, createInjector, undefined, undefined ); function install(Vue) { if (install.installed) return; install.installed = true; Vue.component("Typewriter", __vue_component__); } // Create module definition for Vue.use() var plugin = { install: install }; // Auto-install when vue is found (eg. in browser via <script> tag) var GlobalVue = null; if (typeof window !== "undefined") { GlobalVue = window.Vue; } else if (typeof global !== "undefined") { GlobalVue = global.Vue; } if (GlobalVue) { GlobalVue.use(plugin); } // To allow use as module (npm/webpack/etc.) export component exports.default = __vue_component__; exports.install = install; Object.defineProperty(exports, '__esModule', { value: true }); })));