Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add Image Slider component #1595

Merged
merged 73 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
3d93145
Scaffold pre-observers
dlnr Jul 16, 2024
f986c7c
Testing intersection observers
dlnr Jul 18, 2024
4644b89
Merge branch 'develop' of https://github.com/Amsterdam/design-system …
dlnr Jul 18, 2024
05b3155
Working intersectionObserver
dlnr Jul 19, 2024
dd01ba1
Test fix
dlnr Jul 19, 2024
01d17c2
Merge branch 'develop' of https://github.com/Amsterdam/design-system …
dlnr Jul 19, 2024
175af14
Scrollbar and snapstop options
dlnr Jul 22, 2024
c33e0f0
Previous and Next slide functions
dlnr Jul 22, 2024
7678973
Merge branch 'develop' of https://github.com/Amsterdam/design-system …
dlnr Jul 23, 2024
15f4794
Interactions and thumbnails testing
dlnr Jul 26, 2024
cd3e6c3
Thumbnails
dlnr Jul 26, 2024
d156035
Cleaning
dlnr Jul 26, 2024
23b6910
Some testing
dlnr Jul 26, 2024
c26634e
Some documentation and stories
dlnr Jul 26, 2024
cf8b78f
REfresh not needed
dlnr Jul 26, 2024
8fb8b3b
Aria roles for thumbnails
dlnr Jul 26, 2024
a3e244e
Snapstop on as default
dlnr Jul 26, 2024
c1e07ef
Mixed sizes story for demo purposes
dlnr Jul 26, 2024
a0793bf
Typo
dlnr Jul 26, 2024
bcfd07a
Thumbnail aria testing
dlnr Jul 26, 2024
6844fdf
Alt tekst (testing screen reader)
dlnr Jul 26, 2024
c178452
Translatable labels
dlnr Jul 26, 2024
f66c42e
ImageSliderItem test
dlnr Jul 26, 2024
39f5503
ImageSliderScroller test
dlnr Jul 26, 2024
869ee47
Thumbnails test
dlnr Jul 26, 2024
75464dc
Merge branch 'develop' into feature/DES-869-image-slider
RubenSibon Aug 2, 2024
a6bc6c8
Merge branch 'develop' of https://github.com/Amsterdam/design-system …
dlnr Aug 12, 2024
7a8ccb9
Merge branch 'feature/DES-869-image-slider' of https://github.com/Ams…
dlnr Aug 12, 2024
5c7290d
Contrast color prop change
dlnr Aug 12, 2024
9cd66b5
Ok now you need two props
dlnr Aug 12, 2024
be167b0
Thumbnail hover effect
dlnr Aug 12, 2024
1cab90a
Getting used to new button props
dlnr Aug 12, 2024
d063e4a
Merge branch 'develop' of https://github.com/Amsterdam/design-system …
dlnr Sep 12, 2024
308a999
Removed various sizes story
dlnr Sep 12, 2024
f11504f
Screen decorator for max-width
dlnr Sep 13, 2024
831a7a5
Merge branch 'develop' of https://github.com/Amsterdam/design-system …
dlnr Sep 20, 2024
d877ef1
Removed outline in favor of opacity effect
dlnr Sep 20, 2024
d2bd221
Refactored to use an object
dlnr Sep 20, 2024
5ab2cfd
Test corrections
dlnr Sep 20, 2024
12867ce
Thumbnails keyboard control
dlnr Sep 23, 2024
6c26a17
JSdoc prop description
dlnr Sep 23, 2024
1c336c8
Source set images story
dlnr Sep 23, 2024
c1e3a70
Merge branch 'develop' of https://github.com/Amsterdam/design-system …
dlnr Sep 27, 2024
e1e272a
Always use thumbnails and never show scroller
dlnr Sep 27, 2024
4c8b2e1
Test fix
dlnr Sep 27, 2024
f271005
Some comment resolutions
dlnr Sep 30, 2024
744327e
Rename map
dlnr Sep 30, 2024
ce03bbb
Hide controls when primary input is not a mouse
dlnr Sep 30, 2024
4b9732a
Lower breakpoint, buttons are only too big for phones
dlnr Sep 30, 2024
a04208d
Comments
dlnr Sep 30, 2024
9aca20a
Error fix
dlnr Sep 30, 2024
7f57b76
Thumbnail functions moved
dlnr Oct 1, 2024
f50ef71
Removed comment
dlnr Oct 1, 2024
11f670b
Merge branch 'develop' of https://github.com/Amsterdam/design-system …
dlnr Oct 1, 2024
ed42e6a
Test fix
dlnr Oct 1, 2024
c821453
Moved controls to dedicated file
dlnr Oct 1, 2024
7026b6c
Moved scroller to dedicated file
dlnr Oct 1, 2024
f13eafb
Revert "Moved scroller to dedicated file"
dlnr Oct 2, 2024
6f7a3f6
Revert "Moved controls to dedicated file"
dlnr Oct 2, 2024
84942f5
Move controls again
dlnr Oct 2, 2024
92836a7
Controls test
dlnr Oct 2, 2024
263052e
Status badge
dlnr Oct 2, 2024
b8ce020
Sort all the things
VincentSmedinga Oct 3, 2024
fd82102
Add documentation
VincentSmedinga Oct 3, 2024
8e28d2b
Use full name for aspect ratio prop
VincentSmedinga Oct 3, 2024
c9c9e18
Make variable names more precise
VincentSmedinga Oct 3, 2024
95f5721
Replace switch with lookup table
VincentSmedinga Oct 3, 2024
66ccd62
Make variable names more precise
VincentSmedinga Oct 3, 2024
1fa45b3
Improve rendering performance
VincentSmedinga Oct 3, 2024
3dd85db
Update docs
VincentSmedinga Oct 3, 2024
216ee9f
Update scroll position after resize or orientation change
VincentSmedinga Oct 3, 2024
62a9403
Prevent unnecessary slide after resize or orientation change
VincentSmedinga Oct 3, 2024
45a23f0
Merge branch 'develop' into feature/DES-869-image-slider-object
VincentSmedinga Oct 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions packages/css/src/components/image-slider/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!-- @license CC0-1.0 -->

# Image Slider

Displays a small set of images in a limited space.

## Design

The first or selected image shows at its maximum size.
Every image displays a thumbnail at about 20% of its width.
Users can use buttons, thumbnails or swiping to navigate between the images.
The buttons re not displayed on a narrow touch device.
The images do not slide automatically.

## How to use

- Use this for a series of images that belong together.
- Feature the most essential image first.
- Display the Image Slider at the entire width of the [Screen](/docs/components-layout-screen--docs); do not position it on the [Grid](/docs/components-layout-grid--docs).
- Provide at least 2 images but at most 5.
- Assume that some or many users will not use the Slider and only see the first image.
Display all images separately if you want each of them to receive attention.
- Consult the [Image](/docs/components-media-image--docs) docs for guidelines on the individual images.
89 changes: 89 additions & 0 deletions packages/css/src/components/image-slider/image-slider.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* @license EUPL-1.2+
* Copyright Gemeente Amsterdam
*/
@import "../../common/breakpoint";

.ams-image-slider {
display: grid;
gap: var(--ams-image-slider-gap);
grid-template-rows: 1fr auto;
}

.ams-image-slider__item {
scroll-snap-align: center;
scroll-snap-stop: always;

/** temporary fix for covering the entire gallery */
.ams-image {
inline-size: 100%;
}
}

.ams-image-slider__scroller {
align-items: center;
display: grid;
gap: var(--ams-image-slider-scroller-gap);
grid-auto-columns: 100%;
grid-auto-flow: column;
grid-column: 1/-1;
grid-row: 1;
outline-offset: var(--ams-image-slider-scroller-outline-offset);
overflow-x: auto;
overscroll-behavior-x: contain;
scroll-snap-type: x mandatory;
scrollbar-width: none;

&::-webkit-scrollbar {
display: none;
}

@media not (prefers-reduced-motion) {
scroll-behavior: smooth;
}
}

.ams-image-slider__controls {
display: flex;
grid-column: 1/-1;
grid-row: 1;
justify-content: space-between;

@media (pointer: coarse) and (max-width: $ams-breakpoint-medium) {
display: none;
}
RubenSibon marked this conversation as resolved.
Show resolved Hide resolved
}

.ams-image-slider__control {
place-self: center;
z-index: 1;
}

.ams-image-slider__thumbnails {
display: grid;
gap: var(--ams-image-slider-thumbnails-gap);
grid-template-columns: repeat(5, 1fr);
max-inline-size: 100%;
}

.ams-image-slider__thumbnail {
background-color: var(--ams-image-slider-thumbnails-thumbnail-background-color);
background-position: center;
background-size: cover;
border: none;
cursor: var(--ams-image-slider-thumbnails-thumbnail-cursor);
opacity: var(--ams-image-slider-thumbnails-thumbnail-opacity);
outline-offset: var(--ams-button-outline-offset);
padding-block: 0;
padding-inline: 0;
position: relative;
scroll-snap-align: start;

&:hover {
opacity: var(--ams-image-slider-thumbnails-thumbnail-hover-opacity);
}
}

.ams-image-slider__thumbnail--in-view {
opacity: var(--ams-image-slider-thumbnails-thumbnail-in-view-opacity);
}
1 change: 1 addition & 0 deletions packages/css/src/components/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
@import "./hint/hint";
@import "./password-input/password-input";
@import "./form-error-list/form-error-list";
@import "./image-slider/image-slider";
@import "./table-of-contents/table-of-contents";
@import "./error-message/error-message";
@import "./file-input/file-input";
Expand Down
1 change: 1 addition & 0 deletions packages/css/src/components/screen/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Manages the maximum width and alignment of the entire website or application.
[Header](/docs/components-containers-header--docs),
[Footer](/docs/components-containers-footer--docs),
[Spotlight](/docs/components-containers-spotlight--docs),
[Image Slider](/docs/components-containers-spotlight--docs),
and Figure.

## Design
Expand Down
1 change: 1 addition & 0 deletions packages/css/src/components/spotlight/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Emphasizes a section on a page through a distinctive background colour.

## Guidelines

- Display the Spotlight at the entire width of the [Screen](/docs/components-layout-screen--docs); do not position it on the [Grid](/docs/components-layout-grid--docs).
- Refer to [this overview on Stijlweb](https://amsterdam.nl/stijlweb/basiselementen/kleuren/#PagCls_15671872) to determine whether you can use black or white text on the background colour of your choice.

## Relevant WCAG requirements
Expand Down
89 changes: 89 additions & 0 deletions packages/react/src/ImageSlider/ImageSlider.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { render } from '@testing-library/react'
import { createRef } from 'react'
import { ImageSlider, ImageSliderImageProps } from './ImageSlider'
import '@testing-library/jest-dom'

const observe = jest.fn()
const unobserve = jest.fn()
const disconnect = jest.fn()
const takeRecords = jest.fn()

// Mock implementation of IntersectionObserver
window.IntersectionObserver = jest.fn(() => ({
observe,
unobserve,
disconnect,
takeRecords,
root: null,
rootMargin: '',
thresholds: [],
}))

describe('Image Slider', () => {
const images: ImageSliderImageProps[] = [
{
alt: 'Bridge',
aspectRatio: 'x-wide',
src: 'https://picsum.photos/id/122/320/180',
},
{
alt: 'Bunker',
aspectRatio: 'x-wide',
src: 'https://picsum.photos/id/101/320/180',
},
{
alt: 'Chairs',
aspectRatio: 'x-wide',
src: 'https://picsum.photos/id/153/320/180',
},
]

it('renders', () => {
const { container } = render(<ImageSlider images={images} />)

const component = container.querySelector(':only-child')

expect(component).toBeInTheDocument()
expect(component).toBeVisible()
})

it('renders slides', () => {
const { container } = render(<ImageSlider images={images} />)

const slides = Array.from(container.querySelectorAll('.ams-image-slider__item'))

expect(slides).toHaveLength(3)
})

it('renders a design system BEM class name', () => {
const { container } = render(<ImageSlider images={images} />)

const component = container.querySelector(':only-child')

expect(component).toHaveClass('ams-image-slider')
})

it('renders an additional class name', () => {
const { container } = render(<ImageSlider className="extra" images={images} />)

const component = container.querySelector(':only-child')

expect(component).toHaveClass('ams-image-slider extra')
})

it('supports ForwardRef in React', () => {
const ref = createRef<HTMLDivElement>()

const { container } = render(<ImageSlider images={images} ref={ref} />)

const component = container.querySelector(':only-child')

expect(ref.current).toBe(component)
})

it('renders thumbnails', () => {
const { container } = render(<ImageSlider images={images} />)

expect(container.querySelector('.ams-image-slider__thumbnails')).toBeInTheDocument()
})
})
Loading