add responsive media component; fixes #436

pull/463/head
Cory LaViska 2021-05-04 09:51:16 -04:00
rodzic 86fc6b85d6
commit 5c619b87b6
9 zmienionych plików z 125 dodań i 94 usunięć

Wyświetl plik

@ -38,7 +38,6 @@
- [Radio Group](/components/radio-group.md)
- [Range](/components/range.md)
- [Rating](/components/rating.md)
- [Responsive Embed](/components/responsive-embed.md)
- [Select](/components/select.md)
- [Skeleton](/components/skeleton.md)
- [Spinner](/components/spinner.md)
@ -59,6 +58,7 @@
- [QR Code](/components/qr-code.md)
- [Relative Time](/components/relative-time.md)
- [Resize Observer](/components/resize-observer.md)
- [Responsive Media](/components/responsive-media.md)
- Design Tokens
- [Typography](/tokens/typography.md)

Wyświetl plik

@ -1,27 +0,0 @@
# Responsive Embed
[component-header:sl-responsive-embed]
Displays embedded media in a responsive manner based on its aspect ratio.
You can embed any element of the `<iframe>`, `<embed>`, or `<object>` type. The default aspect ratio is `16:9`.
```html preview
<sl-responsive-embed>
<iframe src="https://player.vimeo.com/video/1053647?title=0&byline=0&portrait=0" frameborder="0" allow="autoplay; fullscreen" allowfullscreen></iframe>
</sl-responsive-embed>
```
## Examples
### Aspect Ratio
To set the aspect ratio, use the `aspect-ratio` attribute.
```html preview
<sl-responsive-embed aspect-ratio="4:3">
<iframe src="https://www.youtube.com/embed/mM5_T-F1Yn4" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</sl-responsive-embed>
```
[component-metadata:sl-responsive-embed]

Wyświetl plik

@ -0,0 +1,37 @@
# Responsive Media
[component-header:sl-responsive-media]
Displays media in the desired aspect ratio.
You can slot in any [replaced element](https://developer.mozilla.org/en-US/docs/Web/CSS/Replaced_element), including `<iframe>`, `<img>`, and `<video>`. As the element's width changes, its height will resize proportionally. Only one element should be slotted into the container. The default aspect ratio is `16:9`.
```html preview
<sl-responsive-media>
<img src="https://images.unsplash.com/photo-1541427468627-a89a96e5ca1d?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1800&q=80" alt="A train riding through autumn foliage with mountains in the distance.">
</sl-responsive-media>
```
## Examples
### Responsive Images
The following image maintains a `4:3` aspect ratio as its container is resized.
```html preview
<sl-responsive-media aspect-ratio="4:3">
<img src="https://images.unsplash.com/photo-1473186578172-c141e6798cf4?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1800&q=80" alt="Two blue chairs on a sandy beach.">
</sl-responsive-media>
```
### Responsive Videos
The following video is embedded using an `iframe` and maintains a `16:9` aspect ratio as its container is resized.
```html preview
<sl-responsive-media aspect-ratio="16:9">
<iframe src="https://player.vimeo.com/video/1053647?title=0&byline=0&portrait=0" frameborder="0" allow="autoplay; fullscreen" allowfullscreen></iframe>
</sl-responsive-media>
```
[component-metadata:sl-responsive-media]

Wyświetl plik

@ -8,6 +8,7 @@ _During the beta period, these restrictions may be relaxed in the event of a mis
## Next
- 🚨 BREAKING: renamed `sl-responsive-embed` to `sl-responsive-media` and added support for images and videos [#436](https://github.com/shoelace-style/shoelace/issues/436)
- Fixed a bug where setting properties before an element was defined would render incorrectly [#425](https://github.com/shoelace-style/shoelace/issues/425)
- Fixed a bug that caused all modules to be imported when cherry picking certain components [#439](https://github.com/shoelace-style/shoelace/issues/439)
- Improved a11y in `sl-progress-ring`

Wyświetl plik

@ -1,19 +0,0 @@
@use '../../styles/component';
:host {
display: block;
}
.responsive-embed {
position: relative;
::slotted(embed),
::slotted(iframe),
::slotted(object) {
position: absolute !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
}
}

Wyświetl plik

@ -1,46 +0,0 @@
import { LitElement, html, unsafeCSS } from 'lit';
import { customElement, property, query } from 'lit/decorators';
import { watch } from '../../internal/decorators';
import styles from 'sass:./responsive-embed.scss';
/**
* @since 2.0
* @status stable
*
* @part base - The component's base wrapper.
*/
@customElement('sl-responsive-embed')
export default class SlResponsiveEmbed extends LitElement {
static styles = unsafeCSS(styles);
@query('.responsive-embed') base: HTMLElement;
/**
* The aspect ratio of the embedded media in the format of `width:height`, e.g. `16:9`, `4:3`, or `1:1`. Ratios not in
* this format will be ignored.
*/
@property({ attribute: 'aspect-ratio' }) aspectRatio = '16:9';
@watch('aspectRatio')
updateAspectRatio() {
const split = this.aspectRatio.split(':');
const x = parseInt(split[0]);
const y = parseInt(split[1]);
this.base.style.paddingBottom = x && y ? `${(y / x) * 100}%` : '';
}
render() {
return html`
<div part="base" class="responsive-embed">
<slot @slotchange=${() => this.updateAspectRatio()}></slot>
</div>
`;
}
}
declare global {
interface HTMLElementTagNameMap {
'sl-responsive-embed': SlResponsiveEmbed;
}
}

Wyświetl plik

@ -0,0 +1,35 @@
@use '../../styles/component';
:host {
display: block;
}
.responsive-media {
position: relative;
::slotted(*) {
position: absolute !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
}
}
.responsive-media--cover {
::slotted(embed),
::slotted(iframe),
::slotted(img),
::slotted(video) {
object-fit: cover !important;
}
}
.responsive-media--contain {
::slotted(embed),
::slotted(iframe),
::slotted(img),
::slotted(video) {
object-fit: contain !important;
}
}

Wyświetl plik

@ -0,0 +1,50 @@
import { LitElement, html, unsafeCSS } from 'lit';
import { customElement, property } from 'lit/decorators';
import { classMap } from 'lit-html/directives/class-map';
import styles from 'sass:./responsive-media.scss';
/**
* @since 2.0
* @status stable
*
* @slot - The element to receive the aspect ratio. Should be a replaced element, such as `<img>`, `<iframe>`, or `<video>`.
*/
@customElement('sl-responsive-media')
export default class SlResponsiveMedia extends LitElement {
static styles = unsafeCSS(styles);
/**
* The aspect ratio of the embedded media in the format of `width:height`, e.g. `16:9`, `4:3`, or `1:1`. Ratios not in
* this format will be ignored.
*/
@property({ attribute: 'aspect-ratio' }) aspectRatio = '16:9';
/** Determines how content will be resized to fit its container. */
@property() fit: 'cover' | 'contain' = 'cover';
render() {
const split = this.aspectRatio.split(':');
const x = parseInt(split[0]);
const y = parseInt(split[1]);
const paddingBottom = x && y ? `${(y / x) * 100}%` : '0';
return html`
<div
class=${classMap({
'responsive-media': true,
'responsive-media--cover': this.fit === 'cover',
'responsive-media--contain': this.fit === 'contain'
})}
style="padding-bottom: ${paddingBottom}"
>
<slot></slot>
</div>
`;
}
}
declare global {
interface HTMLElementTagNameMap {
'sl-responsive-media': SlResponsiveMedia;
}
}

Wyświetl plik

@ -35,7 +35,7 @@ export { default as SlRange } from './components/range/range';
export { default as SlRating } from './components/rating/rating';
export { default as SlRelativeTime } from './components/relative-time/relative-time';
export { default as SlResizeObserver } from './components/resize-observer/resize-observer';
export { default as SlResponsiveEmbed } from './components/responsive-embed/responsive-embed';
export { default as SlResponsiveMedia } from './components/responsive-media/responsive-media';
export { default as SlSelect } from './components/select/select';
export { default as SlSkeleton } from './components/skeleton/skeleton';
export { default as SlSpinner } from './components/spinner/spinner';