4 |
5 |
6 |
7 |
8 | vue-aspect-ratio
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true
5 | },
6 | 'extends': [
7 | 'plugin:vue/essential',
8 | 'eslint:recommended'
9 | ],
10 | rules: {
11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
13 | },
14 | parserOptions: {
15 | parser: 'babel-eslint'
16 | },
17 | overrides: [
18 | {
19 | files: [
20 | '**/__tests__/*.{j,t}s?(x)',
21 | '**/tests/unit/**/*.spec.{j,t}s?(x)'
22 | ],
23 | env: {
24 | jest: true
25 | }
26 | }
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/tests/e2e/support/index.js:
--------------------------------------------------------------------------------
1 | // ***********************************************************
2 | // This example support/index.js is processed and
3 | // loaded automatically before your test files.
4 | //
5 | // This is a great place to put global configuration and
6 | // behavior that modifies Cypress.
7 | //
8 | // You can change the location of this file or turn off
9 | // automatically serving support files with the
10 | // 'supportFile' configuration option.
11 | //
12 | // You can read more here:
13 | // https://on.cypress.io/configuration
14 | // ***********************************************************
15 |
16 | // Import commands.js using ES2015 syntax:
17 | import './commands'
18 |
19 | // Alternatively you can use CommonJS syntax:
20 | // require('./commands')
21 |
--------------------------------------------------------------------------------
/tests/unit/aspect-ratio.spec.js:
--------------------------------------------------------------------------------
1 | // import { mount, createLocalVue } from '@vue/test-utils'
2 | // import Test from '@/components/Test.vue'
3 |
4 | // describe('VueAspectRatio', () => {
5 | // it('should render html in default slot', () => {
6 | // const localVue = createLocalVue()
7 | // const wrapper = mount(Test, {
8 | // localVue
9 | // })
10 | // const contentWrapper = wrapper.find(".content")
11 | // expect(contentWrapper.text().indexOf("This is the content")).toEqual(0);
12 | // });
13 |
14 | // // it('should fallback to 1:1 by default', () => {
15 | // // const localVue = createLocalVue()
16 | // // const wrapper = mount(Test, {
17 | // // localVue
18 | // // })
19 | // // const contentWrapper = wrapper.find(".content")
20 |
21 | // // });
22 | // })
23 |
--------------------------------------------------------------------------------
/tests/e2e/support/commands.js:
--------------------------------------------------------------------------------
1 | // ***********************************************
2 | // This example commands.js shows you how to
3 | // create various custom commands and overwrite
4 | // existing commands.
5 | //
6 | // For more comprehensive examples of custom
7 | // commands please read more here:
8 | // https://on.cypress.io/custom-commands
9 | // ***********************************************
10 | //
11 | //
12 | // -- This is a parent command --
13 | // Cypress.Commands.add("login", (email, password) => { ... })
14 | //
15 | //
16 | // -- This is a child command --
17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
18 | //
19 | //
20 | // -- This is a dual command --
21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
22 | //
23 | //
24 | // -- This is will overwrite an existing command --
25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
26 |
--------------------------------------------------------------------------------
/tests/e2e/plugins/index.js:
--------------------------------------------------------------------------------
1 | // https://docs.cypress.io/guides/guides/plugins-guide.html
2 |
3 | // if you need a custom webpack configuration you can uncomment the following import
4 | // and then use the `file:preprocessor` event
5 | // as explained in the cypress docs
6 | // https://docs.cypress.io/api/plugins/preprocessors-api.html#Examples
7 |
8 | /* eslint-disable import/no-extraneous-dependencies, global-require, arrow-body-style */
9 | // const webpack = require('@cypress/webpack-preprocessor')
10 |
11 | module.exports = (on, config) => {
12 | // on('file:preprocessor', webpack({
13 | // webpackOptions: require('@vue/cli-service/webpack.config'),
14 | // watchOptions: {}
15 | // }))
16 |
17 | return Object.assign({}, config, {
18 | fixturesFolder: 'tests/e2e/fixtures',
19 | integrationFolder: 'tests/e2e/specs',
20 | screenshotsFolder: 'tests/e2e/screenshots',
21 | videosFolder: 'tests/e2e/videos',
22 | supportFile: 'tests/e2e/support/index.js'
23 | })
24 | }
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Alberto De Agostini
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 |
--------------------------------------------------------------------------------
/tests/e2e/specs/test.js:
--------------------------------------------------------------------------------
1 | // https://docs.cypress.io/api/introduction/api.html
2 |
3 | describe("VueAspectRatio", () => {
4 | it("should open the app root url", () => {
5 | cy.visit("localhost:8080")
6 | cy.contains("h1", "Vue Aspect Ratio")
7 | });
8 |
9 | it("should fallback aspect-ratio 1:1 if none is proved", () => {
10 | cy.visit("localhost:8080")
11 | cy.get(".content-2").should($div => {
12 | const style = window.getComputedStyle($div[0])
13 | expect(style.height).to.equal("150px")
14 | })
15 | });
16 |
17 | it("should render a correct 16:9 aspect ratio if given", () => {
18 | cy.visit("localhost:8080")
19 | cy.get(".content-3").should($div => {
20 | const style = window.getComputedStyle($div[0])
21 | expect(style.height).to.equal("180px")
22 | })
23 | });
24 |
25 | it("should render a correct 1:2 aspect ratio if given", () => {
26 | cy.visit("localhost:8080")
27 | cy.get(".content-4").should($div => {
28 | const style = window.getComputedStyle($div[0])
29 | expect(style.height).to.equal("200px")
30 | })
31 | });
32 |
33 | it("should not define width if not specified", () => {
34 | cy.visit("localhost:8080")
35 | cy.get(".vue-ar1 > .vue-aspect-ratio").should($div => {
36 | const height = $div[0].style.height
37 | expect(height).to.equal("")
38 | })
39 | });
40 |
41 | it("should set width of the element if specified", () => {
42 | cy.visit("localhost:8080")
43 | cy.get(".vue-ar2 > .vue-aspect-ratio").should($div => {
44 | const inlineStyle = $div[0].getAttribute("style");
45 | expect(inlineStyle).to.equal("width: 150px;")
46 | })
47 | });
48 | });
49 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": "albertodeagostini.dev@gmail.com",
3 | "name": "vue-aspect-ratio",
4 | "version": "0.1.1",
5 | "scripts": {
6 | "docs": "npm run docs:serve",
7 | "docs:build": "vue-cli-service docs --mode build",
8 | "docs:serve": "vue-cli-service docs --mode serve",
9 | "dev": "vue-cli-service serve",
10 | "build": "vue-cli-service build",
11 | "lint": "vue-cli-service lint",
12 | "test:open": "npx cypress open",
13 | "test": "npx cypress run",
14 | "prepublish": "vue-cli-service lint && vue-cli-service docs --mode build && vue-cli-service build"
15 | },
16 | "main": "dist/vue-aspect-ratio.common.js",
17 | "module": "dist/vue-aspect-ratio.esm.js",
18 | "unpkg": "dist/vue-aspect-ratio.umd.min.js",
19 | "files": [
20 | "dist/vue-aspect-ratio.common.js",
21 | "dist/vue-aspect-ratio.umd.min.js",
22 | "dist/vue-aspect-ratio.umd.js",
23 | "dist/vue-aspect-ratio.esm.js",
24 | "src"
25 | ],
26 | "dependencies": {
27 | "core-js": "^3.3.2"
28 | },
29 | "devDependencies": {
30 | "@vue/cli-plugin-babel": "^5.0.9",
31 | "@vue/cli-plugin-e2e-cypress": "^5.0.9",
32 | "@vue/cli-plugin-eslint": "^5.0.9",
33 | "@vue/cli-plugin-unit-jest": "^5.0.9",
34 | "@vue/cli-service": "^5.0.9",
35 | "@vue/test-utils": "1.0.0-beta.29",
36 | "babel-eslint": "^10.0.3",
37 | "eslint": "^5.16.0",
38 | "eslint-plugin-vue": "^5.0.0",
39 | "vue-cli-plugin-p11n": "^0.4.0",
40 | "vue-template-compiler": "^2.6.10",
41 | "vue": "^2.6.10"
42 | },
43 | "repository": {
44 | "type": "git",
45 | "url": "https://github.com/albertodeago/vue-aspect-ratio.git"
46 | },
47 | "bugs": {
48 | "url": "https://github.com/albertodeago/vue-aspect-ratio/issues"
49 | },
50 | "homepage": "https://github.com/albertodeago/vue-aspect-ratio/blob/master/README.md",
51 | "jsdelivr": "dist/vue-aspect-ratio.umd.min.js",
52 | "license": "MIT",
53 | "sideeffects": false
54 | }
--------------------------------------------------------------------------------
/src/AspectRatio.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
72 |
73 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # vue-aspect-ratio
4 |
5 | A component to render a certain aspect ratio element without javascript computations.
6 | It exposes a default slot that will have the desided ratio.
7 | Weights 3.8kb not gzipped. No dependencies.
8 | 100% responsive
9 |
10 | 
11 |
12 |
13 |
14 |
15 | ## How to install and use
16 |
17 | To install the package in your application just type
18 | ```
19 | npm install vue-aspect-ratio
20 | ```
21 |
22 | Then, to install as a global component
23 | ``` javascript
24 | import Vue from "vue";
25 | import VueAspectRatio from "vue-aspect-ratio";
26 |
27 | Vue.component("vue-aspect-ratio", VueAspectRatio)
28 | ```
29 |
30 | Or you can register locally in one of your components as follows
31 | ``` javascript
32 | import VueAspectRatio from "vue-aspect-ratio";
33 |
34 | export default {
35 | name: "AmazingComponent",
36 | props: [myprop],
37 | components: {
38 | "vue-aspect-ratio": VueAspectRatio
39 | }
40 | }
41 | ```
42 |
43 | Using in templates
44 | ``` html
45 |
46 |
47 |
your content goes here
48 |
49 |
50 | ```
51 |
52 | NOTE: You may need to set in css "height: 100%" on your content that goes inside vue-aspect-ratio to fill the entire space if your content is not long enough.
53 |
54 | ## Parameters and events
55 |
56 | Component props:
57 |
58 | | Name | Type | Mandatory | Example | Description |
59 | |--------|--------|-----------|---------|------------------|
60 | | ar | String | false | "16:9" | the aspect ratio |
61 | | width | String | false | "640px" | the css value of the width to set on the element |
62 |
63 | It does not emit any event
64 |
65 | ## Contributing
66 |
67 | The project is opened to contributes, suggestions and improvements. You can use the [Issues](https://github.com/albertodeago/vue-aspect-ratio/issues) section.
68 |
69 |
70 | ### Project setup
71 |
72 | Fork the project, open it up and type
73 | ```
74 | npm install
75 | ```
76 |
77 | To run the example page, it will open a dev server listening to localhost:8080 (usually), type:
78 | ```
79 | npm run dev
80 | ```
81 |
82 | To build for production
83 | ```
84 | npm run build
85 | ```
86 |
87 | To lint the project
88 | ```
89 | npm run lint
90 | ```
91 |
92 | To prepare for pubblication
93 | ```
94 | npm run prepublish
95 | ```
96 |
97 | ### Test
98 |
99 | The project uses [Cypress](https://www.cypress.io/)
100 | If you want to open the interactive cypress dashboard to run and check tests
101 | ```
102 | npm run test:open
103 | ```
104 |
105 | If you instead just want to run the tests in headless mode
106 | ```
107 | npm run test
108 | ```
109 |
110 | Note: tests required dev server to be up and running
111 |
112 | ## Author and License
113 |
114 | [Alberto De Agostini](https://twitter.com/albertodeago88)
115 |
116 | Licensed under MIT
117 |
--------------------------------------------------------------------------------
/dist/vue-aspect-ratio.umd.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * vue-aspect-ratio v0.1.1
3 | * (c) 2019 albertodeagostini.dev@gmail.com
4 | * Released under the MIT License.
5 | */
6 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self,e.VueAspectRatio=t())}(this,function(){"use strict";function e(e,i){return t(e)||n(e,i)||r()}function t(e){if(Array.isArray(e))return e}function n(e,t){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e)){var n=[],r=!0,i=!1,o=void 0;try{for(var a,s=e[Symbol.iterator]();!(r=(a=s.next()).done)&&(n.push(a.value),!t||n.length!==t);r=!0);}catch(e){i=!0,o=e}finally{try{r||null==s.return||s.return()}finally{if(i)throw o}}return n}}function r(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}function i(e,t,n,r,i,o,a,s,d,u){"boolean"!=typeof a&&(d=s,s=a,a=!1);var c="function"==typeof n?n.options:n;e&&e.render&&(c.render=e.render,c.staticRenderFns=e.staticRenderFns,c._compiled=!0,i&&(c.functional=!0)),r&&(c._scopeId=r);var l;if(o?(l=function(e){e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,e||"undefined"==typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),t&&t.call(this,d(e)),e&&e._registeredComponents&&e._registeredComponents.add(o)},c._ssrRegister=l):t&&(l=a?function(){t.call(this,u(this.$root.$options.shadowRoot))}:function(e){t.call(this,s(e))}),l)if(c.functional){var f=c.render;c.render=function(e,t){return l.call(t),f(e,t)}}else{var p=c.beforeCreate;c.beforeCreate=p?[].concat(p,l):[l]}return n}function o(e){return function(e,t){return a(e,t)}}function a(e,t){var n=u?t.media||"default":e,r=l[n]||(l[n]={ids:new Set,styles:[]});if(!r.ids.has(e)){r.ids.add(e);var i=t.source;if(t.map&&(i+="\n/*# sourceURL="+t.map.sources[0]+" */",i+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(t.map))))+" */"),r.element||(r.element=document.createElement("style"),r.element.type="text/css",t.media&&r.element.setAttribute("media",t.media),c.appendChild(r.element)),"styleSheet"in r.element)r.styles.push(i),r.element.styleSheet.cssText=r.styles.filter(Boolean).join("\n");else{var o=r.ids.size-1,a=document.createTextNode(i),s=r.element.childNodes;s[o]&&r.element.removeChild(s[o]),s.length?r.element.insertBefore(a,s[o]):r.element.appendChild(a)}}}var s={name:"VueAspectRatio",props:{ar:{type:String,default:"1:1",validator:function(t){var n=t.split(":").map(function(e){return parseInt(e)}),r=e(n,2),i=r[0],o=r[1];return!Number.isNaN(i)&&!Number.isNaN(o)}},width:String},data:function(){return{w:null,h:null}},computed:{componentStyle:function(){return this.width?{width:this.width}:{}},innerStyle:function(){return{paddingTop:this.h/this.w*100+"%"}}},created:function(){var t=this.ar.split(":").map(function(e){return parseInt(e)}),n=e(t,2),r=n[0],i=n[1];this.w=r,this.h=i}},d=i,u="undefined"!=typeof navigator&&/msie [6-9]\\b/.test(navigator.userAgent.toLowerCase()),c=document.head||document.getElementsByTagName("head")[0],l={},f=o;const p=s;var m=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"vue-aspect-ratio",style:e.componentStyle},[n("div",{staticClass:"vue-aspect-ratio__inner",style:e.innerStyle},[n("div",{staticClass:"vue-aspect-ratio__content"},[e._t("default")],2)])])},h=[];const v=function(e){e&&e("data-v-f0460d78_0",{source:".vue-aspect-ratio__inner[data-v-f0460d78]{position:relative}.vue-aspect-ratio__content[data-v-f0460d78]{position:absolute;top:0;left:0;width:100%;height:100%}",map:void 0,media:void 0})};var y=d({render:m,staticRenderFns:h},v,p,"data-v-f0460d78",!1,void 0,f,void 0),_=Object.freeze({__proto__:null,default:y});return function(e){return e&&e.default||e}(_)});
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |