diff --git a/src/components/Carousel/Carousel.stories.tsx b/src/components/Carousel/Carousel.stories.tsx
index 879006d..252b9fc 100644
--- a/src/components/Carousel/Carousel.stories.tsx
+++ b/src/components/Carousel/Carousel.stories.tsx
@@ -2,16 +2,50 @@ import { Description, Subtitle, Title, Unstyled } from '@storybook/addon-docs/bl
import type { Meta, StoryObj } from '@storybook/react';
import { useEffect, useRef, useState } from 'react';
import { Link } from '../Link';
-import { Carousel, type CarouselSlide } from './Carousel';
+import {
+ Carousel,
+ CarouselSingle,
+ CarouselSingleImage,
+ CarouselSingleLink,
+ type CarouselSlide,
+} from './';
// @ts-expect-error: Ignore import of image files in Storybook
+import image1_2x from './carousel-sample-images/image-1@2x.webp';
+// @ts-expect-error
import image1 from './carousel-sample-images/image-1.webp';
// @ts-expect-error
+import image2_2x from './carousel-sample-images/image-2@2x.webp';
+// @ts-expect-error
import image2 from './carousel-sample-images/image-2.webp';
// @ts-expect-error
+import image3_2x from './carousel-sample-images/image-3@2x.webp';
+// @ts-expect-error
import image3 from './carousel-sample-images/image-3.webp';
// @ts-expect-error
+import image4_2x from './carousel-sample-images/image-4@2x.webp';
+// @ts-expect-error
import image4 from './carousel-sample-images/image-4.webp';
// @ts-expect-error
+import image5_2x from './carousel-sample-images/image-5@2x.webp';
+// @ts-expect-error
+import image5 from './carousel-sample-images/image-5.webp';
+// @ts-expect-error
+import image6_2x from './carousel-sample-images/image-6@2x.webp';
+// @ts-expect-error
+import image6 from './carousel-sample-images/image-6.webp';
+// @ts-expect-error
+import image7_2x from './carousel-sample-images/image-7@2x.webp';
+// @ts-expect-error
+import image7 from './carousel-sample-images/image-7.webp';
+// @ts-expect-error
+import image8_2x from './carousel-sample-images/image-8@2x.webp';
+// @ts-expect-error
+import image8 from './carousel-sample-images/image-8.webp';
+// @ts-expect-error
+import image9_2x from './carousel-sample-images/image-9@2x.webp';
+// @ts-expect-error
+import image9 from './carousel-sample-images/image-9.webp';
+// @ts-expect-error
import carousel1024At2x from './docs/carousel-1024@2x.webp';
// @ts-expect-error
import carousel1024 from './docs/carousel-1024.webp';
@@ -19,7 +53,6 @@ import carousel1024 from './docs/carousel-1024.webp';
const meta = {
id: 'Component/DADS v2/Carousel',
title: 'Component/カルーセル',
- component: Carousel,
tags: ['autodocs'],
parameters: {
docs: {
@@ -45,9 +78,246 @@ const meta = {
コードスニペットにおける実際の動作は
- NormalのStory
+
+ Container (Multi Slides)のStory
+
を参照してください。
+
+ 使い方
+
+ カルーセルコンポーネントは、マルチ(複数スライド)とシングル(1枚のみ)の2つの構成をサポートしています。
+ 用途に応じて適切なコンポーネントを選択してください。
+
+
+ マルチ
+
+ 複数のスライドをナビゲーション付きで表示する場合は Carousel{' '}
+ コンポーネントを使用します。
+
+
+ 見出しを使用する場合は、Carouselのchildren
+ に見出し要素を渡し、aria-labelledby
+ 属性でその見出しのIDを参照します。見出しを使用しない場合は、
+ Carouselのaria-label属性で直接ラベルを指定します。
+
+
+
+ {`// 見出しありの場合
+
+ 開催中のイベント
+
+
+// 見出しなしの場合
+
+`}
+
+
+ コンポーネント構成
+
+ -
+
Carousel: ナビゲーション付きカルーセルのルートコンテナ
+
+
+
+ シングル
+
+ 単一のスライドのみを表示する場合は CarouselSingle{' '}
+ コンポーネントを使用します。
+
+ コンポーネント構成
+
+ -
+
CarouselSingle: シングル用のルートコンテナ
+
+ -
+
CarouselSingleLink: スライドのリンク要素(href
+ が省略された場合は<span>として描画)
+
+ -
+
CarouselSingleImage: スライドの画像要素
+
+
+
+
+ {`import {
+ CarouselSingle,
+ CarouselSingleImage,
+ CarouselSingleLink,
+} from './Carousel';
+
+const MyKeyVisual = () => (
+
+
+
+
+
+);`}
+
+
+
+ Props
+
+ Carousel(マルチ用)
+
+
+
+
+ | Props |
+ 型 |
+ デフォルト |
+ 説明 |
+
+
+
+
+
+ slides
+ |
+ CarouselSlide[] |
+ - |
+ スライドデータの配列 |
+
+
+
+ currentIndex
+ |
+ number |
+ - |
+ 現在表示中のスライドインデックス |
+
+
+
+ unit
+ |
+ string |
+ 'スライド' |
+ スライドの単位ラベル |
+
+
+
+ isNormal
+ |
+ boolean |
+ - |
+ 通常レイアウト(true)またはコンパクトレイアウト(false)の切り替え |
+
+
+
+ innerRef
+ |
+ Ref<HTMLDivElement> |
+ - |
+ 内側のdiv要素のref(ResizeObserver用) |
+
+
+
+ onPrev
+ |
+ () => void |
+ - |
+ 前へボタンのコールバック |
+
+
+
+ onNext
+ |
+ () => void |
+ - |
+ 次へボタンのコールバック |
+
+
+
+ onStepSelect
+ |
+ (index: number) => void |
+ - |
+ ステップナビゲーションでのスライド選択コールバック |
+
+
+
+
+
+ CarouselSlide(スライドデータ)
+
+
+
+
+ | プロパティ |
+ 型 |
+ 説明 |
+
+
+
+
+
+ id
+ |
+ string |
+ スライドの一意な識別子 |
+
+
+
+ label
+ |
+ string |
+ スライドの表示ラベル |
+
+
+
+ href
+ |
+ string? |
+ スライドのリンクURL(省略時はリンクなし) |
+
+
+
+ target
+ |
+ string? |
+ リンクのtarget属性 |
+
+
+
+ image
+ |
+ CarouselImage |
+ 画像情報(src, srcSet, alt, width, height) |
+
+
+
+
+
+ CarouselSingleLink(シングル用スライドリンク)
+
+
+
+
+ | Props |
+ 型 |
+ 説明 |
+
+
+
+
+
+ href
+ |
+ string? |
+
+ リンクURL(省略時は<span>として描画)
+ |
+
+
+
+
+ ブレークポイント
Carousel
コンポーネントの規定のブレークポイントはコンテナ幅を基準とした1024pxです。ブレークポイントを変更するには、コンポーネント内に記述されているすべての
@@ -74,13 +344,14 @@ const meta = {
export default meta;
-const slides: CarouselSlide[] = [
+const containerSlides: CarouselSlide[] = [
{
id: 'slide-1',
label: 'スライド1',
href: '#link1',
image: {
src: image1,
+ srcSet: `${image1_2x} 2x`,
alt: '学ぼうSDGs 偶数月の第3土曜日 環境保全の「自分事化」で学べるワークショップ開催',
width: 696,
height: 392,
@@ -92,6 +363,7 @@ const slides: CarouselSlide[] = [
href: '#link2',
image: {
src: image2,
+ srcSet: `${image2_2x} 2x`,
alt: '地産地消キャンペーン 県の名産品や体験イベントを楽しもう 期間:4月から7月までの毎週末開催!',
width: 696,
height: 392,
@@ -103,6 +375,7 @@ const slides: CarouselSlide[] = [
href: '#link3',
image: {
src: image3,
+ srcSet: `${image3_2x} 2x`,
alt: '令和 国立公園・歴史名所スタンプラリー まわろうよ 今年の週末 全国を 子どもたちの歴史理解促進と、日本各地の名産品・観光資源に親しむことを目的に、本イベントを全国開催しています!',
width: 696,
height: 392,
@@ -114,6 +387,7 @@ const slides: CarouselSlide[] = [
href: '#link4',
image: {
src: image4,
+ srcSet: `${image4_2x} 2x`,
alt: '合同健康診断のお知らせ ご自身とご家族の健康維持のため、定期的な健康診断の受診を。皆様の健やかな生活を応援します。 6月1日より受付開始 川海町および森林町にお住いの方が対象です',
width: 696,
height: 392,
@@ -121,16 +395,67 @@ const slides: CarouselSlide[] = [
},
];
+const containerSlidesWithoutLinks: CarouselSlide[] = containerSlides.map((slide) => ({
+ ...slide,
+ href: undefined,
+}));
+
+const keyVisualSlides: CarouselSlide[] = [
+ {
+ id: 'slide-1',
+ label: 'スライド1',
+ image: {
+ src: image5,
+ srcSet: `${image5_2x} 2x`,
+ alt: '写真:デジタル公園の大木 - 太い幹があり、そこから伸びる多数の枝が絡み合うように広がっている。枝の間からは青空と緑の葉が見える。',
+ width: 696,
+ height: 392,
+ },
+ },
+ {
+ id: 'slide-2',
+ label: 'スライド2',
+ image: {
+ src: image6,
+ srcSet: `${image6_2x} 2x`,
+ alt: '写真:デジタル海水浴場 - 透明度が高いターコイズブルーの海と砂浜の風景。海は穏やかで、水面には細かな波紋が広がっている。',
+ width: 696,
+ height: 392,
+ },
+ },
+ {
+ id: 'slide-3',
+ label: 'スライド3',
+ image: {
+ src: image7,
+ srcSet: `${image7_2x} 2x`,
+ alt: '写真:デジタル中央通り沿いの花壇 - 白、黄色、紫、オレンジのパンジーが咲いている。背景には車のテールランプの赤い光が見える。',
+ width: 696,
+ height: 392,
+ },
+ },
+ {
+ id: 'slide-4',
+ label: 'スライド4',
+ image: {
+ src: image8,
+ srcSet: `${image8_2x} 2x`,
+ alt: '写真:デジタル県の夕焼け雲 - オレンジのグラデーションの空に、複数の濃い灰色の雲が浮かんでいる。下部には山々のシルエットが黒く連なっている。',
+ width: 696,
+ height: 392,
+ },
+ },
+];
+
/**
- * コンテナ幅が1024pxの地点にブレークポイントを持つカルーセルの作例です。各スライドは横幅696pxです。
- *
- * ブレークポイント前後の挙動を確認するには[NormalのStory](?path=/story/component-dads-v2-carousel--normal)を参照してください。
+ * コンテナタイプのカルーセルです。見出しあり、リンクありの複数スライド構成(マルチ)
*
- * `Carousel`コンポーネントの規定のブレークポイントはコンテナ幅を基準とした1024pxです。ブレークポイントを変更するには、コンポーネント内に記述されているすべての`@[64rem]`の指定を同一の任意の値、またはTailwind CSSのテーマ設定で定義されたブレークポイントに置き換えてください。
+ * コンテナ幅が1024pxの地点にブレークポイントを持ちます。各スライドは横幅696pxです。
*/
-export const Normal: StoryObj = {
+export const Container: StoryObj = {
+ name: 'Container (Multi Slides)',
render: () => {
- const CONTAINER_BREAKPOINT = 64; // rem
+ const CONTAINER_BREAKPOINT = 64;
const [currentIndex, setCurrentIndex] = useState(0);
const [isNormal, setIsNormal] = useState(false);
const carouselInnerRef = useRef(null);
@@ -141,7 +466,6 @@ export const Normal: StoryObj = {
const observer = new ResizeObserver((entries) => {
for (const entry of entries) {
- // Get font size of root element to convert rem to px
const fontSize = parseFloat(getComputedStyle(document.documentElement).fontSize);
const widthPx = entry.borderBoxSize?.[0]?.inlineSize ?? entry.contentRect.width;
setIsNormal(widthPx >= CONTAINER_BREAKPOINT * fontSize);
@@ -153,22 +477,150 @@ export const Normal: StoryObj = {
}, []);
const handleNext = () => {
- setCurrentIndex((index) => (index + 1) % slides.length);
+ setCurrentIndex((index) => (index + 1) % containerSlides.length);
};
const handlePrev = () => {
- setCurrentIndex((index) => (index + slides.length - 1) % slides.length);
+ setCurrentIndex((index) => (index + containerSlides.length - 1) % containerSlides.length);
};
const handleSelect = (index: number) => {
- setCurrentIndex((index + slides.length) % slides.length);
+ setCurrentIndex((index + containerSlides.length) % containerSlides.length);
+ };
+
+ return (
+
+
+ 開催中のイベント
+
+
+ );
+ },
+};
+
+/**
+ * コンテナタイプのカルーセルです。見出しあり、リンクなしの複数スライド構成(マルチ)
+ */
+export const ContainerWithoutLinks: StoryObj = {
+ name: 'Container (Multi Slides without Links)',
+ render: () => {
+ const CONTAINER_BREAKPOINT = 64;
+ const [currentIndex, setCurrentIndex] = useState(0);
+ const [isNormal, setIsNormal] = useState(false);
+ const carouselInnerRef = useRef(null);
+
+ useEffect(() => {
+ const element = carouselInnerRef.current;
+ if (!element) return;
+
+ const observer = new ResizeObserver((entries) => {
+ for (const entry of entries) {
+ const fontSize = parseFloat(getComputedStyle(document.documentElement).fontSize);
+ const widthPx = entry.borderBoxSize?.[0]?.inlineSize ?? entry.contentRect.width;
+ setIsNormal(widthPx >= CONTAINER_BREAKPOINT * fontSize);
+ }
+ });
+
+ observer.observe(element, { box: 'border-box' });
+ return () => observer.disconnect();
+ }, []);
+
+ const handleNext = () => {
+ setCurrentIndex((index) => (index + 1) % containerSlidesWithoutLinks.length);
+ };
+
+ const handlePrev = () => {
+ setCurrentIndex(
+ (index) =>
+ (index + containerSlidesWithoutLinks.length - 1) % containerSlidesWithoutLinks.length,
+ );
+ };
+
+ const handleSelect = (index: number) => {
+ setCurrentIndex(
+ (index + containerSlidesWithoutLinks.length) % containerSlidesWithoutLinks.length,
+ );
+ };
+
+ return (
+
+
+ 開催中のイベント
+
+
+ );
+ },
+};
+
+/**
+ * 打ち出しタイプのカルーセルです。見出しなし、リンクなしの複数スライド構成(マルチ)
+ */
+export const KeyVisual: StoryObj = {
+ name: 'Key Visual (Multi Slides without Link)',
+ render: () => {
+ const CONTAINER_BREAKPOINT = 64;
+ const [currentIndex, setCurrentIndex] = useState(0);
+ const [isNormal, setIsNormal] = useState(false);
+ const carouselInnerRef = useRef(null);
+
+ useEffect(() => {
+ const element = carouselInnerRef.current;
+ if (!element) return;
+
+ const observer = new ResizeObserver((entries) => {
+ for (const entry of entries) {
+ const fontSize = parseFloat(getComputedStyle(document.documentElement).fontSize);
+ const widthPx = entry.borderBoxSize?.[0]?.inlineSize ?? entry.contentRect.width;
+ setIsNormal(widthPx >= CONTAINER_BREAKPOINT * fontSize);
+ }
+ });
+
+ observer.observe(element, { box: 'border-box' });
+ return () => observer.disconnect();
+ }, []);
+
+ const handleNext = () => {
+ setCurrentIndex((index) => (index + 1) % keyVisualSlides.length);
+ };
+
+ const handlePrev = () => {
+ setCurrentIndex((index) => (index + keyVisualSlides.length - 1) % keyVisualSlides.length);
+ };
+
+ const handleSelect = (index: number) => {
+ setCurrentIndex((index + keyVisualSlides.length) % keyVisualSlides.length);
};
return (
{
+ return (
+
+
+
+
+
+ );
+ },
+};
diff --git a/src/components/Carousel/Carousel.tsx b/src/components/Carousel/Carousel.tsx
index 45a7ff3..c1e76fa 100644
--- a/src/components/Carousel/Carousel.tsx
+++ b/src/components/Carousel/Carousel.tsx
@@ -6,25 +6,18 @@ import { Disclosure, DisclosureSummary } from '../Disclosure';
type CarouselImage = {
src: string;
+ srcSet?: string;
alt: string;
width: number;
height: number;
};
-type CarouselImageSource = {
- srcSet: string;
- width?: number;
- height?: number;
- media: string;
-};
-
export type CarouselSlide = {
id: string;
label: string;
- href: string;
+ href?: string;
target?: string;
image: CarouselImage;
- imageSources?: CarouselImageSource[];
};
// Carousel Sub Components
@@ -163,34 +156,24 @@ const CarouselPageNav = (props: CarouselPageNavProps) => {
type CarouselBackgroundLayerProps = {
className?: string;
image: CarouselImage;
- imageSources?: CarouselImageSource[];
};
const CarouselBackgroundLayer = (props: CarouselBackgroundLayerProps) => {
- const { className, image, imageSources } = props;
+ const { className, image } = props;
+
return (
-
- {imageSources?.map((source) => (
-
- ))}
-
-
+
);
@@ -240,38 +223,30 @@ const CarouselExpandList = (props: CarouselExpandListProps) => {
{slide.label}
-
- {slide.imageSources?.map((source) => (
-
- ))}
-
-
+
-
+
);
@@ -324,35 +299,27 @@ const CarouselPanelArea = (props: CarouselPanelAreaProps) => {
{mainLabel}
-
- {currentSlide.imageSources?.map((source) => (
-
- ))}
-
-
+
@@ -374,24 +341,14 @@ const CarouselPanelArea = (props: CarouselPanelAreaProps) => {
focus-visible:outline focus-visible:outline-4 focus-visible:outline-black focus-visible:outline-offset-[calc(2/16*1rem)] focus-visible:rounded-[calc(4/16*1rem)] focus-visible:ring-[calc(2/16*1rem)] focus-visible:ring-yellow-300
`}
>
-
- {nextSlide.imageSources?.map((source) => (
-
- ))}
-
-
+
次の{unit}
@@ -400,10 +357,7 @@ const CarouselPanelArea = (props: CarouselPanelAreaProps) => {
-
+
{
group-has-[[open]]/carousel:!hidden @[64rem]:block
`}
>
-
+
);
@@ -435,6 +389,7 @@ export type CarouselProps = ComponentProps<'section'> & {
export const Carousel = (props: CarouselProps) => {
const {
className,
+ children,
slides,
currentIndex,
unit = 'スライド',
@@ -461,11 +416,12 @@ export const Carousel = (props: CarouselProps) => {
+ {children}
{
);
};
+
diff --git a/src/components/Carousel/CarouselSingle.tsx b/src/components/Carousel/CarouselSingle.tsx
new file mode 100644
index 0000000..e65fd3e
--- /dev/null
+++ b/src/components/Carousel/CarouselSingle.tsx
@@ -0,0 +1,53 @@
+import type { ComponentProps } from 'react';
+
+export type CarouselSingleProps = ComponentProps<'div'>;
+
+export const CarouselSingle = (props: CarouselSingleProps) => {
+ const { className, children, ...rest } = props;
+ return (
+
+ {children}
+
+ );
+};
+
+export type CarouselSingleLinkProps = ComponentProps<'a'>;
+
+export const CarouselSingleLink = (props: CarouselSingleLinkProps) => {
+ const { className, href, children, ...rest } = props;
+
+ if (href) {
+ return (
+
+ {children}
+
+ );
+ }
+
+ return {children};
+};
+
+export type CarouselSingleImageProps = ComponentProps<'img'>;
+
+export const CarouselSingleImage = (props: CarouselSingleImageProps) => {
+ const { className, alt, ...rest } = props;
+ return (
+
+ );
+};
diff --git a/src/components/Carousel/carousel-sample-images/image-1.webp b/src/components/Carousel/carousel-sample-images/image-1.webp
index f535a5d..473931f 100644
Binary files a/src/components/Carousel/carousel-sample-images/image-1.webp and b/src/components/Carousel/carousel-sample-images/image-1.webp differ
diff --git a/src/components/Carousel/carousel-sample-images/image-1@2x.webp b/src/components/Carousel/carousel-sample-images/image-1@2x.webp
new file mode 100644
index 0000000..f4dcaaf
Binary files /dev/null and b/src/components/Carousel/carousel-sample-images/image-1@2x.webp differ
diff --git a/src/components/Carousel/carousel-sample-images/image-2.webp b/src/components/Carousel/carousel-sample-images/image-2.webp
index 34aa780..b832dcb 100644
Binary files a/src/components/Carousel/carousel-sample-images/image-2.webp and b/src/components/Carousel/carousel-sample-images/image-2.webp differ
diff --git a/src/components/Carousel/carousel-sample-images/image-2@2x.webp b/src/components/Carousel/carousel-sample-images/image-2@2x.webp
new file mode 100644
index 0000000..48f9678
Binary files /dev/null and b/src/components/Carousel/carousel-sample-images/image-2@2x.webp differ
diff --git a/src/components/Carousel/carousel-sample-images/image-3.webp b/src/components/Carousel/carousel-sample-images/image-3.webp
index c0e436d..ae4cdae 100644
Binary files a/src/components/Carousel/carousel-sample-images/image-3.webp and b/src/components/Carousel/carousel-sample-images/image-3.webp differ
diff --git a/src/components/Carousel/carousel-sample-images/image-3@2x.webp b/src/components/Carousel/carousel-sample-images/image-3@2x.webp
new file mode 100644
index 0000000..83531c8
Binary files /dev/null and b/src/components/Carousel/carousel-sample-images/image-3@2x.webp differ
diff --git a/src/components/Carousel/carousel-sample-images/image-4.webp b/src/components/Carousel/carousel-sample-images/image-4.webp
index 2e22f6a..efce07b 100644
Binary files a/src/components/Carousel/carousel-sample-images/image-4.webp and b/src/components/Carousel/carousel-sample-images/image-4.webp differ
diff --git a/src/components/Carousel/carousel-sample-images/image-4@2x.webp b/src/components/Carousel/carousel-sample-images/image-4@2x.webp
new file mode 100644
index 0000000..30191d5
Binary files /dev/null and b/src/components/Carousel/carousel-sample-images/image-4@2x.webp differ
diff --git a/src/components/Carousel/carousel-sample-images/image-5.webp b/src/components/Carousel/carousel-sample-images/image-5.webp
new file mode 100644
index 0000000..233ddff
Binary files /dev/null and b/src/components/Carousel/carousel-sample-images/image-5.webp differ
diff --git a/src/components/Carousel/carousel-sample-images/image-5@2x.webp b/src/components/Carousel/carousel-sample-images/image-5@2x.webp
new file mode 100644
index 0000000..3680c5d
Binary files /dev/null and b/src/components/Carousel/carousel-sample-images/image-5@2x.webp differ
diff --git a/src/components/Carousel/carousel-sample-images/image-6.webp b/src/components/Carousel/carousel-sample-images/image-6.webp
new file mode 100644
index 0000000..c418381
Binary files /dev/null and b/src/components/Carousel/carousel-sample-images/image-6.webp differ
diff --git a/src/components/Carousel/carousel-sample-images/image-6@2x.webp b/src/components/Carousel/carousel-sample-images/image-6@2x.webp
new file mode 100644
index 0000000..221c499
Binary files /dev/null and b/src/components/Carousel/carousel-sample-images/image-6@2x.webp differ
diff --git a/src/components/Carousel/carousel-sample-images/image-7.webp b/src/components/Carousel/carousel-sample-images/image-7.webp
new file mode 100644
index 0000000..541a727
Binary files /dev/null and b/src/components/Carousel/carousel-sample-images/image-7.webp differ
diff --git a/src/components/Carousel/carousel-sample-images/image-7@2x.webp b/src/components/Carousel/carousel-sample-images/image-7@2x.webp
new file mode 100644
index 0000000..4989368
Binary files /dev/null and b/src/components/Carousel/carousel-sample-images/image-7@2x.webp differ
diff --git a/src/components/Carousel/carousel-sample-images/image-8.webp b/src/components/Carousel/carousel-sample-images/image-8.webp
new file mode 100644
index 0000000..90d2b98
Binary files /dev/null and b/src/components/Carousel/carousel-sample-images/image-8.webp differ
diff --git a/src/components/Carousel/carousel-sample-images/image-8@2x.webp b/src/components/Carousel/carousel-sample-images/image-8@2x.webp
new file mode 100644
index 0000000..d0a92cb
Binary files /dev/null and b/src/components/Carousel/carousel-sample-images/image-8@2x.webp differ
diff --git a/src/components/Carousel/carousel-sample-images/image-9.webp b/src/components/Carousel/carousel-sample-images/image-9.webp
new file mode 100644
index 0000000..155675f
Binary files /dev/null and b/src/components/Carousel/carousel-sample-images/image-9.webp differ
diff --git a/src/components/Carousel/carousel-sample-images/image-9@2x.webp b/src/components/Carousel/carousel-sample-images/image-9@2x.webp
new file mode 100644
index 0000000..8f27025
Binary files /dev/null and b/src/components/Carousel/carousel-sample-images/image-9@2x.webp differ
diff --git a/src/components/Carousel/index.ts b/src/components/Carousel/index.ts
index bae7d1a..b03f1b7 100644
--- a/src/components/Carousel/index.ts
+++ b/src/components/Carousel/index.ts
@@ -1,2 +1,8 @@
export type { CarouselProps, CarouselSlide } from './Carousel';
export { Carousel } from './Carousel';
+export type {
+ CarouselSingleImageProps,
+ CarouselSingleLinkProps,
+ CarouselSingleProps,
+} from './CarouselSingle';
+export { CarouselSingle, CarouselSingleImage, CarouselSingleLink } from './CarouselSingle';
diff --git a/src/components/index.ts b/src/components/index.ts
index 71c7acb..7c560ee 100644
--- a/src/components/index.ts
+++ b/src/components/index.ts
@@ -7,7 +7,7 @@ export {
export { Blockquote } from './Blockquote';
export { BreadcrumbItem, BreadcrumbList, Breadcrumbs, BreadcrumbsLabel } from './Breadcrumbs';
export { Button, buttonBaseStyle, buttonSizeStyle, buttonVariantStyle } from './Button';
-export { Carousel } from './Carousel';
+export { Carousel, CarouselSingle, CarouselSingleImage, CarouselSingleLink } from './Carousel';
export { Checkbox } from './Checkbox';
export { ChipLabel } from './ChipLabel';
export * from './DatePicker';
diff --git a/src/index.ts b/src/index.ts
index 0c48ebf..86621d4 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -11,6 +11,9 @@ export {
buttonSizeStyle,
buttonVariantStyle,
Carousel,
+ CarouselSingle,
+ CarouselSingleImage,
+ CarouselSingleLink,
Checkbox,
ChipLabel,
DatePicker,