diff --git a/.changeset/short-adults-know.md b/.changeset/short-adults-know.md new file mode 100644 index 0000000000..ae06e05778 --- /dev/null +++ b/.changeset/short-adults-know.md @@ -0,0 +1,5 @@ +--- +'@sumup-oss/circuit-ui': minor +--- + +Added a new CarouselPagination component. Use it to display larger amounts of content in limited spaces by dividing it into multiple pieces to be discoverd by the users through interaction. diff --git a/.eslintrc.js b/.eslintrc.js index 6cd4c31fe1..8ef89f7c34 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -47,18 +47,12 @@ module.exports = require('@sumup-oss/foundry/eslint')({ }, }, { - files: ['**/*.stories.*'], + files: ['**/*.stories.*', '**/*.spec.*'], rules: { 'import/no-relative-packages': 'off', 'react-server-components/use-client': 'off', }, }, - { - files: ['**/*.spec.*'], - rules: { - 'react-server-components/use-client': 'off', - }, - }, { files: ['packages/circuit-ui/components/legacy/**/*'], rules: { diff --git a/.storybook/fixtures.ts b/.storybook/fixtures.ts new file mode 100644 index 0000000000..a47ae1a8b0 --- /dev/null +++ b/.storybook/fixtures.ts @@ -0,0 +1,22 @@ +export const images: { src: string; alt: string }[] = [ + { + src: '/images/sumup-coffee-transaction.jpg', + alt: 'Next to a cup of coffee lays a phone showing a card transaction in the SumUp app', + }, + { + src: '/images/sumup-product-catalog.jpg', + alt: 'A person holds a tablet showing a grid of products in the SumUp POS app. In the background, cakes and pastries sit on a table', + }, + { + src: '/images/sumup-tablet-insights.jpg', + alt: 'A tablet shows sales insights in the SumUp POS app. On the table next to it are a SumUp Solo card reader with printer and two bowls with fruits', + }, + { + src: '/images/sumup-solo-cradle.jpg', + alt: 'A SumUp Solo card reader sits in its charging cradle next to a tray of red, green and dark-brown mini tarts', + }, + { + src: '/images/sumup-solo-printer.jpg', + alt: 'A person taps their phone onto a SumUp Solo card reader, perhaps to pay for the assortment of food around it on the table', + }, +]; diff --git a/.storybook/public/images/illustration-waves-2.jpg b/.storybook/public/images/illustration-waves-2.jpg deleted file mode 100644 index 4c84b33fb8..0000000000 Binary files a/.storybook/public/images/illustration-waves-2.jpg and /dev/null differ diff --git a/.storybook/public/images/illustration-waves-3.jpg b/.storybook/public/images/illustration-waves-3.jpg deleted file mode 100644 index 6ff7bd8439..0000000000 Binary files a/.storybook/public/images/illustration-waves-3.jpg and /dev/null differ diff --git a/.storybook/public/images/illustration-waves.jpg b/.storybook/public/images/illustration-waves.jpg deleted file mode 100644 index 6fb7a86d16..0000000000 Binary files a/.storybook/public/images/illustration-waves.jpg and /dev/null differ diff --git a/.storybook/public/images/sumup-coffee-transaction.jpg b/.storybook/public/images/sumup-coffee-transaction.jpg new file mode 100644 index 0000000000..c1eb353744 Binary files /dev/null and b/.storybook/public/images/sumup-coffee-transaction.jpg differ diff --git a/.storybook/public/images/sumup-product-catalog.jpg b/.storybook/public/images/sumup-product-catalog.jpg new file mode 100644 index 0000000000..3e0ed1b418 Binary files /dev/null and b/.storybook/public/images/sumup-product-catalog.jpg differ diff --git a/.storybook/public/images/sumup-solo-cradle.jpg b/.storybook/public/images/sumup-solo-cradle.jpg new file mode 100644 index 0000000000..9db7ae64c1 Binary files /dev/null and b/.storybook/public/images/sumup-solo-cradle.jpg differ diff --git a/.storybook/public/images/sumup-solo-printer.jpg b/.storybook/public/images/sumup-solo-printer.jpg new file mode 100644 index 0000000000..b855cfc570 Binary files /dev/null and b/.storybook/public/images/sumup-solo-printer.jpg differ diff --git a/.storybook/public/images/sumup-tablet-insights.jpg b/.storybook/public/images/sumup-tablet-insights.jpg new file mode 100644 index 0000000000..a4081fa42e Binary files /dev/null and b/.storybook/public/images/sumup-tablet-insights.jpg differ diff --git a/packages/circuit-ui/components/Carousel/Carousel.spec.tsx b/packages/circuit-ui/components/Carousel/Carousel.spec.tsx index 515d8a6b99..3b4ca70221 100644 --- a/packages/circuit-ui/components/Carousel/Carousel.spec.tsx +++ b/packages/circuit-ui/components/Carousel/Carousel.spec.tsx @@ -15,10 +15,12 @@ import { describe, expect, it, vi } from 'vitest'; +import { images } from '../../../../.storybook/fixtures.js'; import { axe, render, screen } from '../../util/test-utils.js'; import { Carousel } from './Carousel.js'; -import { SLIDES } from './__fixtures__/index.js'; + +const slides = images.map((image) => ({ image })); describe('Carousel', () => { const baseProps = { @@ -37,7 +39,7 @@ describe('Carousel', () => { it('should render with children as a function', () => { const children = vi.fn(() =>

Carousel heading

); render( - + {children} , ); @@ -47,7 +49,7 @@ describe('Carousel', () => { it('should render with children as a node', () => { render( - +

Carousel heading

, ); @@ -56,7 +58,7 @@ describe('Carousel', () => { }); it('should have no accessibility violations', async () => { - const { container } = render(); + const { container } = render(); const actual = await axe(container); expect(actual).toHaveNoViolations(); diff --git a/packages/circuit-ui/components/Carousel/Carousel.stories.tsx b/packages/circuit-ui/components/Carousel/Carousel.stories.tsx index 6ff670dfc2..1ccb75a0c3 100644 --- a/packages/circuit-ui/components/Carousel/Carousel.stories.tsx +++ b/packages/circuit-ui/components/Carousel/Carousel.stories.tsx @@ -15,6 +15,8 @@ import { useState } from 'react'; +import { images } from '../../../../.storybook/fixtures.js'; + import { Container } from './components/Container/index.js'; import { Slides } from './components/Slides/index.js'; import { Slide } from './components/Slide/index.js'; @@ -32,7 +34,8 @@ import { ANIMATION_DURATION, SLIDE_DURATION, } from './constants.js'; -import { SLIDES } from './__fixtures__/index.js'; + +const slides = images.map((image) => ({ image })); export default { title: 'Components/Carousel', @@ -47,7 +50,7 @@ export const Stateful = (args: CarouselProps) => ( ); Stateful.args = { - slides: SLIDES, + slides, slideDuration: SLIDE_DURATION, animationDuration: ANIMATION_DURATION, aspectRatio: ASPECT_RATIO, @@ -61,7 +64,7 @@ Stateful.args = { }; export const Composed = () => { - const total = SLIDES.length; + const total = slides.length; const [step, setStep] = useState(0); const goBack = () => setStep(step === 0 ? total - 1 : step - 1); const goForward = () => setStep(step === total - 1 ? 0 : step + 1); @@ -70,7 +73,7 @@ export const Composed = () => {
- {SLIDES.map(({ image }, index) => ( + {slides.map(({ image }, index) => ( { - + Previous - + Next diff --git a/packages/circuit-ui/components/Carousel/components/Slide/Slide.stories.tsx b/packages/circuit-ui/components/Carousel/components/Slide/Slide.stories.tsx index bd725fd1c3..d53ead8126 100644 --- a/packages/circuit-ui/components/Carousel/components/Slide/Slide.stories.tsx +++ b/packages/circuit-ui/components/Carousel/components/Slide/Slide.stories.tsx @@ -26,8 +26,8 @@ export default { export const OnlyImage = (args: SlideProps) => ( Aerial photo of turbulent blue ocean waves ); @@ -35,8 +35,8 @@ export const OnlyImage = (args: SlideProps) => ( export const TextAndImage = (args: SlideProps) => ( Aerial photo of turbulent blue ocean waves { diff --git a/packages/circuit-ui/components/CarouselPagination/CarouselPagination.mdx b/packages/circuit-ui/components/CarouselPagination/CarouselPagination.mdx new file mode 100644 index 0000000000..f0e0088a99 --- /dev/null +++ b/packages/circuit-ui/components/CarouselPagination/CarouselPagination.mdx @@ -0,0 +1,25 @@ +import { Meta, Status, Props, Story } from '../../../../.storybook/components'; +import * as Stories from './CarouselPagination.stories'; + + + +# CarouselPagination + + + +The carousel pagination component allows users to navigate content that is divided into multiple slides or pages. + + + + +## Usage + +Consider adjusting the layout or using a different component if the number of slides/pages exceeds five. + +For inline use cases, create an illusion of continuity through cropped images or text, so users quickly understand that they can get more content by moving beyond the screen edge. + +Do not place the carousel pagination on busy, dynamic backgrounds (i.e. on images, illustrations), in order to ensure optimal contrast and discoverability. + +Ensure that content outside the viewport is searchable and becomes visible when focused. Consider lazy-loading content that is initially hidden to optimize performance. + + diff --git a/packages/circuit-ui/components/CarouselPagination/CarouselPagination.module.css b/packages/circuit-ui/components/CarouselPagination/CarouselPagination.module.css new file mode 100644 index 0000000000..094fefb1c9 --- /dev/null +++ b/packages/circuit-ui/components/CarouselPagination/CarouselPagination.module.css @@ -0,0 +1,55 @@ +.base { + display: flex; + padding: 0; + margin: 0; + list-style-type: none; +} + +.cue { + display: block; + padding: var(--cui-spacings-byte); + background: none; + border: none; + border-radius: var(--cui-border-radius-pill); +} + +a.cue, +button.cue { + cursor: pointer; +} + +.shape { + display: block; + width: var(--cui-spacings-kilo); + height: var(--cui-spacings-kilo); + background-color: var(--cui-fg-placeholder); + border-radius: var(--cui-border-radius-pill); + transition: + background-color var(--cui-transitions-default), + width var(--cui-transitions-default); +} + +a.cue:hover .shape, +button.cue:hover .shape { + background-color: var(--cui-fg-placeholder-hovered); +} + +a.cue:active .shape, +button.cue:active .shape { + background-color: var(--cui-fg-placeholder-pressed); +} + +.cue[aria-current] .shape { + width: var(--cui-spacings-peta); + background-color: var(--cui-bg-strong); +} + +a.cue[aria-current]:hover .shape, +button.cue[aria-current]:hover .shape { + background-color: var(--cui-bg-strong-hovered); +} + +a.cue[aria-current]:active .shape, +button.cue[aria-current]:active .shape { + background-color: var(--cui-bg-strong-pressed); +} diff --git a/packages/circuit-ui/components/CarouselPagination/CarouselPagination.spec.tsx b/packages/circuit-ui/components/CarouselPagination/CarouselPagination.spec.tsx new file mode 100644 index 0000000000..261f39818f --- /dev/null +++ b/packages/circuit-ui/components/CarouselPagination/CarouselPagination.spec.tsx @@ -0,0 +1,90 @@ +/** + * Copyright 2024, SumUp Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, expect, it, vi } from 'vitest'; +import { createRef } from 'react'; + +import { render, screen } from '../../util/test-utils.js'; + +import { CarouselPagination } from './CarouselPagination.js'; + +describe('CarouselPagination', () => { + const baseProps = { + slides: [ + { id: 'foo', label: 'Foo' }, + { id: 'bar', label: 'Bar' }, + { id: 'baz', label: 'Baz' }, + ], + currentId: 'foo', + }; + + it('should merge a custom class name with the default ones', () => { + const className = 'foo'; + render(); + const list = screen.getByRole('list'); + expect(list?.className).toContain(className); + }); + + it('should forward a ref', () => { + const ref = createRef(); + render(); + const list = screen.getByRole('list'); + expect(ref.current).toBe(list); + }); + + it('should render as buttons when the slides have onClick handlers', () => { + const slides = [ + { id: 'foo', label: 'Foo', onClick: vi.fn() }, + { id: 'bar', label: 'Bar', onClick: vi.fn() }, + { id: 'baz', label: 'Baz', onClick: vi.fn() }, + ]; + render(); + const buttons = screen.getAllByRole('button'); + expect(buttons).toHaveLength(slides.length); + }); + + it('should render as links when the slides have href attributes', () => { + const slides = [ + { id: 'foo', label: 'Foo', href: '#foo', onClick: vi.fn() }, + { id: 'bar', label: 'Bar', href: '#bar', onClick: vi.fn() }, + { id: 'baz', label: 'Baz', href: '#baz', onClick: vi.fn() }, + ]; + render(); + const links = screen.getAllByRole('link'); + expect(links).toHaveLength(slides.length); + }); + + it('should mark the current active item', () => { + const slides = [ + { id: 'foo', label: 'Foo', href: '#foo' }, + { id: 'bar', label: 'Bar', href: '#bar' }, + { id: 'baz', label: 'Baz', href: '#baz' }, + ]; + render(); + const currentSlide = screen.getByRole('link', { name: /foo/i }); + expect(currentSlide).toHaveAttribute('aria-current'); + }); + + it('should mark the current active item with the provided type', () => { + const slides = [ + { id: 'foo', label: 'Foo', href: '#foo' }, + { id: 'bar', label: 'Bar', href: '#bar' }, + { id: 'baz', label: 'Baz', href: '#baz' }, + ]; + render(); + const currentSlide = screen.getByRole('link', { name: /foo/i }); + expect(currentSlide).toHaveAttribute('aria-current', 'page'); + }); +}); diff --git a/packages/circuit-ui/components/CarouselPagination/CarouselPagination.stories.tsx b/packages/circuit-ui/components/CarouselPagination/CarouselPagination.stories.tsx new file mode 100644 index 0000000000..074387425f --- /dev/null +++ b/packages/circuit-ui/components/CarouselPagination/CarouselPagination.stories.tsx @@ -0,0 +1,97 @@ +/** + * Copyright 2024, SumUp Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { useState } from 'react'; + +import { + CarouselPagination, + type CarouselPaginationProps, +} from './CarouselPagination.js'; +import { Carousel as ExampleCarousel } from './examples/Carousel.js'; + +export default { + title: 'Components/CarouselPagination', + component: CarouselPagination, +}; + +export const Base = (args: CarouselPaginationProps) => { + const [currentId, setCurrentId] = useState(args.currentId); + + const slides = args.slides.map((slide) => ({ + ...slide, + onClick: () => { + setCurrentId(slide.id); + }, + })); + + return ; +}; + +Base.args = { + slides: [ + { id: 'foo', label: 'Foo' }, + { id: 'bar', label: 'Bar' }, + { id: 'baz', label: 'Baz' }, + ], + currentId: 'foo', +}; + +export const Carousel = (args: CarouselPaginationProps) => ( + +); + +Carousel.args = { + slides: [ + { + id: 'coffee-transaction', + label: 'coffee-transaction', + href: '#coffee-transaction', + target: '_self', + image: { src: '/images/sumup-coffee-transaction.jpg', alt: '' }, + }, + { + id: 'product-catalog', + label: 'Product catalog', + href: '#product-catalog', + target: '_self', + image: { src: '/images/sumup-product-catalog.jpg', alt: '' }, + }, + { + id: 'solo-cradle', + label: 'Solo with cradle', + href: '#solo-cradle', + target: '_self', + image: { src: '/images/sumup-solo-cradle.jpg', alt: '' }, + }, + { + id: 'solo-printer', + label: 'Solo printer', + href: '#solo-printer', + target: '_self', + image: { src: '/images/sumup-solo-printer.jpg', alt: '' }, + }, + { + id: 'tablet-insights', + label: 'Tablet insights', + href: '#tablet-insights', + target: '_self', + image: { src: '/images/sumup-tablet-insights.jpg', alt: '' }, + }, + ], + currentId: 'coffee-transaction', +}; +Carousel.parameters = { + chromatic: { disableSnapshot: true }, +}; diff --git a/packages/circuit-ui/components/CarouselPagination/CarouselPagination.tsx b/packages/circuit-ui/components/CarouselPagination/CarouselPagination.tsx new file mode 100644 index 0000000000..a7e2f5d2c1 --- /dev/null +++ b/packages/circuit-ui/components/CarouselPagination/CarouselPagination.tsx @@ -0,0 +1,106 @@ +/** + * Copyright 2024, SumUp Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use client'; + +import { + forwardRef, + type AnchorHTMLAttributes, + type ButtonHTMLAttributes, + type HTMLAttributes, +} from 'react'; + +import { useComponents } from '../ComponentsContext/useComponents.js'; +import type { AsPropType } from '../../types/prop-types.js'; +import { utilClasses } from '../../styles/utility.js'; +import { clsx } from '../../styles/clsx.js'; + +import classes from './CarouselPagination.module.css'; + +type LinkElProps = AnchorHTMLAttributes; +type ButtonElProps = ButtonHTMLAttributes; + +export type Slide = LinkElProps & + ButtonElProps & { + /** + * A unique identifier + */ + id: string | number; + /** + * A concise description of the slide content + */ + label: string; + }; + +export interface CarouselPaginationProps + extends HTMLAttributes { + /** + * The collection of slides that can be navigated using this component. + */ + slides: Slide[]; + /** + * The unique identifier of the current slide + */ + currentId: string | number; + /** + * Specify the nature of the slide content for the [`aria-current`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current) attribute. + * + * `page`: Represents the current page within a set of pages such as the link + * to the current document in a breadcrumb. + * + * `step`: Represents the current step within a process such as the current + * step in an enumerated multi step checkout flow. + */ + type?: 'page' | 'step'; +} + +/** + * The carousel pagination component allows users to navigate content that is + * divided into multiple slides or pages. + */ +export const CarouselPagination = forwardRef< + HTMLUListElement, + CarouselPaginationProps +>(({ slides, currentId, type, className, ...props }, ref) => { + const components = useComponents(); + const Link = components.Link as AsPropType; + + return ( +
    + {slides.map(({ id, label, ...item }) => { + let Element: AsPropType; + if (item.href) { + Element = Link; + } else if (item.onClick) { + Element = 'button'; + } else { + Element = 'span'; + } + return ( +
  • + + + {label} + +
  • + ); + })} +
+ ); +}); diff --git a/packages/circuit-ui/components/CarouselPagination/examples/Carousel.module.css b/packages/circuit-ui/components/CarouselPagination/examples/Carousel.module.css new file mode 100644 index 0000000000..a690ccc52f --- /dev/null +++ b/packages/circuit-ui/components/CarouselPagination/examples/Carousel.module.css @@ -0,0 +1,39 @@ +.wrapper { + display: flex; + flex-direction: column; + align-items: center; + max-width: 100vw; +} + +.slides { + display: flex; + gap: var(--cui-spacings-mega); + max-width: 100%; + padding: var(--cui-spacings-mega); + margin-right: calc(var(--cui-spacings-mega)); + margin-left: calc(-1 * var(--cui-spacings-mega)); + overflow-x: auto; + scroll-snap-type: x mandatory; + scroll-padding: var(--cui-spacings-mega); + scrollbar-width: none; + scroll-behavior: smooth; +} + +.slides::-webkit-scrollbar { + display: none; +} + +.slide { + flex-shrink: 0; + width: 80vw; + height: min(60vw, 80vh); + scroll-snap-align: start; +} + +.image { + width: 100%; + height: 100%; + object-fit: cover; + background: var(--cui-bg-highlight); + border-radius: var(--cui-border-radius-kilo); +} diff --git a/packages/circuit-ui/components/CarouselPagination/examples/Carousel.tsx b/packages/circuit-ui/components/CarouselPagination/examples/Carousel.tsx new file mode 100644 index 0000000000..054402c565 --- /dev/null +++ b/packages/circuit-ui/components/CarouselPagination/examples/Carousel.tsx @@ -0,0 +1,91 @@ +/** + * Copyright 2025, SumUp Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use client'; + +import { useEffect, useRef, useState } from 'react'; + +import { + CarouselPagination, + type CarouselPaginationProps, +} from '../CarouselPagination.js'; + +import classes from './Carousel.module.css'; + +type Slide = { + id: string; + label: string; + image?: { + src: string; + alt: string; + }; +}; + +export interface CarouselProps extends CarouselPaginationProps { + slides: Slide[]; +} + +export function Carousel({ + currentId: initialCurrentId, + slides, +}: CarouselProps) { + const trackRef = useRef(null); + const [currentId, setCurrentId] = useState(initialCurrentId || slides[0].id); + + useEffect(() => { + const trackEl = trackRef.current; + + if (!trackEl) { + return undefined; + } + + const handleScroll = () => { + const { scrollLeft, scrollWidth } = trackEl; + const index = Math.round((scrollLeft / scrollWidth) * slides.length); + + const id = slides[index]?.id; + + if (currentId !== id) { + setCurrentId(id); + } + }; + + trackEl.addEventListener('scroll', handleScroll); + + return () => { + trackEl.removeEventListener('scroll', handleScroll); + }; + }, [slides, currentId]); + + return ( +
+
+ {slides.map((slide) => ( +
+ {slide.image && ( + {slide.image.alt} + )} +
+ ))} +
+ +
+ ); +} diff --git a/packages/circuit-ui/components/Carousel/__fixtures__/index.ts b/packages/circuit-ui/components/CarouselPagination/index.ts similarity index 54% rename from packages/circuit-ui/components/Carousel/__fixtures__/index.ts rename to packages/circuit-ui/components/CarouselPagination/index.ts index 90d108dd16..90fe00cfe3 100644 --- a/packages/circuit-ui/components/Carousel/__fixtures__/index.ts +++ b/packages/circuit-ui/components/CarouselPagination/index.ts @@ -1,5 +1,5 @@ /** - * Copyright 2019, SumUp Ltd. + * Copyright 2024, SumUp Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,23 +13,6 @@ * limitations under the License. */ -export const SLIDES = [ - { - image: { - src: '/images/illustration-waves.jpg', - alt: 'Aerial photo of turbulent blue ocean waves', - }, - }, - { - image: { - src: '/images/illustration-waves-2.jpg', - alt: 'Aerial photo of turbulent turquoise ocean waves', - }, - }, - { - image: { - src: '/images/illustration-waves-3.jpg', - alt: 'Aerial photo of turbulent ocean water with white foam', - }, - }, -]; +export { CarouselPagination } from './CarouselPagination.js'; + +export type { CarouselPaginationProps } from './CarouselPagination.js'; diff --git a/packages/circuit-ui/components/Image/Image.stories.tsx b/packages/circuit-ui/components/Image/Image.stories.tsx index 5e00679927..7a869a75de 100644 --- a/packages/circuit-ui/components/Image/Image.stories.tsx +++ b/packages/circuit-ui/components/Image/Image.stories.tsx @@ -28,6 +28,6 @@ export default { export const Base = (args: ImageProps) => ; Base.args = { - src: '/images/illustration-waves.jpg', - alt: 'Aerial photo of turbulent blue-turquoise ocean waves', + src: '/images/sumup-tablet-insights.jpg', + alt: 'A tablet shows sales insights in the SumUp POS app. On the table next to it are a SumUp Solo card reader with printer and two bowls with fruits', }; diff --git a/packages/circuit-ui/components/Modal/Modal.stories.tsx b/packages/circuit-ui/components/Modal/Modal.stories.tsx index 89ea759ad0..2dc0f90f15 100644 --- a/packages/circuit-ui/components/Modal/Modal.stories.tsx +++ b/packages/circuit-ui/components/Modal/Modal.stories.tsx @@ -201,8 +201,8 @@ CustomStyles.args = { children: () => (
- {images.map((src) => ( + {images.map((image) => ( A random picture from Unsplash ))} diff --git a/packages/circuit-ui/components/Step/examples/YesOrNoSlider.tsx b/packages/circuit-ui/components/Step/examples/YesOrNoSlider.tsx index 90fa5fca5b..8ac2adaf2c 100644 --- a/packages/circuit-ui/components/Step/examples/YesOrNoSlider.tsx +++ b/packages/circuit-ui/components/Step/examples/YesOrNoSlider.tsx @@ -49,7 +49,7 @@ const Swipeable = ({ }; export interface YesOrNoSliderProps extends StepProps { - images: string[]; + images: { src: string; alt: string }[]; } export function YesOrNoSlider({ images, ...stepProps }: YesOrNoSliderProps) { @@ -84,8 +84,8 @@ export function YesOrNoSlider({ images, ...stepProps }: YesOrNoSliderProps) { > handleSwipe(eventData, actions)}> A random picture from Unsplash diff --git a/packages/circuit-ui/index.ts b/packages/circuit-ui/index.ts index f654e1ab4a..d93a7938b5 100644 --- a/packages/circuit-ui/index.ts +++ b/packages/circuit-ui/index.ts @@ -195,6 +195,8 @@ export { CarouselComposer, } from './components/Carousel/index.js'; export type { CarouselProps } from './components/Carousel/index.js'; +export { CarouselPagination } from './components/CarouselPagination/index.js'; +export type { CarouselPaginationProps } from './components/CarouselPagination/index.js'; export { Avatar } from './components/Avatar/index.js'; export type { AvatarProps } from './components/Avatar/index.js';