├── .editorconfig
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── dist
├── main.esm.js
├── main.js
├── main.umd.min.js
└── main.umd.min.js.map
├── package-lock.json
├── package.json
├── src
├── Textra.vue
└── main.js
└── test
├── .setup.js
└── test.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | npm-debug.log
4 | yarn-error.log
5 |
6 | # Editor directories and files
7 | .idea
8 | *.suo
9 | *.ntvs*
10 | *.njsproj
11 | *.sln
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | cache:
3 | directories:
4 | - node_modules
5 | node_js:
6 | - "10"
7 | services:
8 | - xvfb
9 | before_script:
10 | - npm install
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018 Hosein Barzegaran
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Textra [](https://travis-ci.org/hosein2398/Textra)
3 |
4 | > A Vue.js add-on to slide your text. [demo](https://hosein2398.github.io/textra/)
5 |
6 | ## Installing
7 | ```
8 | npm i -D vue-textra
9 | ```
10 | Then inside your project, start using it:
11 | ```js
12 | import Vue from 'vue'
13 | import App from './App.vue'
14 | import Textra from 'vue-textra'
15 |
16 | Vue.use(Textra);
17 | new Vue({
18 | el: '#app',
19 | render: h => h(App)
20 | })
21 | ```
22 | To use inside browser:
23 | ```html
24 |
25 | ```
26 | Then:
27 | ```js
28 | Vue.use(Textra);
29 | ```
30 | ## Usage
31 | Inside any of your components:
32 | ```html
33 |
34 | ```
35 | And in your instance data:
36 | ```js
37 | //...
38 | data () {
39 | return {
40 | words: ["My text to show", "Great news here!", "Vue is great", "Sample Text"]
41 | }
42 | }
43 | //...
44 | ```
45 |
46 | Another example :
47 | ```html
48 |
49 | ```
50 | This one will loop around for ever.
51 | ## Props
52 | #### `data`
53 | Type : Array
54 | Description : Should be array of things you want to slide.
55 |
56 | ---
57 |
58 | #### `timer`
59 | Type : Number
60 | Description : Defines gap between each slide as second.
61 | Default : `2`
62 |
63 | ---
64 |
65 | #### `filter`
66 | Type : String
67 | Description : Defines type of filter you want to use when sliding.
68 | Default : `simple`
69 |
70 | ---
71 |
72 | #### `infinite`
73 | Type : Boolean
74 | Description : Defines whether your slider should keep looping or not.
75 | Default : `false`
76 |
77 |
78 | ## Filters
79 | There are 9 types of filters available for now:
80 | + `simple`
81 | + `bottom-top`
82 | + `top-bottom`
83 | + `right-left`
84 | + `left-right`
85 | + `press`
86 | + `scale`
87 | + `flash`
88 | + `flip`
89 |
--------------------------------------------------------------------------------
/dist/main.esm.js:
--------------------------------------------------------------------------------
1 | import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
2 | import __vue_create_injector__ from 'vue-runtime-helpers/dist/inject-style/browser.js';
3 |
4 | //
5 | //
6 | //
7 | //
8 | //
9 | //
10 | var script = {
11 | name: "Textra",
12 | props: {
13 | data: {
14 | type: Array,
15 | required: true
16 | },
17 | filter: {
18 | type: String,
19 | "default": "simple"
20 | },
21 | timer: {
22 | type: Number,
23 | "default": 2
24 | },
25 | infinite: {
26 | type: Boolean,
27 | "default": false
28 | }
29 | },
30 | data: function data() {
31 | return {
32 | defaultStyle: "transition: all 0.5s;",
33 | currentWord: this.data[0],
34 | liStl: null,
35 | dataCounter: 0,
36 | animationID: null,
37 | filters: {
38 | simple: ["opacity:0", "opacity:1"],
39 | "bottom-top": ["transform:translateY(10px);opacity:0;", "transform:translateY(0px);opacity:1;"],
40 | "top-bottom": ["transform:translateY(-10px);opacity:0;", "transform:translateY(0px);opacity:1;"],
41 | "right-left": ["transform:translateX(10px);opacity:0;", "transform:translateX(0px);opacity:1;"],
42 | "left-right": ["transform:translateX(-10px);opacity:0;", "transform:translateX(0px);opacity:1;"],
43 | press: ["letter-spacing: 4px;opacity:0;", "opacity:1;"],
44 | scale: ["transform:scaleY(1.4);opacity:0;", "opacity:1;"],
45 | flash: ["transform:skewX(-70deg);opacity:0;", "transform:skewX(0deg);opacity:1;"],
46 | flip: ["transform:rotateX(-180deg);opacity:0;", "transform:rotate(0deg);opacity:1;"]
47 | }
48 | };
49 | },
50 | computed: {
51 | mainStyleComputed: function mainStyleComputed() {
52 | return this.defaultStyle + this.liStl;
53 | }
54 | },
55 | created: function created() {
56 | var previousTime = 0;
57 | var that = this;
58 |
59 | function run(currentTime) {
60 | if (previousTime + this.timer * 1000 < currentTime) {
61 | //hiding
62 | this.liStl = this.filters[this.filter][0];
63 | }
64 |
65 | if (previousTime + this.timer * 1000 + 1000 < currentTime) {
66 | //showing
67 | previousTime = currentTime;
68 | this.currentWord = this.data[++this.dataCounter];
69 | this.liStl = this.filters[this.filter][1];
70 |
71 | if (this.dataCounter === this.data.length) {
72 | if (this.infinite) {
73 | this.dataCounter = 0;
74 | this.currentWord = this.data[this.dataCounter];
75 | } else {
76 | window.cancelAnimationFrame(this.animationID);
77 | return;
78 | }
79 | }
80 | }
81 |
82 | this.animationID = window.requestAnimationFrame(run.bind(that));
83 | }
84 |
85 | this.animationID = window.requestAnimationFrame(run.bind(that));
86 | },
87 | beforeDestroy: function beforeDestroy() {
88 | window.cancelAnimationFrame(this.animationID);
89 | }
90 | };
91 |
92 | /* script */
93 | var __vue_script__ = script;
94 | /* template */
95 |
96 | var __vue_render__ = function __vue_render__() {
97 | var _vm = this;
98 |
99 | var _h = _vm.$createElement;
100 |
101 | var _c = _vm._self._c || _h;
102 |
103 | return _c('div', {
104 | staticClass: "textra"
105 | }, [_c('div', {
106 | staticClass: "mainTextra",
107 | style: _vm.mainStyleComputed,
108 | domProps: {
109 | "innerHTML": _vm._s(_vm.currentWord)
110 | }
111 | })]);
112 | };
113 |
114 | var __vue_staticRenderFns__ = [];
115 | /* style */
116 |
117 | var __vue_inject_styles__ = function __vue_inject_styles__(inject) {
118 | if (!inject) return;
119 | inject("data-v-d9d0826c_0", {
120 | source: ".textra[data-v-d9d0826c]{height:auto;width:auto;display:block}",
121 | map: undefined,
122 | media: undefined
123 | });
124 | };
125 | /* scoped */
126 |
127 |
128 | var __vue_scope_id__ = "data-v-d9d0826c";
129 | /* module identifier */
130 |
131 | var __vue_module_identifier__ = undefined;
132 | /* functional template */
133 |
134 | var __vue_is_functional_template__ = false;
135 | /* style inject SSR */
136 |
137 | var TextraPlugin = __vue_normalize__({
138 | render: __vue_render__,
139 | staticRenderFns: __vue_staticRenderFns__
140 | }, __vue_inject_styles__, __vue_script__, __vue_scope_id__, __vue_is_functional_template__, __vue_module_identifier__, __vue_create_injector__, undefined);
141 |
142 | var Textra = {
143 | install: function install(Vue) {
144 | Vue.component("textra", TextraPlugin);
145 | }
146 | };
147 |
148 | export default Textra;
149 |
--------------------------------------------------------------------------------
/dist/main.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
4 |
5 | var __vue_normalize__ = _interopDefault(require('vue-runtime-helpers/dist/normalize-component.js'));
6 | var __vue_create_injector__ = _interopDefault(require('vue-runtime-helpers/dist/inject-style/browser.js'));
7 |
8 | //
9 | //
10 | //
11 | //
12 | //
13 | //
14 | var script = {
15 | name: "Textra",
16 | props: {
17 | data: {
18 | type: Array,
19 | required: true
20 | },
21 | filter: {
22 | type: String,
23 | "default": "simple"
24 | },
25 | timer: {
26 | type: Number,
27 | "default": 2
28 | },
29 | infinite: {
30 | type: Boolean,
31 | "default": false
32 | }
33 | },
34 | data: function data() {
35 | return {
36 | defaultStyle: "transition: all 0.5s;",
37 | currentWord: this.data[0],
38 | liStl: null,
39 | dataCounter: 0,
40 | animationID: null,
41 | filters: {
42 | simple: ["opacity:0", "opacity:1"],
43 | "bottom-top": ["transform:translateY(10px);opacity:0;", "transform:translateY(0px);opacity:1;"],
44 | "top-bottom": ["transform:translateY(-10px);opacity:0;", "transform:translateY(0px);opacity:1;"],
45 | "right-left": ["transform:translateX(10px);opacity:0;", "transform:translateX(0px);opacity:1;"],
46 | "left-right": ["transform:translateX(-10px);opacity:0;", "transform:translateX(0px);opacity:1;"],
47 | press: ["letter-spacing: 4px;opacity:0;", "opacity:1;"],
48 | scale: ["transform:scaleY(1.4);opacity:0;", "opacity:1;"],
49 | flash: ["transform:skewX(-70deg);opacity:0;", "transform:skewX(0deg);opacity:1;"],
50 | flip: ["transform:rotateX(-180deg);opacity:0;", "transform:rotate(0deg);opacity:1;"]
51 | }
52 | };
53 | },
54 | computed: {
55 | mainStyleComputed: function mainStyleComputed() {
56 | return this.defaultStyle + this.liStl;
57 | }
58 | },
59 | created: function created() {
60 | var previousTime = 0;
61 | var that = this;
62 |
63 | function run(currentTime) {
64 | if (previousTime + this.timer * 1000 < currentTime) {
65 | //hiding
66 | this.liStl = this.filters[this.filter][0];
67 | }
68 |
69 | if (previousTime + this.timer * 1000 + 1000 < currentTime) {
70 | //showing
71 | previousTime = currentTime;
72 | this.currentWord = this.data[++this.dataCounter];
73 | this.liStl = this.filters[this.filter][1];
74 |
75 | if (this.dataCounter === this.data.length) {
76 | if (this.infinite) {
77 | this.dataCounter = 0;
78 | this.currentWord = this.data[this.dataCounter];
79 | } else {
80 | window.cancelAnimationFrame(this.animationID);
81 | return;
82 | }
83 | }
84 | }
85 |
86 | this.animationID = window.requestAnimationFrame(run.bind(that));
87 | }
88 |
89 | this.animationID = window.requestAnimationFrame(run.bind(that));
90 | },
91 | beforeDestroy: function beforeDestroy() {
92 | window.cancelAnimationFrame(this.animationID);
93 | }
94 | };
95 |
96 | /* script */
97 | var __vue_script__ = script;
98 | /* template */
99 |
100 | var __vue_render__ = function __vue_render__() {
101 | var _vm = this;
102 |
103 | var _h = _vm.$createElement;
104 |
105 | var _c = _vm._self._c || _h;
106 |
107 | return _c('div', {
108 | staticClass: "textra"
109 | }, [_c('div', {
110 | staticClass: "mainTextra",
111 | style: _vm.mainStyleComputed,
112 | domProps: {
113 | "innerHTML": _vm._s(_vm.currentWord)
114 | }
115 | })]);
116 | };
117 |
118 | var __vue_staticRenderFns__ = [];
119 | /* style */
120 |
121 | var __vue_inject_styles__ = function __vue_inject_styles__(inject) {
122 | if (!inject) return;
123 | inject("data-v-d9d0826c_0", {
124 | source: ".textra[data-v-d9d0826c]{height:auto;width:auto;display:block}",
125 | map: undefined,
126 | media: undefined
127 | });
128 | };
129 | /* scoped */
130 |
131 |
132 | var __vue_scope_id__ = "data-v-d9d0826c";
133 | /* module identifier */
134 |
135 | var __vue_module_identifier__ = undefined;
136 | /* functional template */
137 |
138 | var __vue_is_functional_template__ = false;
139 | /* style inject SSR */
140 |
141 | var TextraPlugin = __vue_normalize__({
142 | render: __vue_render__,
143 | staticRenderFns: __vue_staticRenderFns__
144 | }, __vue_inject_styles__, __vue_script__, __vue_scope_id__, __vue_is_functional_template__, __vue_module_identifier__, __vue_create_injector__, undefined);
145 |
146 | var Textra = {
147 | install: function install(Vue) {
148 | Vue.component("textra", TextraPlugin);
149 | }
150 | };
151 |
152 | module.exports = Textra;
153 |
--------------------------------------------------------------------------------
/dist/main.umd.min.js:
--------------------------------------------------------------------------------
1 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).Textra=e()}(this,function(){"use strict";var t={name:"Textra",props:{data:{type:Array,required:!0},filter:{type:String,default:"simple"},timer:{type:Number,default:2},infinite:{type:Boolean,default:!1}},data:function(){return{defaultStyle:"transition: all 0.5s;",currentWord:this.data[0],liStl:null,dataCounter:0,animationID:null,filters:{simple:["opacity:0","opacity:1"],"bottom-top":["transform:translateY(10px);opacity:0;","transform:translateY(0px);opacity:1;"],"top-bottom":["transform:translateY(-10px);opacity:0;","transform:translateY(0px);opacity:1;"],"right-left":["transform:translateX(10px);opacity:0;","transform:translateX(0px);opacity:1;"],"left-right":["transform:translateX(-10px);opacity:0;","transform:translateX(0px);opacity:1;"],press:["letter-spacing: 4px;opacity:0;","opacity:1;"],scale:["transform:scaleY(1.4);opacity:0;","opacity:1;"],flash:["transform:skewX(-70deg);opacity:0;","transform:skewX(0deg);opacity:1;"],flip:["transform:rotateX(-180deg);opacity:0;","transform:rotate(0deg);opacity:1;"]}}},computed:{mainStyleComputed:function(){return this.defaultStyle+this.liStl}},created:function(){var t=0,e=this;this.animationID=window.requestAnimationFrame(function n(i){if(t+1e3*this.timer",
6 | "license": "MIT",
7 | "homepage": "https://github.com/hosein2398/Textra",
8 | "bugs": {
9 | "url": "https://github.com/hosein2398/Textra/issues"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/hosein2398/Textra"
14 | },
15 | "keywords": [
16 | "vue",
17 | "slider",
18 | "slide text",
19 | "text animation"
20 | ],
21 | "main": "dist/main.js",
22 | "module": "dist/main.esm.js",
23 | "browser": "dist/main.umd.min.js",
24 | "scripts": {
25 | "test": "./node_modules/.bin/ava test/test.js",
26 | "build": "bili ./src/main.js --format umd-min,cjs,esm --module-name Textra --plugins.vue.css false"
27 | },
28 | "devDependencies": {
29 | "@babel/preset-stage-3": "^7.0.0",
30 | "ava": "^0.25.0",
31 | "avoriaz": "^6.3.0",
32 | "babel-loader": "^7.1.2",
33 | "bili": "^4.8.1",
34 | "browser-env": "^3.2.5",
35 | "cross-env": "^5.0.5",
36 | "css-loader": "^0.28.7",
37 | "file-loader": "^1.1.4",
38 | "require-extension-hooks": "^0.3.2",
39 | "require-extension-hooks-babel": "^0.1.1",
40 | "require-extension-hooks-vue": "^0.4.1",
41 | "rollup-plugin-vue": "^5.0.1",
42 | "vue": "^2.6.10",
43 | "vue-loader": "^13.0.5",
44 | "vue-template-compiler": "^2.6.10",
45 | "webpack": "^3.6.0",
46 | "webpack-dev-server": "^2.9.1"
47 | },
48 | "dependencies": {},
49 | "ava": {
50 | "require": [
51 | "./test/.setup.js"
52 | ]
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Textra.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
103 |
104 |
111 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import TextraPlugin from "./Textra.vue";
2 |
3 | const Textra = {
4 | install(Vue) {
5 | Vue.component("textra", TextraPlugin);
6 | }
7 | };
8 |
9 | export default Textra;
10 |
--------------------------------------------------------------------------------
/test/.setup.js:
--------------------------------------------------------------------------------
1 |
2 | require('browser-env')()
3 | const Vue = require('vue');
4 | var hooks = require('require-extension-hooks')
5 |
6 | Vue.config.productionTip = false;
7 | // Setup vue files to be processed by `require-extension-hooks-vue`
8 | hooks('vue').plugin('vue').push()
9 |
10 | // Setup vue and js files to be processed by `require-extension-hooks-babel`
11 | hooks(['vue', 'js']).plugin('babel').push()
12 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | import {
2 | mount
3 | } from 'avoriaz';
4 | import test from 'ava';
5 | import Textra from '../src/Textra.vue';
6 | import {
7 | setTimeout
8 | } from 'timers';
9 |
10 | const wrapper = mount(Textra);
11 | wrapper.setProps({
12 | data: ['first', 'sec', 'third']
13 | });
14 |
15 |
16 |
17 | test('There should be tag with class of textra', (t) => {
18 | t.plan(2);
19 | const tagClass = wrapper.find('.textra').length;
20 | t.is(tagClass, 1);
21 | t.not(tagClass, 2);
22 | });
23 |
24 | test('There should be tag with class of mainTextra', (t) => {
25 | t.plan(2);
26 | const tagClass = wrapper.find('.mainTextra').length;
27 | t.is(tagClass, 1);
28 | t.not(tagClass, 2);
29 | });
30 |
31 | test('Checks if mainStyleComputed exists', (t) => {
32 | const meth = typeof wrapper.computed().mainStyleComputed;
33 | t.is(meth, 'function');
34 | });
35 |
36 | /*
37 | Test below is paused due to a bug in avoriaz
38 | **/
39 |
40 | // test('Checks existence some of datas', (t) => {
41 | // t.plan(2);
42 | // const datas = wrapper.data();
43 | // console.log(datas)
44 | // t.is(datas.dataCounter , 0);
45 | // t.is(datas.displayState , 'shown');
46 | // });
47 |
48 |
49 |
50 | /*
51 |
52 | unfortunately since AVA does not support tests with settimeout and setinterval,
53 | we can not test this functionality of plugin.
54 |
55 |
56 | **/
--------------------------------------------------------------------------------