+ );
+};
+
+type CarouselItemsProps = {
+ /** Additional CSS className for the element. */
+ children: React.ReactNode;
+ /** The components to be displayed within the carousel. */
+ className?: string;
+};
+
+type CarouselItemsContextValue = {
+ ref: React.Ref;
+ onScroll?: (event: React.UIEvent) => void;
+};
+
+const CarouselItemsContext = createContext({
+ ref: null,
+} as CarouselItemsContextValue);
+
+const CarouselItems = ({ className, children }: CarouselItemsProps) => (
+
+ {({ ref, onScroll }) => (
{
'h-full',
'rounded-[inherit]',
])}
- data-slot="carousel"
+ ref={ref}
+ // When the SnapEvent is supported: https://developer.mozilla.org/en-US/docs/Web/API/SnapEvent
+ // We can use the scrollsnapchange event to detect when the user has scrolled to a new item.
+ // We can then use Array.from(event.target.children).indexOf(event.snapTargetInline) to calculate the index of the item that is currently in view.
+ // Another option is to use the scrollEnd event, when Safiri supports it: https://developer.apple.com/documentation/webkitjs/snap_event/scrollend_event
+ onScroll={onScroll}
>
{children}
-
-
-
-
-
- );
-};
+ )}
+
+);
type CarouselItemProps = {
className?: string;
@@ -122,6 +208,8 @@ const CarouselItem = ({ className, children }: CarouselItemProps) => (
export {
Carousel as UNSAFE_Carousel,
CarouselItem as UNSAFE_CarouselItem,
+ CarouselItems as UNSAFE_CarouselItems,
+ type CarouselItemsProps as UNSAFE_CarouselItemsProps,
type CarouselItemProps as UNSAFE_CarouselItemProps,
type CarouselProps as UNSAFE_CarouselProps,
};
diff --git a/packages/react/src/hero/hero.stories.tsx b/packages/react/src/hero/hero.stories.tsx
index d86850595..e80ca11ab 100644
--- a/packages/react/src/hero/hero.stories.tsx
+++ b/packages/react/src/hero/hero.stories.tsx
@@ -3,14 +3,15 @@ import type { Meta, StoryObj } from '@storybook/react';
import { Group } from 'react-aria-components';
import { Badge } from '../badge';
import { Button } from '../button';
-import { Content, Heading, Media } from '../content';
-import { Description } from '../label';
-import { VideoLoop } from '../video-loop';
-import { UNSAFE_Hero as Hero } from './hero';
import {
UNSAFE_Carousel as Carousel,
UNSAFE_CarouselItem as CarouselItem,
+ UNSAFE_CarouselItems as CarouselItems,
} from '../carousel';
+import { Content, Heading, Media } from '../content';
+import { Description } from '../label';
+import { VideoLoop } from '../video-loop';
+import { UNSAFE_Hero as Hero } from './hero';
const meta: Meta = {
title: 'Hero',
@@ -33,18 +34,24 @@ const meta: Meta = {
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
@@ -125,18 +132,24 @@ export const StandardWithCarousel = () => (
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
@@ -202,31 +215,37 @@ export const FullBleedWithCarousel = () => (
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 922f35d5c..c5695eed5 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -278,6 +278,9 @@ importers:
react-stately:
specifier: ^3.35.0
version: 3.36.1(react@19.0.0)
+ use-debounce:
+ specifier: ^10.0.4
+ version: 10.0.4(react@19.0.0)
devDependencies:
tailwindcss:
specifier: 4.1.7
@@ -8841,6 +8844,12 @@ packages:
'@types/react':
optional: true
+ use-debounce@10.0.4:
+ resolution: {integrity: sha512-6Cf7Yr7Wk7Kdv77nnJMf6de4HuDE4dTxKij+RqE9rufDsI6zsbjyAxcH5y2ueJCQAnfgKbzXbZHYlkFwmBlWkw==}
+ engines: {node: '>= 16.0.0'}
+ peerDependencies:
+ react: '*'
+
use-device-pixel-ratio@1.1.2:
resolution: {integrity: sha512-nFxV0HwLdRUt20kvIgqHYZe6PK/v4mU1X8/eLsT1ti5ck0l2ob0HDRziaJPx+YWzBo6dMm4cTac3mcyk68Gh+A==}
peerDependencies:
@@ -19854,6 +19863,10 @@ snapshots:
optionalDependencies:
'@types/react': 19.0.12
+ use-debounce@10.0.4(react@19.0.0):
+ dependencies:
+ react: 19.0.0
+
use-device-pixel-ratio@1.1.2(react@19.0.0):
dependencies:
react: 19.0.0
From 30b9971eddb778ead02c115046aa9fde78ed56bd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Oscar=20Carlstr=C3=B6m?=
Date: Fri, 6 Jun 2025 12:48:00 +0200
Subject: [PATCH 06/24] Fix focus styles
---
.../react/src/carousel/carousel.stories.tsx | 14 ++--
packages/react/src/carousel/carousel.tsx | 64 +++++++++++++------
packages/react/src/hero/hero.stories.tsx | 13 ++++
packages/react/src/hero/hero.tsx | 4 +-
packages/react/src/video-loop/video-loop.tsx | 1 +
5 files changed, 72 insertions(+), 24 deletions(-)
diff --git a/packages/react/src/carousel/carousel.stories.tsx b/packages/react/src/carousel/carousel.stories.tsx
index f1ab5dabd..b5ade6dfd 100644
--- a/packages/react/src/carousel/carousel.stories.tsx
+++ b/packages/react/src/carousel/carousel.stories.tsx
@@ -6,7 +6,6 @@ import {
UNSAFE_CarouselItem as CarouselItem,
UNSAFE_CarouselItems as CarouselItems,
} from '../carousel';
-import { VideoLoop } from '../video-loop';
const meta: Meta = {
title: 'Carousel',
@@ -26,10 +25,15 @@ const meta: Meta = {
/>
-
+
+
+
diff --git a/packages/react/src/carousel/carousel.tsx b/packages/react/src/carousel/carousel.tsx
index 74e016c84..13233a640 100644
--- a/packages/react/src/carousel/carousel.tsx
+++ b/packages/react/src/carousel/carousel.tsx
@@ -1,4 +1,4 @@
-import { cx } from 'cva';
+import { cva, cx, type VariantProps } from 'cva';
import { createContext, useEffect, useRef, useState } from 'react';
import { ButtonContext } from '../button';
import { useLocale } from '../use-locale';
@@ -70,7 +70,18 @@ const Carousel = ({ className, children }: CarouselProps) => {
);
return (
-
From bdf6e655c49accd4a31ce3389ab338a2ff40cef5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Oscar=20Carlstr=C3=B6m?=
Date: Tue, 10 Jun 2025 14:22:32 +0200
Subject: [PATCH 17/24] Refactor Carousel API
---
.../react/src/carousel/carousel.stories.tsx | 43 +++---
packages/react/src/carousel/carousel.tsx | 140 +++++++++---------
packages/react/src/content/content.tsx | 47 +++++-
packages/react/src/hero/hero.stories.tsx | 90 ++++++-----
packages/react/src/hero/hero.tsx | 12 +-
5 files changed, 201 insertions(+), 131 deletions(-)
diff --git a/packages/react/src/carousel/carousel.stories.tsx b/packages/react/src/carousel/carousel.stories.tsx
index 7375c2e4b..95bf9485e 100644
--- a/packages/react/src/carousel/carousel.stories.tsx
+++ b/packages/react/src/carousel/carousel.stories.tsx
@@ -4,6 +4,7 @@ import {
UNSAFE_CarouselItem as CarouselItem,
UNSAFE_CarouselItems as CarouselItems,
} from '../carousel';
+import { Media } from '../content';
const meta: Meta = {
title: 'Carousel',
@@ -17,28 +18,36 @@ const meta: Meta = {
-
+
+
+
-
+
+
+
-
-
+
+
+
+
-
+
+
+
diff --git a/packages/react/src/carousel/carousel.tsx b/packages/react/src/carousel/carousel.tsx
index 1f6ea02bb..ebc119a0c 100644
--- a/packages/react/src/carousel/carousel.tsx
+++ b/packages/react/src/carousel/carousel.tsx
@@ -1,12 +1,13 @@
import { ChevronLeft, ChevronRight } from '@obosbbl/grunnmuren-icons-react';
import { useUpdateEffect } from '@react-aria/utils';
-import { type VariantProps, cva, cx } from 'cva';
+import { cx } from 'cva';
import { createContext, useEffect, useRef, useState } from 'react';
import { Provider } from 'react-aria-components';
import { useDebouncedCallback } from 'use-debounce';
import { Button, ButtonContext } from '../button';
import { translations } from '../translations';
import { useLocale } from '../use-locale';
+import { MediaContext } from '../content';
type CarouselProps = {
/** The components to be displayed within the carousel. */
@@ -70,20 +71,7 @@ const Carousel = ({ className, children }: CarouselProps) => {
);
return (
- (the scroll-snap container) or component is focused, apply custom focus styles around the carousel, this makes ensures that the focus outline is visible around the carousel in all cases
- '[&:has([data-slot="carousel-items"]:focus-visible,[data-slot="video-loop-button"]:focus-visible)]:outline-focus',
- '[&:has([data-slot="carousel-items"]:focus-visible,[data-slot="video-loop-button"]:focus-visible)]:outline-focus-offset',
- // Unset the default focus outline for potential video loop buttons, as it interferes with the custom focus styles for the carousel
- '**:data-[slot="video-loop-button"]:focus-visible:outline-none',
- // biome-ignore lint/nursery/useSortedClasses: biome is unable to sort the custom classes for 3xl and 4xl breakpoints
- 'h-70 sm:h-[25rem] lg:h-[35rem] xl:h-[40rem] 2xl:h-[42rem] 3xl:h-[48rem] 4xl:h-[53rem]',
- )}
- >
+
{
],
]}
>
- {children}
- <_CarouselControls>
-
-
-
-
-
-
-
+ (the scroll-snap container) or component is focused, apply custom focus styles around the carousel, this makes ensures that the focus outline is visible around the carousel in all cases
+ '[&:has([data-slot="carousel-items"]:focus-visible,[data-slot="video-loop-button"]:focus-visible)]:outline-focus',
+ '[&:has([data-slot="carousel-items"]:focus-visible,[data-slot="video-loop-button"]:focus-visible)]:outline-focus-offset',
+ // Unset the default focus outline for potential video loop buttons, as it interferes with the custom focus styles for the carousel
+ '**:data-[slot="video-loop-button"]:focus-visible:outline-none',
+ )}
+ >
+ {children}
+ <_CarouselControls>
+
+
+
+
+
+
+
+
{children}
@@ -202,7 +207,6 @@ const CarouselItems = ({ className, children }: CarouselItemsProps) => (
'snap-mandatory',
'overflow-x-auto',
'outline-none',
- 'h-full',
'rounded-[inherit]',
])}
ref={ref}
@@ -218,35 +222,35 @@ const CarouselItems = ({ className, children }: CarouselItemsProps) => (
);
-type CarouselItemProps = VariantProps & {
+type CarouselItemProps = {
className?: string;
children: React.ReactNode;
};
-const carouselItemVariant = cva({
- base: 'shrink-0 basis-full snap-start *:h-full *:w-full',
- variants: {
- /**
- * Control how the content should be placed with the object-fit property
- * You might for example want to use `fit="contain"` portrait images that should not be cropped
- * @default cover
- * */
- fit: {
- cover: '*:object-cover',
- contain: 'bg-blue-dark *:object-contain',
- },
- },
- defaultVariants: {
- fit: 'cover',
- },
-});
-
-const CarouselItem = ({ fit, className, children }: CarouselItemProps) => {
- const _className = carouselItemVariant({ fit });
-
+const CarouselItem = ({ className, children }: CarouselItemProps) => {
return (
-
- {children}
+
+
+ {children}
+
);
};
diff --git a/packages/react/src/content/content.tsx b/packages/react/src/content/content.tsx
index 271e52ea8..78d697f82 100644
--- a/packages/react/src/content/content.tsx
+++ b/packages/react/src/content/content.tsx
@@ -85,11 +85,49 @@ const Content = ({ ref = null, ...props }: ContentProps) => {
return outerWrapper ? outerWrapper(content) : content;
};
-type MediaProps = HTMLProps & {
- children: React.ReactNode;
-};
+type MediaProps = HTMLProps &
+ VariantProps & {
+ children: React.ReactNode;
+ /** Ref for the element. */
+ ref?: Ref;
+ };
+
+const mediaVariant = cva({
+ variants: {
+ /**
+ * Control how the content should be placed with the object-fit property
+ * You might for example want to use `fit="contain"` portrait images that should not be cropped
+ * @default cover
+ * */
+ fit: {
+ cover: '*:object-cover',
+ contain: '*:object-contain',
+ },
+ },
+});
-const Media = (props: MediaProps) => ;
+const MediaContext = createContext<
+ ContextValue, HTMLDivElement>
+>({});
+
+const Media = ({ ref = null, ...props }: MediaProps) => {
+ [props, ref] = useContextProps(props, ref, MediaContext);
+
+ const { className, fit, ...restProps } = props;
+
+ const _className = mediaVariant({
+ fit,
+ });
+
+ return (
+
+ );
+};
type FooterProps = HTMLProps & {
children: React.ReactNode;
@@ -117,6 +155,7 @@ export {
Heading,
HeadingContext,
Media,
+ MediaContext,
type CaptionProps,
type ContentProps,
type FooterProps,
diff --git a/packages/react/src/hero/hero.stories.tsx b/packages/react/src/hero/hero.stories.tsx
index d7827fa6a..a3dbbc4a7 100644
--- a/packages/react/src/hero/hero.stories.tsx
+++ b/packages/react/src/hero/hero.stories.tsx
@@ -32,24 +32,26 @@ const meta: Meta = {
personer som vil ta OBOS videre. Søk på våre ledige stillinger!
-
-
-
-
+
+
+
+
-
-
+
+
+
+
-
-
-
-
+
+
+
+
),
@@ -126,31 +128,35 @@ export const StandardWithCarousel = () => (
OBOS-butikken– din lokale OBOS-butikk i Oslo sentrum
-
-
-
-
+
+
+
+
-
-
+
+
+
+
-
-
+
+
+
+
-
-
-
-
+
+
+
+
);
@@ -212,45 +218,53 @@ export const FullBleedWithCarousel = () => (
Ulven– et nytt nabolag i Oslo
-
-
-
+
+
+
-
+
-
+
-
+
+
+
-
-
+
+
+
+
-
-
+
+
+
+
-
-
+
+
+
+
-
-
-
-
+
+
+
+
);
diff --git a/packages/react/src/hero/hero.tsx b/packages/react/src/hero/hero.tsx
index a1e918ca6..e411ee00f 100644
--- a/packages/react/src/hero/hero.tsx
+++ b/packages/react/src/hero/hero.tsx
@@ -19,9 +19,10 @@ const oneColumnLayout = [
// Make sure other elements than and (i.e CTA) does not span the full width on small screens
'*:not-data-[slot="content"]:not-data-[slot="media"]:w-fit',
// Other elements than and (e.g. CTA, SVG logo or Badge) take up 3 columns on medium screens and above, and are right aligned
- 'lg:*:not-data-[slot="content"]:not-data-[slot="media"]:col-span-3 lg:*:not-data-[slot="content"]:not-data-[slot="media"]:justify-self-end',
+ 'lg:*:not-data-[slot="content"]:not-data-[slot="media"]:not-data-[slot="carousel"]:col-span-3 lg:*:not-data-[slot="content"]:not-data-[slot="media"]:justify-self-end',
// content takes up the full width on medium screens and above
'lg:*:data-[slot="media"]:col-span-full *:data-[slot="media"]:*:w-full',
+ 'lg:*:data-[slot="carousel"]:col-span-full *:data-[slot="carousel"]:*:w-full',
// Aligns and any element beside it (e.g. , , etc.) to the bottom of the container
'lg:items-end',
];
@@ -37,6 +38,7 @@ const variants = cva({
// Vertical spacing in the
'*:data-[slot="content"]:gap-y-3',
// Make sure content fills any available vertical and horizontal space
+ // TODO move to context
'*:data-[slot="media"]:*:object-cover',
],
variants: {
@@ -49,14 +51,16 @@ const variants = cva({
'full-bleed': [
oneColumnLayout,
// biome-ignore lint/nursery/useSortedClasses: biome is unable to sort the custom classes for 3xl and 4xl breakpoints
- '*:data-[slot="media"]:h-70 sm:*:data-[slot="media"]:h-[25rem] lg:*:data-[slot="media"]:h-[30rem] lg:*:data-[slot="media"]:h-[35rem] xl:*:data-[slot="media"]:h-[40rem] 2xl:*:data-[slot="media"]:h-[42rem] 3xl:*:data-[slot="media"]:h-[48rem] 4xl:*:data-[slot="media"]:h-[53rem]',
+ '*:data-[slot="media"]:h-70 sm:*:data-[slot="media"]:h-[25rem] lg:*:data-[slot="media"]:h-[35rem] xl:*:data-[slot="media"]:h-[40rem] 2xl:*:data-[slot="media"]:h-[42rem] 3xl:*:data-[slot="media"]:h-[48rem] 4xl:*:data-[slot="media"]:h-[53rem]',
// Match the heights of the wrapper for the Media content (e.g. image, VideoLoop, video etc.)
// biome-ignore lint/nursery/useSortedClasses: biome is unable to sort the custom classes for 3xl and 4xl breakpoints
'*:data-[slot="media"]:*:h-70 sm:*:data-[slot="media"]:*:h-[25rem] lg:*:data-[slot="media"]:*:h-[35rem] xl:*:data-[slot="media"]:*:h-[40rem] 2xl:*:data-[slot="media"]:*:h-[42rem] 3xl:*:data-[slot="media"]:*:h-[48rem] 4xl:*:data-[slot="media"]:*:h-[53rem]',
- // Position the media content to fill the entire viewport width
+ // Position the media and carousel content to fill the entire viewport width
'*:data-[slot="media"]:*:absolute *:data-[slot="media"]:*:left-0',
+ '*:data-[slot="carousel"]:*:absolute *:data-[slot="carousel"]:*:left-0',
+ '**:data-[slot="carousel-controls"]:container **:data-[slot="carousel-controls"]:right-0 **:data-[slot="carousel-controls"]:bottom-4 **:data-[slot="carousel-controls"]:left-0 **:data-[slot="carousel-controls"]:justify-end',
// Override rounded corners of Carousel slots
- '**:data-[slot="carousel"]:rounded-none',
+ '*:data-[slot="carousel"]:*:rounded-none',
],
'two-column': [
'lg:items-center lg:*:col-span-6',
From adc0a25fc74112edf409606726a9a45472ba0abc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Oscar=20Carlstr=C3=B6m?=
Date: Tue, 10 Jun 2025 14:37:34 +0200
Subject: [PATCH 18/24] Remove redundant CSS classes
---
packages/react/src/hero/hero.tsx | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/packages/react/src/hero/hero.tsx b/packages/react/src/hero/hero.tsx
index e411ee00f..296d10931 100644
--- a/packages/react/src/hero/hero.tsx
+++ b/packages/react/src/hero/hero.tsx
@@ -50,11 +50,9 @@ const variants = cva({
standard: [roundedMediaCorners, oneColumnLayout],
'full-bleed': [
oneColumnLayout,
- // biome-ignore lint/nursery/useSortedClasses: biome is unable to sort the custom classes for 3xl and 4xl breakpoints
- '*:data-[slot="media"]:h-70 sm:*:data-[slot="media"]:h-[25rem] lg:*:data-[slot="media"]:h-[35rem] xl:*:data-[slot="media"]:h-[40rem] 2xl:*:data-[slot="media"]:h-[42rem] 3xl:*:data-[slot="media"]:h-[48rem] 4xl:*:data-[slot="media"]:h-[53rem]',
// Match the heights of the wrapper for the Media content (e.g. image, VideoLoop, video etc.)
// biome-ignore lint/nursery/useSortedClasses: biome is unable to sort the custom classes for 3xl and 4xl breakpoints
- '*:data-[slot="media"]:*:h-70 sm:*:data-[slot="media"]:*:h-[25rem] lg:*:data-[slot="media"]:*:h-[35rem] xl:*:data-[slot="media"]:*:h-[40rem] 2xl:*:data-[slot="media"]:*:h-[42rem] 3xl:*:data-[slot="media"]:*:h-[48rem] 4xl:*:data-[slot="media"]:*:h-[53rem]',
+ '*:data-[slot="media"]:*:h-70 sm:*:data-[slot="media"]:*:h-[25rem] md:*:data-[slot="media"]:*:h-[30rem] lg:*:data-[slot="media"]:*:h-[35rem] xl:*:data-[slot="media"]:*:h-[40rem] 2xl:*:data-[slot="media"]:*:h-[42rem] 3xl:*:data-[slot="media"]:*:h-[48rem] 4xl:*:data-[slot="media"]:*:h-[53rem]',
// Position the media and carousel content to fill the entire viewport width
'*:data-[slot="media"]:*:absolute *:data-[slot="media"]:*:left-0',
'*:data-[slot="carousel"]:*:absolute *:data-[slot="carousel"]:*:left-0',
From e4737047e2023f18aa6980d0c347b847e265b53a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Oscar=20Carlstr=C3=B6m?=
Date: Tue, 10 Jun 2025 14:38:16 +0200
Subject: [PATCH 19/24] Remove comment
---
packages/react/src/hero/hero.tsx | 1 -
1 file changed, 1 deletion(-)
diff --git a/packages/react/src/hero/hero.tsx b/packages/react/src/hero/hero.tsx
index 296d10931..134acf575 100644
--- a/packages/react/src/hero/hero.tsx
+++ b/packages/react/src/hero/hero.tsx
@@ -38,7 +38,6 @@ const variants = cva({
// Vertical spacing in the
'*:data-[slot="content"]:gap-y-3',
// Make sure content fills any available vertical and horizontal space
- // TODO move to context
'*:data-[slot="media"]:*:object-cover',
],
variants: {
From 8c0053fa560ec95090613396a17eaa4bbdf2be1c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Oscar=20Carlstr=C3=B6m?=
Date: Tue, 10 Jun 2025 14:40:07 +0200
Subject: [PATCH 20/24] Fix comment
---
packages/react/src/hero/hero.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/react/src/hero/hero.tsx b/packages/react/src/hero/hero.tsx
index 134acf575..41cf85770 100644
--- a/packages/react/src/hero/hero.tsx
+++ b/packages/react/src/hero/hero.tsx
@@ -20,7 +20,7 @@ const oneColumnLayout = [
'*:not-data-[slot="content"]:not-data-[slot="media"]:w-fit',
// Other elements than and (e.g. CTA, SVG logo or Badge) take up 3 columns on medium screens and above, and are right aligned
'lg:*:not-data-[slot="content"]:not-data-[slot="media"]:not-data-[slot="carousel"]:col-span-3 lg:*:not-data-[slot="content"]:not-data-[slot="media"]:justify-self-end',
- // content takes up the full width on medium screens and above
+ // and content takes up the full width on medium screens and above
'lg:*:data-[slot="media"]:col-span-full *:data-[slot="media"]:*:w-full',
'lg:*:data-[slot="carousel"]:col-span-full *:data-[slot="carousel"]:*:w-full',
// Aligns and any element beside it (e.g. , , etc.) to the bottom of the container
From baa0d8ab3f1f09966110ead7da38c9d40b8452bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Oscar=20Carlstr=C3=B6m?=
Date: Tue, 10 Jun 2025 14:45:41 +0200
Subject: [PATCH 21/24] Update code examples
---
.changeset/many-rocks-itch.md | 114 +++++++++++++++++++---------------
1 file changed, 65 insertions(+), 49 deletions(-)
diff --git a/.changeset/many-rocks-itch.md b/.changeset/many-rocks-itch.md
index 406cdec64..89d0486d7 100644
--- a/.changeset/many-rocks-itch.md
+++ b/.changeset/many-rocks-itch.md
@@ -12,36 +12,44 @@ New `Carousel` component that can be used for any content, all though primarily
``` tsx
-
+
+
-
-
+
+
+
+
-
+ tem>
+
// This image has a portrait aspect ratio
-
+
-
-
+
+
+
+
-
+
+
```
-Use the `fit` prop on the `` primitive to control the `object-fit` (`cover` | `contain`) behavior of the item, this is a way to prevent cropping of images in portrait format. This defaults to `cover`, so for portrait images set it to `contain`.
+Use the `fit` prop on the `` primitive to control the `object-fit` (`cover` | `contain`) behavior of the item, this is a way to prevent cropping of images in portrait format. This defaults to `cover`, so for portrait images set it to `contain`.
### In Hero
@@ -52,46 +60,54 @@ The component can also be used inside the `` component:
Ulven– et nytt nabolag i Oslo
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- // This image has a portrait aspect ratio
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ // This image has a portrait aspect ratio
+
+
+
+
+
+
+
+
+
+
+
```
From 08c0a453f9692af87df091d4ff1dd14fcf9fb850 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Oscar=20Carlstr=C3=B6m?=
Date: Tue, 10 Jun 2025 14:47:43 +0200
Subject: [PATCH 22/24] Organize imports
---
packages/react/src/carousel/carousel.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/react/src/carousel/carousel.tsx b/packages/react/src/carousel/carousel.tsx
index ebc119a0c..e40845ed1 100644
--- a/packages/react/src/carousel/carousel.tsx
+++ b/packages/react/src/carousel/carousel.tsx
@@ -5,9 +5,9 @@ import { createContext, useEffect, useRef, useState } from 'react';
import { Provider } from 'react-aria-components';
import { useDebouncedCallback } from 'use-debounce';
import { Button, ButtonContext } from '../button';
+import { MediaContext } from '../content';
import { translations } from '../translations';
import { useLocale } from '../use-locale';
-import { MediaContext } from '../content';
type CarouselProps = {
/** The components to be displayed within the carousel. */
From b4464733ae85689bea5917036f35ae653b812973 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Oscar=20Carlstr=C3=B6m?=
Date: Tue, 10 Jun 2025 14:57:58 +0200
Subject: [PATCH 23/24] Update notes
---
.changeset/many-rocks-itch.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.changeset/many-rocks-itch.md b/.changeset/many-rocks-itch.md
index 89d0486d7..672ebe6bb 100644
--- a/.changeset/many-rocks-itch.md
+++ b/.changeset/many-rocks-itch.md
@@ -49,7 +49,7 @@ New `Carousel` component that can be used for any content, all though primarily
```
-Use the `fit` prop on the `` primitive to control the `object-fit` (`cover` | `contain`) behavior of the item, this is a way to prevent cropping of images in portrait format. This defaults to `cover`, so for portrait images set it to `contain`.
+Use the `fit` prop on the `` primitive to control the `object-fit` (`cover` | `contain`) behavior of it's children, this is a way to prevent cropping of images in portrait format. This defaults to `cover`, so for portrait images set it to `contain`.
### In Hero
From 2db7498521fe682c9c944eab6f9bd830851557dc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Oscar=20Carlstr=C3=B6m?=
Date: Tue, 10 Jun 2025 15:48:44 +0200
Subject: [PATCH 24/24] Only apply bg color to object-contain images
---
packages/react/src/carousel/carousel.tsx | 2 +-
packages/react/src/content/content.tsx | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/carousel/carousel.tsx b/packages/react/src/carousel/carousel.tsx
index e40845ed1..e2f25fe13 100644
--- a/packages/react/src/carousel/carousel.tsx
+++ b/packages/react/src/carousel/carousel.tsx
@@ -240,7 +240,7 @@ const CarouselItem = ({ className, children }: CarouselItemProps) => {
{
fit: 'cover',
className: cx(
- 'bg-blue-dark',
+ 'data-[fit="contain"]:bg-blue-dark',
'*:w-full',
// biome-ignore lint/nursery/useSortedClasses: biome is unable to sort the custom classes for 3xl and 4xl breakpoints
'*:h-70 sm:*:h-[25rem] lg:*:h-[35rem] xl:*:h-[40rem] 2xl:*:h-[42rem] 3xl:*:h-[48rem] 4xl:*:h-[53rem]',
diff --git a/packages/react/src/content/content.tsx b/packages/react/src/content/content.tsx
index 78d697f82..ad01341e4 100644
--- a/packages/react/src/content/content.tsx
+++ b/packages/react/src/content/content.tsx
@@ -123,6 +123,9 @@ const Media = ({ ref = null, ...props }: MediaProps) => {