UNPKG

@hypothesis/frontend-shared

Version:

Shared components, styles and utilities for Hypothesis projects

62 lines 2.54 kB
var _jsxFileName = "/home/runner/work/frontend-shared/frontend-shared/src/components/data/AspectRatio.tsx"; import classnames from 'classnames'; import { cloneElement, toChildArray } from 'preact'; import { jsxDEV as _jsxDEV } from "preact/jsx-dev-runtime"; /** * Render a wrapper element that constrains its first direct child to the * specified `ratio`. * * This component relies upon the old-fashioned "bottom-padding hack" to * constrain content until such a time as the browser support for `aspect-ratio` * is sufficient. * * In this model, proportional bottom padding is applied to a * relatively-positioned, full-width container, while the content element itself * is absolute-positioned with respect to the container. * * See https://www.smashingmagazine.com/2013/09/responsive-images-performance-problem-case-study/#the-padding-bottom-hack */ export default function AspectRatio({ children, objectFit = 'cover', ratio = '16/9' }) { // Find the first vNode. This is the element that will be constrained to the // aspect ratio. Typically, this is either: // - a "replaceable element", e.g. image or video (media), or // - a block element, e.g. a div that contains placeholder content. In this // case, content within this node will be centered horizontally and // vertically. const childNodes = toChildArray(children); const firstChildNode = childNodes.find(child => typeof child === 'object'); const otherChildren = firstChildNode ? childNodes.filter(child => child !== firstChildNode) : children; const mediaClasses = classnames( // Position the element box relative to its container 'absolute w-full h-full top-0 left-0', // Center any children horizontally and vertically 'flex items-center justify-center', { 'object-cover': objectFit === 'cover', // default 'object-contain': objectFit === 'contain', 'object-fill': objectFit === 'fill', 'object-scale-down': objectFit === 'scale-down', 'object-none': objectFit === 'none' }); return _jsxDEV("div", { className: "w-full h-0 relative overflow-hidden", "data-component": "AspectRatio", style: { paddingBottom: `calc(100% / (${ratio}))` }, children: [firstChildNode && cloneElement(firstChildNode, { class: classnames(mediaClasses, // Retain existing classes firstChildNode.props.className) }), otherChildren] }, void 0, true, { fileName: _jsxFileName, lineNumber: 64, columnNumber: 5 }, this); } //# sourceMappingURL=AspectRatio.js.map