diff --git a/src/hooks/useHasFocus/useHasFocus.test.tsx b/src/hooks/useHasFocus/useHasFocus.test.tsx
index f5bfed7..d780188 100644
--- a/src/hooks/useHasFocus/useHasFocus.test.tsx
+++ b/src/hooks/useHasFocus/useHasFocus.test.tsx
@@ -1,6 +1,6 @@
/* eslint-disable react/jsx-no-literals */
/* eslint-disable react/no-multi-comp */
-import { act, render, waitFor } from '@testing-library/react';
+import { act, render } from '@testing-library/react';
import { useRef, type ReactElement } from 'react';
import { useHasFocus } from './useHasFocus.js';
diff --git a/src/index.ts b/src/index.ts
index 4670f9f..402a77a 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -18,3 +18,4 @@ export * from './hooks/useToggle/useToggle.js';
export * from './hooks/useUnmount/useUnmount.js';
export * from './hooks/useWindowEventListener/useWindowEventListener.js';
export * from './utils/arrayRef/arrayRef.js';
+export * from './utils/objectFit/objectFit.js';
diff --git a/src/utils/objectFit/objectFit.mdx b/src/utils/objectFit/objectFit.mdx
new file mode 100644
index 0000000..1a31acf
--- /dev/null
+++ b/src/utils/objectFit/objectFit.mdx
@@ -0,0 +1,155 @@
+import { Meta } from '@storybook/blocks';
+
+
+
+# objectFit
+
+This util mimics the CSS property `object-fit` for all HTML elements;
+
+It exports two reusable methods: `contain` and `cover`. Given the sizes of an parent element and its
+child element: Contain returns the size to be applied to the element to let it fits its parent and
+keeping its apect ratio. Cover returns the size to be applied to the element to let it fill its
+parent, keeping its aspect ratio, most likely overflowing the parent element.
+
+If the sizes or aspect ratio are initially known, it's better to use values instead of retrieving
+sizes from an image because its faster from a performance perspective.
+
+## Reference
+
+```ts
+function objectFit(fit: 'contain' | 'cover') {
+ return (
+ parentWidth: number,
+ parentHeight: number,
+ childWidth: number,
+ childHeight: number,
+ ): { x: number; y: number; width: number; height: number; scale: number; cssText: string } => {
+ if ([parentWidth, parentHeight, childWidth, childHeight].some((value) => value <= 0)) {
+ throw new Error(`All arguments should have a positive value`);
+ }
+
+ const mathMethod = fit === 'contain' ? Math.min : Math.max;
+ const scale = mathMethod(parentWidth / childWidth, parentHeight / childHeight);
+ const width = Math.ceil(childWidth * scale);
+ const height = Math.ceil(childHeight * scale);
+ const x = Math.trunc((parentWidth - width) * 0.5);
+ const y = Math.trunc((parentHeight - height) * 0.5);
+
+ return {
+ x,
+ y,
+ width,
+ height,
+ scale,
+ cssText: `left:${x}px;top:${y}px;width:${width}px;height:${height}px;`,
+ };
+ };
+}
+
+export const contain = objectFit('contain');
+export const cover = objectFit('cover');
+```
+
+### Parameters
+
+- parentWidth: number
+- parentHeight: number
+- childWidth: number
+- childHeight: number
+
+### Returns
+
+An object containing:
+
+- x: number
+- y: number
+- width: number
+- height: number
+- scale: number
+- cssText: string (easily add CSS values to child element)
+
+## Usage
+
+Contain:
+
+With the contain method you can use both position absolute and relative on the child element.
+Relative can be useful if you want to position elements inside absolute to the parent.
+
+```tsx
+import { contain } from './objectFit.js';
+
+export function Contain(): ReactElement {
+ const parentRef = useRef(null);
+ const childRef = useRef(null);
+
+ const onResize = useCallback(() => {
+ if (!parentRef.current || !childRef.current) {
+ return;
+ }
+
+ const objectFit = contain(parentRef.current.offsetWidth, parentRef.current.offsetHeight, 1, 1);
+
+ childRef.current.style.cssText += objectFit.cssText;
+ }, [parentRef, childRef]);
+
+ useResizeObserver(parentRef, onResize);
+
+ return (
+
+ );
+}
+```
+
+Cover:
+
+With contain you need to use position absolute to position the child.
+
+```tsx
+import { cover } from './objectFit.js';
+
+export function Cover(): ReactElement {
+ const parentRef = useRef(null);
+ const childRef = useRef(null);
+
+ const onResize = useCallback(() => {
+ if (!parentRef.current || !childRef.current) {
+ return;
+ }
+
+ const objectFit = cover(
+ parentRef.current.offsetWidth,
+ parentRef.current.offsetHeight,
+ 1920,
+ 1080,
+ );
+
+ childRef.current.style.cssText += objectFit.cssText;
+ }, [parentRef, childRef]);
+
+ useResizeObserver(parentRef, onResize);
+
+ return (
+
+ );
+}
+```
diff --git a/src/utils/objectFit/objectFit.stories.tsx b/src/utils/objectFit/objectFit.stories.tsx
new file mode 100644
index 0000000..86a8f00
--- /dev/null
+++ b/src/utils/objectFit/objectFit.stories.tsx
@@ -0,0 +1,101 @@
+/* eslint-disable react/no-multi-comp */
+import { type ReactElement, useCallback, useRef } from 'react';
+import { useResizeObserver } from '../../hooks/useResizeObserver/useResizeObserver.js';
+import { contain, cover } from './objectFit.js';
+
+export default {
+ title: 'utils/objectFit',
+};
+
+export function Contain(): ReactElement {
+ const parentRef = useRef(null);
+ const childRef = useRef(null);
+ const infoRef = useRef(null);
+
+ const onResize = useCallback(() => {
+ if (!parentRef.current || !childRef.current || !infoRef.current) {
+ return;
+ }
+
+ const objectFit = contain(parentRef.current.offsetWidth, parentRef.current.offsetHeight, 1, 1);
+ childRef.current.style.cssText += objectFit.cssText;
+
+ infoRef.current.innerHTML = JSON.stringify(objectFit);
+ }, [parentRef, childRef, infoRef]);
+
+ useResizeObserver(parentRef, onResize);
+
+ return (
+
+
+
+
+
+
+ );
+}
+
+export function Cover(): ReactElement {
+ const parentRef = useRef(null);
+ const childRef = useRef(null);
+ const infoRef = useRef(null);
+ const demoRef = useRef(null);
+
+ const onResize = useCallback(() => {
+ if (!parentRef.current || !childRef.current || !infoRef.current || !demoRef.current) {
+ return;
+ }
+
+ const objectFit = cover(
+ parentRef.current.offsetWidth,
+ parentRef.current.offsetHeight,
+ childRef.current.naturalWidth,
+ childRef.current.naturalHeight,
+ );
+ childRef.current.style.cssText += objectFit.cssText;
+
+ infoRef.current.innerHTML = JSON.stringify(objectFit);
+ // Using a second image to show the overflowing from the child element on the parent element because the css resize property doesn't allow overflowing.
+ const size = childRef.current.getBoundingClientRect();
+ demoRef.current.style.cssText += `left:${size.left}px;width:${size.width}px;height:${size.height}px;`;
+ }, [parentRef, childRef, infoRef]);
+
+ useResizeObserver(parentRef, onResize);
+
+ const dataUri =
+ 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB4AAAAQ4CAIAAABnsVYUAAAszUlEQVR4nO3d21NV5/3H8b05uDeo4AHcKh4CajUiSWNr7enCNpP+Af1Pc9XOdDJNp/VQk0yamKqNh1YNoGgQAeW42b8LZ/itwSoo+xO1vF5XPA9rrf3lznnP8tnl8fHxEgAAAAAANFvL6x4AAAAAAID/TQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABECNAAAAAAAEQI0AAAAAAARAjQAAAAAABFtr3sAAABYl3q9/qc//enJkyelUun48ePHjh175Uc9ePDg7t274+Pj09PTCwsLjUZj06ZNHR0dO3furNVqtVqteVM/1+Li4r179+7du/fw4cO5ubn5+fnW1tZKpdLd3d3T07Nv375KpfIDjAEAAE1RHh8ff90zAADAq7t06dK1a9ee/vzKAXp4ePjy5ctTU1MvuKarq2toaCiXoev1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7m7uGAAA0HSO4AAAYEPr6en56KOPrl69evPmzXq9/rzLyuXy3r17T5w4sXnz5sQYe/fu/fDDD7/66qu7d+++4LJqtXrs2LH+/v6XfWMaAABeCwEaAICNrr29fWho6NixYyMjI2NjY48ePZqZmVlcXGxpaalUKlu3bu3t7e3r6wul52WbN2/+5S9/OTk5OTw8/ODBg+np6fn5+Uaj0d7e3tnZuWPHjlqtVqvVpGcAAN4i5fHx8dc9AwAAAAAA/4OcAQ0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQIQADQAAAABAhAANAAAAAECEAA0AAAAAQMT/AZN1LTqqap2hAAAAAElFTkSuQmCC';
+ return (
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/utils/objectFit/objectFit.test.ts b/src/utils/objectFit/objectFit.test.ts
new file mode 100644
index 0000000..ca84eaf
--- /dev/null
+++ b/src/utils/objectFit/objectFit.test.ts
@@ -0,0 +1,37 @@
+import { contain, cover } from './objectFit.js';
+
+describe('objectFit', () => {
+ describe('contain', () => {
+ it('returns expected values for positive input arguments', () => {
+ expect(contain(100, 100, 50, 50)).toEqual({
+ x: 0,
+ y: 0,
+ width: 100,
+ height: 100,
+ scale: 2,
+ cssText: 'left:0px;top:0px;width:100px;height:100px;',
+ });
+ });
+
+ it('throws an error for non-positive input arguments', () => {
+ expect(() => contain(1, 1, 1, 0)).toThrow('All arguments should have a positive value');
+ });
+ });
+
+ describe('cover', () => {
+ it('returns expected values for positive input arguments', () => {
+ expect(cover(100, 100, 50, 50)).toEqual({
+ x: 0,
+ y: 0,
+ width: 100,
+ height: 100,
+ scale: 2,
+ cssText: 'left:0px;top:0px;width:100px;height:100px;',
+ });
+ });
+
+ it('throws an error for non-positive input arguments', () => {
+ expect(() => cover(1, 1, -1, 1)).toThrow('All arguments should have a positive value');
+ });
+ });
+});
diff --git a/src/utils/objectFit/objectFit.ts b/src/utils/objectFit/objectFit.ts
new file mode 100644
index 0000000..e40178f
--- /dev/null
+++ b/src/utils/objectFit/objectFit.ts
@@ -0,0 +1,31 @@
+function objectFit(fit: 'contain' | 'cover') {
+ return (
+ parentWidth: number,
+ parentHeight: number,
+ childWidth: number,
+ childHeight: number,
+ ): { x: number; y: number; width: number; height: number; scale: number; cssText: string } => {
+ if ([parentWidth, parentHeight, childWidth, childHeight].some((value) => value <= 0)) {
+ throw new Error(`All arguments should have a positive value`);
+ }
+
+ const mathMethod = fit === 'contain' ? Math.min : Math.max;
+ const scale = mathMethod(parentWidth / childWidth, parentHeight / childHeight);
+ const width = Math.ceil(childWidth * scale);
+ const height = Math.ceil(childHeight * scale);
+ const x = Math.trunc((parentWidth - width) * 0.5);
+ const y = Math.trunc((parentHeight - height) * 0.5);
+
+ return {
+ x,
+ y,
+ width,
+ height,
+ scale,
+ cssText: `left:${x}px;top:${y}px;width:${width}px;height:${height}px;`,
+ };
+ };
+}
+
+export const contain = objectFit('contain');
+export const cover = objectFit('cover');