Skip to content

Commit

Permalink
fix: comply to width & height attributes
Browse files Browse the repository at this point in the history
fix #46

BREAKING CHANGE:

`width` and `height` attributes are now applied as-is to the `svg` element, if you want the previous, responsive behavior, use only the new `viewBox` prop instead.

Before: `width="200" height="100"`
After: `viewBox="0 0 200 100"`
  • Loading branch information
LeBenLeBen committed Jan 27, 2021
1 parent 7279c5c commit 8e844cf
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 41 deletions.
51 changes: 37 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ import {
`ContentLoader` is a meta loader while other loaders are just higher-order components of it. By default `ContentLoader` only displays a simple rectangle, here's how you can use it to create custom loaders:

```vue
<ContentLoader>
<ContentLoader viewBox="0 0 250 110">
<rect x="0" y="0" rx="3" ry="3" width="250" height="10" />
<rect x="20" y="20" rx="3" ry="3" width="220" height="10" />
<rect x="20" y="40" rx="3" ry="3" width="170" height="10" />
Expand All @@ -90,19 +90,42 @@ You can also use the [online tool](http://danilowoz.com/create-vue-content-loade

### Props

| Prop | Type | Default | Description |
| ------------------- | ------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| width | number | `400` | |
| height | number | `130` | |
| speed | number | `2` | |
| preserveAspectRatio | string | `'xMidYMid meet'` | |
| primaryColor | string | `'#f9f9f9'` | |
| secondaryColor | string | `'#ecebeb'` | |
| uniqueKey | string | `randomId()` | Unique ID, you need to make it consistent for SSR |
| animate | boolean | `true` | |
| baseUrl | string | empty string | Required if you're using `<base url="/" />` in your `<head />`. Defaults to an empty string. This prop is common used as: `<content-loader :base-url="$route.fullPath" />` which will fill the SVG attribute with the relative path. Related [#14](https://github.com/egoist/vue-content-loader/issues/14). |
| primaryOpacity | number | `1` | Background opacity (0 = transparent, 1 = opaque) used to solve an issue in Safari |
| secondaryOpacity | number | `1` | Background opacity (0 = transparent, 1 = opaque) used to solve an issue in Safari |
| Prop | Type | Default | Description |
| ------------------- | -------------- | ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| width | number, string | | SVG width in pixels without unit |
| height | number, string | | SVG height in pixels without unit |
| viewBox | string | `'0 0 ${width || 400} ${height || 130}'` | See [SVG viewBox](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox) attribute |
| preserveAspectRatio | string | `'xMidYMid meet'` | See [SVG preserveAspectRatio](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio) attribute |
| speed | number | `2` | Animation speed |
| primaryColor | string | `'#f9f9f9'` | Background color |
| secondaryColor | string | `'#ecebeb'` | Highlight color |
| uniqueKey | string | `randomId()` | Unique ID, you need to make it consistent for SSR |
| animate | boolean | `true` | |
| baseUrl | string | empty string | Required if you're using `<base url="/" />` in your `<head />`. Defaults to an empty string. This prop is common used as: `<content-loader :base-url="$route.fullPath" />` which will fill the SVG attribute with the relative path. Related [#14](https://github.com/egoist/vue-content-loader/issues/14). |
| primaryOpacity | number | `1` | Background opacity (0 = transparent, 1 = opaque) used to solve an issue in Safari |
| secondaryOpacity | number | `1` | Background opacity (0 = transparent, 1 = opaque) used to solve an issue in Safari |

## Examples

### Responsiveness

To create a responsive loader that will follow its parent container width, use only the `viewBox` attribute to set the ratio:

```vue
<ContentLoader viewBox="0 0 300 200">
<!-- ... -->
</ContentLoader>
```

To create a loader with fixed dimensions, use `width` and `height` attributes:

```vue
<ContentLoader width="300" height="200">
<!-- ... -->
</ContentLoader>
```

Note: the exact behavior might be different depending on the CSS you apply to SVG elements.

## Credits

Expand Down
38 changes: 19 additions & 19 deletions src/ContentLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,22 @@ export default defineComponent({

props: {
width: {
type: [Number, String],
default: 400
type: [Number, String]
},
height: {
type: [Number, String],
default: 130
type: [Number, String]
},
speed: {
type: Number,
default: 2
viewBox: {
type: String
},
preserveAspectRatio: {
type: String,
default: 'xMidYMid meet'
},
speed: {
type: Number,
default: 2
},
baseUrl: {
type: String,
default: ''
Expand Down Expand Up @@ -53,17 +54,23 @@ export default defineComponent({
setup(props) {
const idClip = props.uniqueKey ? `${props.uniqueKey}-idClip` : uid()
const idGradient = props.uniqueKey ? `${props.uniqueKey}-idGradient` : uid()
const width = props.width ?? 400
const height = props.height ?? 130
const computedViewBox = props.viewBox ?? `0 0 ${width} ${height}`

return {
idClip,
idGradient
idGradient,
computedViewBox
}
},

render() {
return (
<svg
viewBox={`0 0 ${this.width} ${this.height}`}
width={this.width}
height={this.height}
viewBox={this.computedViewBox}
version="1.1"
preserveAspectRatio={this.preserveAspectRatio}
>
Expand All @@ -72,23 +79,16 @@ export default defineComponent({
clip-path={`url(${this.baseUrl}#${this.idClip})`}
x="0"
y="0"
width={this.width}
height={this.height}
width="100%"
height="100%"
/>

<defs>
<clipPath id={this.idClip}>
{this.$slots.default ? (
this.$slots.default()
) : (
<rect
x="0"
y="0"
rx="5"
ry="5"
width={this.width}
height={this.height}
/>
<rect x="0" y="0" rx="5" ry="5" width="100%" height="100%" />
)}
</clipPath>

Expand Down
17 changes: 11 additions & 6 deletions src/ContentLoader.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ describe('ContentLoader', () => {
it('has default values for props', () => {
const wrapper = mount(ContentLoader)

expect(wrapper.vm.width).toBe(400)
expect(wrapper.vm.height).toBe(130)
expect(wrapper.vm.width).toBe(undefined)
expect(wrapper.vm.height).toBe(undefined)
expect(wrapper.vm.speed).toBe(2)
expect(wrapper.vm.preserveAspectRatio).toBe('xMidYMid meet')
expect(wrapper.vm.baseUrl).toBe('')
expect(wrapper.vm.primaryColor).toBe('#f9f9f9')
expect(wrapper.vm.secondaryColor).toBe('#ecebeb')
expect(wrapper.vm.primaryOpacity).toBe(1)
expect(wrapper.vm.secondaryOpacity).toBe(1)
expect(wrapper.vm.uniqueKey).toBe(undefined)
expect(wrapper.vm.animate).toBe(true)
})

Expand All @@ -27,6 +28,8 @@ describe('ContentLoader', () => {
})

expect(wrapper.find('svg').attributes()).toEqual({
width: '300',
height: '200',
preserveAspectRatio: 'xMaxYMid slice',
version: '1.1',
viewBox: '0 0 300 200'
Expand All @@ -43,6 +46,8 @@ describe('ContentLoader', () => {
})

expect(wrapper.find('svg').attributes()).toEqual({
width: '300',
height: '200',
preserveAspectRatio: 'xMaxYMid slice',
version: '1.1',
viewBox: '0 0 300 200'
Expand All @@ -57,8 +62,8 @@ describe('ContentLoader', () => {
'clip-path': `url(#${wrapper.vm.idClip})`,
x: '0',
y: '0',
width: '400',
height: '130'
width: '100%',
height: '100%'
})
})

Expand Down Expand Up @@ -143,8 +148,8 @@ describe('ContentLoader', () => {
y: '0',
rx: '5',
ry: '5',
width: '400',
height: '130'
width: '100%',
height: '100%'
})
})

Expand Down
2 changes: 1 addition & 1 deletion src/InstagramLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import ContentLoader from './ContentLoader'

const InstagramLoader = (props, { attrs }) => {
return (
<ContentLoader {...attrs} height={480}>
<ContentLoader {...attrs} viewBox="0 0 400 480">
<circle cx="30" cy="30" r="30" />

<rect x="75" y="13" rx="4" ry="4" width="100" height="13" />
Expand Down
21 changes: 20 additions & 1 deletion stories/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,26 @@ section
render() {
return (
<Container>
<ContentLoader width={400} height={150} />
<ContentLoader width={200} height={100} />
</Container>
)
}
}
})
.addStory({
title: 'custom viewBox',
component: {
render() {
return (
<Container>
<ContentLoader viewBox="0 0 250 110">
<rect x="0" y="0" rx="3" ry="3" width="250" height="10" />
<rect x="20" y="20" rx="3" ry="3" width="220" height="10" />
<rect x="20" y="40" rx="3" ry="3" width="170" height="10" />
<rect x="0" y="60" rx="3" ry="3" width="250" height="10" />
<rect x="20" y="80" rx="3" ry="3" width="200" height="10" />
<rect x="20" y="100" rx="3" ry="3" width="80" height="10" />
</ContentLoader>
</Container>
)
}
Expand Down

0 comments on commit 8e844cf

Please sign in to comment.