Skip to content

Commit

Permalink
fix: slider tab
Browse files Browse the repository at this point in the history
  • Loading branch information
giuliaghisini committed Mar 5, 2024
1 parent 9907cad commit 75e8a8c
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 122 deletions.
122 changes: 94 additions & 28 deletions src/components/ItaliaTheme/Blocks/Listing/Commons/utils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { useRef, useEffect } from 'react';
import {
NextArrow,
PrevArrow,
} from 'design-comuni-plone-theme/components/ItaliaTheme';

export const getCategory = (item, show_type, show_section, props) => {
let cat = [];
Expand All @@ -17,19 +21,11 @@ export const getCategory = (item, show_type, show_section, props) => {
}
return null;
};
export const visibleSlideTitle = (selector) => {
// Needed to deal with react-slick duplicating a lot of slides
// when used in infinite mode. It's an useless and counterproductive
// thing to do on their part, there are multiple issues opened.
// The lib is not actually mantained so...
return Array.from(document.querySelectorAll(selector)).find((e) => {
const rect = e.getBoundingClientRect();
return rect.left >= 0 && rect.right <= window.innerWidth;
});
};

export const useSlider = (userAutoplay) => {
export const useSlider = (userAutoplay, block_id) => {
const slider = useRef(null);
const sliderContainer = document.getElementById('outside-slider-' + block_id);
const sliderElement = document.querySelector(`#slider_${block_id}`);
const onIntersection = (entries, opt) => {
entries.forEach((entry) =>
entry.target.classList.toggle('visible', entry.isIntersecting),
Expand All @@ -39,49 +35,119 @@ export const useSlider = (userAutoplay) => {
root: null,
threshold: 0.5,
});
if (document.querySelector('.block.listing.slider'))
observer.observe(document.querySelector('.block.listing.slider'));

if (sliderContainer) observer.observe(sliderContainer);
useEffect(() => {
return () => observer.disconnect();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const focusNext = (currentSlide) => {
const sliderElement = document.querySelector('.block.listing.slider');
if (!sliderElement) return;
const sliderIsVisible = sliderElement.classList.contains('visible');
const sliderIsVisible = sliderContainer.classList.contains('visible');

if (!sliderIsVisible) {
slider.current.slickPause();
return;
}
const slide = sliderElement.querySelectorAll(
`a.slide-link[data-slide="${currentSlide}"]`,
const slide = sliderElement.querySelector(
`#slider_${block_id} .slick-slide[data-index="${currentSlide}"]`,
);

if ((userAutoplay && !slide) || (userAutoplay && !slide.length > 0)) return;

// Custom handling of focus for a11y
const link = visibleSlideTitle(
`a.slide-link[data-slide="${currentSlide}"]`,
);
if (userAutoplay && !slide) return;

if (!link || document.activeElement === link) {
if (!slide || document.activeElement === slide) {
return;
}
// eslint-disable-next-line no-unused-expressions
else if (
// if the focus was already on a slide, move it to the current one
Array.from(document.querySelectorAll('.slick-slide')).some((el) =>
el.contains(document.activeElement),
)
Array.from(
document.querySelectorAll(`#slider_${block_id} .slick-slide`),
).some((el) => el.contains(document.activeElement))
) {
link.focus();
slide.focus();
}
};

const visibleSlide = (selector) => {
// Needed to deal with react-slick duplicating a lot of slides
// when used in infinite mode. It's an useless and counterproductive
// thing to do on their part, there are multiple issues opened.
// The lib is not actually mantained so...

return Array.from(document.querySelectorAll(selector)).find((e) => {
const slick_slide = e.closest('.slick-slide');
return !slick_slide.classList.contains('slick-cloned');
});
};

const SliderNextArrow = (props) => {
// Custom handling of focus for a11y
const { className, style, onClick, currentSlide } = props;
const handleClick = (options) => {
onClick(options, false);
};
const handleKeyboardUsers = (e) => {
if (e.key === 'Tab' && e.shiftKey) {
e.stopPropagation();
e.preventDefault();

const slide = visibleSlide(
`#slider_${block_id} .slick-slide[data-index="${currentSlide}"]`,
);
slide && slide.focus();
}
};

return (
<NextArrow
className={className}
style={{ ...style }}
onClick={handleClick}
onKeyDown={handleKeyboardUsers}
id={'sliderNextArrow_' + block_id}
/>
);
};

const SliderPrevArrow = (props) => {
// Custom handling of focus for a11y
const { className, style, onClick, focusNext, currentSlide, slideCount } =
props;
const handleClick = (options) => {
onClick(options, false);
};
const handleKeyboardUsers = (e) => {
if (e.key === 'Tab' && !e.shiftKey) {
e.stopPropagation();
e.preventDefault();

if (currentSlide < slideCount) {
const slide = visibleSlide(
`#slider_${block_id} .slick-slide[data-index="${currentSlide}"]`,
);

slide && slide.focus();
} else focusNext(0, block_id);
}
};
return (
<PrevArrow
className={className}
style={{ ...style }}
onClick={handleClick}
onKeyDown={handleKeyboardUsers}
id={'sliderPrevArrow_' + block_id}
/>
);
};

return {
slider,
focusNext,
visibleSlide,
SliderNextArrow,
SliderPrevArrow,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const SimpleCardDefault = (props) => {
id_lighthouse,
rrule,
index,
handleKeyboardUsers = () => {}, //for slider template handler
} = props;

const getItemClass = (item) => {
Expand Down Expand Up @@ -119,6 +120,7 @@ const SimpleCardDefault = (props) => {
item={!isEditMode ? item : null}
href={isEditMode ? '#' : null}
data-element={id_lighthouse}
onKeyDown={handleKeyboardUsers}
>
{itemTitle}
</UniversalLink>
Expand Down
125 changes: 38 additions & 87 deletions src/components/ItaliaTheme/Blocks/Listing/SliderTemplate.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,13 @@ import {
SingleSlideWrapper,
CarouselWrapper,
ButtonPlayPause,
NextArrow,
PrevArrow,
} from 'design-comuni-plone-theme/components/ItaliaTheme';
import {
useSlider,
visibleSlideTitle,
} from 'design-comuni-plone-theme/components/ItaliaTheme/Blocks/Listing/Commons/utils';
import { useSlider } from 'design-comuni-plone-theme/components/ItaliaTheme/Blocks/Listing/Commons/utils';
import React, { useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import PropTypes from 'prop-types';
import cx from 'classnames';
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
import { v4 as uuid } from 'uuid';
import config from '@plone/volto/registry';

const messages = defineMessages({
Expand All @@ -41,67 +35,17 @@ const messages = defineMessages({
},
});

function SliderNextArrow(props) {
// Custom handling of focus for a11y
const { className, style, onClick, currentSlide, id } = props;
const handleClick = (options) => {
onClick(options, false);
};
const handleKeyboardUsers = (e) => {
if (e.key === 'Tab' && e.shiftKey) {
e.stopPropagation();
e.preventDefault();

const link = visibleSlideTitle(
`a.slide-link[data-slide="${currentSlide}"]`,
);
link && link.focus();
}
};

return (
<NextArrow
className={className}
style={{ ...style }}
onClick={handleClick}
onKeyDown={handleKeyboardUsers}
id={id}
/>
);
}

function SliderPrevArrow(props) {
// Custom handling of focus for a11y
const { className, style, onClick, focusNext, currentSlide, slideCount, id } =
props;
const handleClick = (options) => {
onClick(options, false);
};
const handleKeyboardUsers = (e) => {
if (e.key === 'Tab' && !e.shiftKey) {
e.stopPropagation();
e.preventDefault();
if (currentSlide < slideCount) {
const link = visibleSlideTitle(
`a.slide-link[data-slide="${currentSlide}"]`,
);
link && link.focus();
} else focusNext(0);
}
};
return (
<PrevArrow
className={className}
style={{ ...style }}
onClick={handleClick}
onKeyDown={handleKeyboardUsers}
id={id}
/>
);
}

const Slide = (props) => {
const { item, index, appearance, appearanceProp, block_id } = props;
const {
item,
index,
nextIndex,
prevIndex,
appearance,
appearanceProp,
block_id,
} = props;

const handleKeyboardUsers = (e) => {
const { key, shiftKey } = e;
if (key === 'Tab') {
Expand All @@ -112,10 +56,21 @@ const Slide = (props) => {
// if (userAutoplay) setUserAutoplay(false);
// slider.current.slickPause();
let elementToFocus;

if (shiftKey) {
elementToFocus = document.getElementById('sliderPrevArrow_' + block_id);
elementToFocus =
prevIndex != null
? document.querySelector(
`#slider_${block_id} .slick-slide[data-index="${prevIndex}"]`,
)
: document.getElementById('sliderPrevArrow_' + block_id);
} else
elementToFocus = document.getElementById('sliderNextArrow_' + block_id);
elementToFocus =
nextIndex != null
? document.querySelector(
`#slider_${block_id} .slick-slide[data-index="${nextIndex}"]`,
)
: document.getElementById('sliderNextArrow_' + block_id);
elementToFocus.focus();
}
};
Expand Down Expand Up @@ -154,9 +109,10 @@ const SliderTemplate = ({
autoplay_speed = 2, //seconds
slide_appearance = 'default',
reactSlick,
...appearanceProp
block,
...otherProps
}) => {
const block_id = uuid();
const block_id = block;
const intl = useIntl();

const [userAutoplay, setUserAutoplay] = useState(autoplay);
Expand All @@ -165,7 +121,11 @@ const SliderTemplate = ({
? items.length
: parseInt(slidesToShow);
const Slider = reactSlick.default;
const { slider, focusNext } = useSlider(userAutoplay);
const { slider, focusNext, SliderNextArrow, SliderPrevArrow } = useSlider(
userAutoplay,
block_id,
);

const toggleAutoplay = () => {
if (!slider?.current) return;
if (userAutoplay) {
Expand Down Expand Up @@ -237,20 +197,8 @@ const SliderTemplate = ({
focusOnSelect: false,
draggable: true,
accessibility: true,
nextArrow: (
<SliderNextArrow
intl={intl}
focusNext={focusNext}
id={'sliderNextArrow_' + block_id}
/>
),
prevArrow: (
<SliderPrevArrow
intl={intl}
focusNext={focusNext}
id={'sliderPrevArrow_' + block_id}
/>
),
nextArrow: <SliderNextArrow intl={intl} focusNext={focusNext} />,
prevArrow: <SliderPrevArrow intl={intl} focusNext={focusNext} />,
appendDots: renderCustomDots,
// Custom handling of focus for a11y
afterChange: focusNext,
Expand All @@ -271,6 +219,7 @@ const SliderTemplate = ({
'no-margin': full_width,
['appearance_' + slide_appearance]: slide_appearance,
})}
id={'slider_' + block_id}
>
<Container className="px-4">
{title && (
Expand Down Expand Up @@ -305,6 +254,8 @@ const SliderTemplate = ({
<Slide
image={image}
index={index}
nextIndex={index + 1 === items.length ? null : index + 1}
prevIndex={index - 1 === -1 ? null : index - 1}
full_width={full_width}
item={item}
show_image_title={show_image_title}
Expand All @@ -313,7 +264,7 @@ const SliderTemplate = ({
userAutoplay={userAutoplay}
slider={slider}
appearance={slide_appearance}
appearanceProp={appearanceProp}
appearanceProp={otherProps}
block_id={block_id}
/>
);
Expand Down
Loading

0 comments on commit 75e8a8c

Please sign in to comment.