Skip to content

Commit

Permalink
chore: moved useSlider in dedicated file
Browse files Browse the repository at this point in the history
  • Loading branch information
giuliaghisini committed Mar 6, 2024
1 parent 8e694a2 commit 62402d7
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 196 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ const CardWithImageDefault = (props) => {
item={!isEditMode ? item : null}
href={isEditMode ? '#' : ''}
data-element={id_lighthouse}
tabIndex={0}
>
{item.title || item.id}
</UniversalLink>
Expand Down
177 changes: 0 additions & 177 deletions src/components/ItaliaTheme/Blocks/Listing/Commons/utils.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
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 @@ -21,174 +15,3 @@ export const getCategory = (item, show_type, show_section, props) => {
}
return null;
};

export const useSlider = (userAutoplay, block_id) => {
const slider = useRef(null);
const sliderContainer = document.getElementById('outside-slider-' + block_id);
const sliderElementSelector = `#slider_${block_id}`;
const sliderElement = document.querySelector(sliderElementSelector);
const onIntersection = (entries, opt) => {
entries.forEach((entry) =>
entry.target.classList.toggle('visible', entry.isIntersecting),
);
};
const observer = new IntersectionObserver(onIntersection, {
root: null,
threshold: 0.5,
});

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

const focusSlide = (slideIndex) => {
if (!sliderElement) return;
const sliderIsVisible = sliderContainer.classList.contains('visible');

if (!sliderIsVisible) {
slider.current.slickPause();
return;
}

const slide = document.querySelector(
`${sliderElementSelector} .slick-slide[data-index="${slideIndex}"] .it-single-slide-wrapper`,
);

if (userAutoplay && !slide) return;

if (!slide || document.activeElement === slide) {
return;
}

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(
`${sliderElementSelector} .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, 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(
`${sliderElementSelector} .slick-slide[data-index="${currentSlide}"]`,
);

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

const handleSlideKeydown = (index, prevIndex, nextIndex) => (e) => {
const { key, shiftKey } = e;

if (key === 'Tab') {
const slide_selector = `#slider_${block_id} .slick-slide[data-index="${index}"]`;

const focusableSlideElements = document.querySelectorAll(
`${slide_selector} a, ${slide_selector} button, ${slide_selector} [tabindex="0"]`,
);
const isFirstSlideFocusableElement =
e.target === focusableSlideElements[0];
const isLastSlideFocusableElement =
e.target === focusableSlideElements[focusableSlideElements.length - 1];

if (
(isFirstSlideFocusableElement && shiftKey) ||
(isLastSlideFocusableElement && !shiftKey)
) {
e.preventDefault();
e.stopPropagation();
//shift+tab ed è il primo elemento focusabile nella slide, oppure tab ed è l'ultimo elemento focusabile nella slide
//go to next/prev slide or to next/prev button.
} else {
return; //continue doing default bhv of Tab key, to focus next focusable element inside slide.
}

// Keeping auto pause off for now
// if (userAutoplay) setUserAutoplay(false);
// slider.current.slickPause();

if (shiftKey) {
if (prevIndex != null) {
slider.current.slickGoTo(prevIndex);
} else {
document.getElementById('sliderPrevArrow_' + block_id).focus();
}
} else {
if (nextIndex != null) {
slider.current.slickGoTo(nextIndex);
} else {
document.getElementById('sliderNextArrow_' + block_id).focus();
}
}
}
};

return {
slider,
focusSlide,
visibleSlide,
SliderNextArrow,
SliderPrevArrow,
handleSlideKeydown,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ const SimpleCardDefault = (props) => {
item={!isEditMode ? item : null}
href={isEditMode ? '#' : null}
data-element={id_lighthouse}
tabIndex={0}
>
{itemTitle}
</UniversalLink>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const SlideItemDefault = ({
setUserAutoplay,
userAutoplay,
slider,
messages,
}) => {
return (
<React.Fragment>
Expand All @@ -26,7 +25,6 @@ const SlideItemDefault = ({
<div className="slide-title">
<UniversalLink
item={item}
title={intl.formatMessage(messages.viewImage)}
tabIndex={0}
data-slide={index}
className={'slide-link no-external-if-link'}
Expand Down
21 changes: 8 additions & 13 deletions src/components/ItaliaTheme/Blocks/Listing/SliderTemplate.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
CarouselWrapper,
ButtonPlayPause,
} from 'design-comuni-plone-theme/components/ItaliaTheme';
import { useSlider } from 'design-comuni-plone-theme/components/ItaliaTheme/Blocks/Listing/Commons/utils';
import { useSlider } from 'design-comuni-plone-theme/components/ItaliaTheme/Slider/slider';
import React, { useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import PropTypes from 'prop-types';
Expand All @@ -20,8 +20,8 @@ import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
import config from '@plone/volto/registry';

const messages = defineMessages({
viewImage: {
id: 'viewImage',
carouselItemAriaLabel: {
id: 'carousel-item-aria-label',
defaultMessage:
'Sei attualmente in un carosello, per navigare usa le frecce sinistra e destra',
},
Expand All @@ -36,6 +36,7 @@ const messages = defineMessages({
});

const Slide = (props) => {
const intl = useIntl();
const { item, index, appearance, appearanceProp, onKeyDown } = props;

const appearances = config.blocks.blocksConfig.listing.variations.filter(
Expand All @@ -48,13 +49,10 @@ const Slide = (props) => {
key={item['@id'] + index}
index={index}
onKeyDown={onKeyDown}
aria-label={intl.formatMessage(messages.carouselItemAriaLabel)}
>
<div className={'slide-wrapper'} role="presentation">
<SlideItemAppearance
{...props}
{...appearanceProp}
messages={messages}
/>
<SlideItemAppearance {...props} {...appearanceProp} />
</div>
</SingleSlideWrapper>
);
Expand Down Expand Up @@ -93,7 +91,7 @@ const SliderTemplate = ({
SliderNextArrow,
SliderPrevArrow,
handleSlideKeydown,
} = useSlider(userAutoplay, block_id);
} = useSlider(userAutoplay, setUserAutoplay, block_id);

const toggleAutoplay = () => {
if (!slider?.current) return;
Expand Down Expand Up @@ -219,19 +217,16 @@ const SliderTemplate = ({
sizes: `max-width(991px) 620px, ${1300 / nSlidesToShow}px`,
critical: true,
});
const nextIndex = index < items.length ? index + 1 : null;
const nextIndex = index < items.length - 1 ? index + 1 : null;
const prevIndex = index > 0 ? index - 1 : null;
return (
<Slide
image={image}
index={index}
nextIndex={index < items.length ? index + 1 : null}
prevIndex={index > 0 ? index - 1 : null}
full_width={full_width}
item={item}
show_image_title={show_image_title}
intl={intl}
setUserAutoplay={setUserAutoplay}
userAutoplay={userAutoplay}
slider={slider}
appearance={slide_appearance}
Expand Down
10 changes: 6 additions & 4 deletions src/components/ItaliaTheme/Slider/SingleSlideWrapper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ const messages = defineMessages({
defaultMessage: 'Slide',
},
});
const SingleSlideWrapper = ({ className, key, index, children, onKeyDown }) => {
const SingleSlideWrapper = (props) => {
const { className, key, index, children, onKeyDown } = props;
const intl = useIntl();
const wrapperKey = key ?? 'slide-wrapper-' + index;

Expand All @@ -15,12 +16,13 @@ const SingleSlideWrapper = ({ className, key, index, children, onKeyDown }) => {
className={`it-single-slide-wrapper ${className ?? ''}`}
key={wrapperKey}
data-slide={index}
role="button"
aria-roledescription="group"
role="group"
aria-label={
intl.formatMessage(messages.carouselSlide) +
' ' +
(index ? index + 1 : '')
(index ? index + 1 : '') +
' - ' +
(props['aria-label'] ?? '')
}
onKeyDown={onKeyDown}
onClick={(e) => {
Expand Down
Loading

0 comments on commit 62402d7

Please sign in to comment.