@lumx/react 3.9.2 → 3.9.4-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -6,8 +6,8 @@
6
6
  "url": "https://github.com/lumapps/design-system/issues"
7
7
  },
8
8
  "dependencies": {
9
- "@lumx/core": "^3.9.2",
10
- "@lumx/icons": "^3.9.2",
9
+ "@lumx/core": "^3.9.4-alpha.0",
10
+ "@lumx/icons": "^3.9.4-alpha.0",
11
11
  "@popperjs/core": "^2.5.4",
12
12
  "body-scroll-lock": "^3.1.5",
13
13
  "classnames": "^2.3.2",
@@ -39,6 +39,7 @@
39
39
  "@testing-library/user-event": "^14.4.3",
40
40
  "@types/body-scroll-lock": "^2.6.1",
41
41
  "@types/classnames": "^2.2.9",
42
+ "@types/dom-view-transitions": "^1.0.5",
42
43
  "@types/jest": "^29.2.1",
43
44
  "@types/lodash": "^4.14.149",
44
45
  "@types/react": "^17.0.2",
@@ -110,5 +111,5 @@
110
111
  "build:storybook": "storybook build"
111
112
  },
112
113
  "sideEffects": false,
113
- "version": "3.9.2"
114
+ "version": "3.9.4-alpha.0"
114
115
  }
@@ -3,8 +3,9 @@ import React from 'react';
3
3
  import { render, screen, waitFor } from '@testing-library/react';
4
4
  import { getByClassName, queryByClassName } from '@lumx/react/testing/utils/queries';
5
5
  import { commonTestsSuiteRTL } from '@lumx/react/testing/utils';
6
-
7
6
  import userEvent from '@testing-library/user-event';
7
+ import { VISUALLY_HIDDEN } from '@lumx/react/constants';
8
+
8
9
  import { DatePickerControlled, DatePickerControlledProps } from './DatePickerControlled';
9
10
  import { CLASSNAME } from './constants';
10
11
 
@@ -39,7 +40,7 @@ const queries = {
39
40
  screen.getByRole('spinbutton', {
40
41
  name: /année/i,
41
42
  }),
42
- getAccessibleMonthYear: (container: HTMLElement) => getByClassName(container, 'visually-hidden'),
43
+ getAccessibleMonthYear: (container: HTMLElement) => getByClassName(container, VISUALLY_HIDDEN),
43
44
  };
44
45
 
45
46
  describe(`<${DatePickerControlled.displayName}>`, () => {
@@ -13,6 +13,7 @@ import { getYearDisplayName } from '@lumx/react/utils/date/getYearDisplayName';
13
13
  import { onEnterPressed } from '@lumx/react/utils/event';
14
14
  import { addMonthResetDay } from '@lumx/react/utils/date/addMonthResetDay';
15
15
  import { formatDayNumber } from '@lumx/react/utils/date/formatDayNumber';
16
+ import { VISUALLY_HIDDEN } from '@lumx/react/constants';
16
17
  import { CLASSNAME } from './constants';
17
18
 
18
19
  /**
@@ -147,7 +148,7 @@ export const DatePickerControlled: Comp<DatePickerControlledProps, HTMLDivElemen
147
148
  }
148
149
  label={
149
150
  <>
150
- <span aria-live={labelAriaLive} className={onMonthChange ? 'visually-hidden' : ''} dir="auto">
151
+ <span aria-live={labelAriaLive} className={onMonthChange ? VISUALLY_HIDDEN : ''} dir="auto">
151
152
  {monthYear}
152
153
  </span>
153
154
  {onMonthChange && (
@@ -222,7 +223,7 @@ export const DatePickerControlled: Comp<DatePickerControlledProps, HTMLDivElemen
222
223
  onClick={() => onChange(date)}
223
224
  >
224
225
  <span aria-hidden>{formatDayNumber(locale, date)}</span>
225
- <span className="visually-hidden">
226
+ <span className={VISUALLY_HIDDEN}>
226
227
  {date.toLocaleDateString(locale, {
227
228
  day: 'numeric',
228
229
  month: 'long',
@@ -55,6 +55,8 @@ const Inner: Comp<ImageLightboxProps, HTMLDivElement> = forwardRef((props, ref)
55
55
  closeButtonProps={closeButtonProps}
56
56
  focusElement={currentPaginationItemRef}
57
57
  {...forwardedProps}
58
+ // Disable the close on click away as we want a custom one here
59
+ preventAutoClose
58
60
  >
59
61
  <ClickAwayProvider childrenRefs={clickAwayChildrenRefs} callback={onClickAway}>
60
62
  <ImageSlideshow
@@ -31,6 +31,7 @@ export const ImageSlideshow: React.FC<ImageSlideshowProps> = ({
31
31
  activeIndex,
32
32
  slideshowId,
33
33
  setSlideshow,
34
+ slideshow,
34
35
  slideshowSlidesId,
35
36
  slidesCount,
36
37
  onNextClick,
@@ -61,6 +62,7 @@ export const ImageSlideshow: React.FC<ImageSlideshowProps> = ({
61
62
  onNextClick={onNextClick}
62
63
  onPreviousClick={onPreviousClick}
63
64
  onPaginationClick={onPaginationClick}
65
+ parentRef={slideshow}
64
66
  {...slideshowControlsProps}
65
67
  paginationItemProps={(index: number) => {
66
68
  const props = slideshowControlsProps?.paginationItemProps?.(index) || {};
@@ -109,7 +109,7 @@ export function useImageLightbox<P extends Partial<ImageLightboxProps>>(
109
109
  isOpen: true,
110
110
  onClose: () => {
111
111
  close();
112
- prevProps?.onClose?.();
112
+ propsRef.current?.onClose?.();
113
113
  },
114
114
  images,
115
115
  activeImageIndex: activeImageIndex || 0,
@@ -6,6 +6,7 @@ import classNames from 'classnames';
6
6
  import { FULL_WIDTH_PERCENT } from '@lumx/react/components/slideshow/constants';
7
7
  import { Comp, GenericProps, HasTheme } from '@lumx/react/utils/type';
8
8
  import { getRootClassName, handleBasicClasses } from '@lumx/react/utils/className';
9
+ import { useMergeRefs } from '@lumx/react/utils/mergeRefs';
9
10
  import { buildSlideShowGroupId, SlideshowItemGroup } from './SlideshowItemGroup';
10
11
 
11
12
  export interface SlidesProps extends GenericProps, HasTheme {
@@ -32,7 +33,7 @@ export interface SlidesProps extends GenericProps, HasTheme {
32
33
  /**
33
34
  * Accessible label to set on a slide group.
34
35
  * Receives the group position starting from 1 and the total number of groups.
35
- * */
36
+ */
36
37
  slideGroupLabel?: (groupPosition: number, groupTotal: number) => string;
37
38
  }
38
39
 
@@ -70,7 +71,6 @@ export const Slides: Comp<SlidesProps, HTMLDivElement> = forwardRef((props, ref)
70
71
  slideGroupLabel,
71
72
  ...forwardedProps
72
73
  } = props;
73
- const wrapperRef = React.useRef<HTMLDivElement>(null);
74
74
  const startIndexVisible = activeIndex;
75
75
  const endIndexVisible = startIndexVisible + 1;
76
76
 
@@ -82,10 +82,12 @@ export const Slides: Comp<SlidesProps, HTMLDivElement> = forwardRef((props, ref)
82
82
  return groupBy && groupBy > 1 ? chunk(childrenArray, groupBy) : childrenArray;
83
83
  }, [children, groupBy]);
84
84
 
85
+ const slidesRef = React.useRef<HTMLDivElement>(null);
86
+
85
87
  return (
86
88
  <section
87
89
  id={id}
88
- ref={ref}
90
+ ref={useMergeRefs(slidesRef, ref)}
89
91
  {...forwardedProps}
90
92
  className={classNames(className, handleBasicClasses({ prefix: CLASSNAME, theme }), {
91
93
  [`${CLASSNAME}--fill-height`]: fillHeight,
@@ -100,14 +102,14 @@ export const Slides: Comp<SlidesProps, HTMLDivElement> = forwardRef((props, ref)
100
102
  onMouseLeave={toggleAutoPlay}
101
103
  aria-live={isAutoPlaying ? 'off' : 'polite'}
102
104
  >
103
- <div ref={wrapperRef} className={`${CLASSNAME}__wrapper`} style={wrapperStyle}>
105
+ <div className={`${CLASSNAME}__wrapper`} style={wrapperStyle}>
104
106
  {groups.map((group, index) => (
105
107
  <SlideshowItemGroup
106
108
  key={index}
107
109
  id={slidesId && buildSlideShowGroupId(slidesId, index)}
108
- role={hasControls ? 'tabpanel' : 'group'}
109
110
  label={slideGroupLabel ? slideGroupLabel(index + 1, groups.length) : undefined}
110
111
  isDisplayed={index >= startIndexVisible && index < endIndexVisible}
112
+ slidesRef={slidesRef}
111
113
  >
112
114
  {group}
113
115
  </SlideshowItemGroup>
@@ -1,6 +1,7 @@
1
+ /* eslint-disable jsx-a11y/anchor-is-valid */
1
2
  import React from 'react';
2
3
  import range from 'lodash/range';
3
- import { AspectRatio, Button, FlexBox, ImageBlock, Slideshow, SlideshowItem, Orientation } from '@lumx/react';
4
+ import { AspectRatio, Button, FlexBox, ImageBlock, Slideshow, SlideshowItem, Orientation, Link } from '@lumx/react';
4
5
  import { IMAGES, LANDSCAPE_IMAGES } from '@lumx/react/stories/controls/image';
5
6
 
6
7
  export default {
@@ -65,6 +66,16 @@ export const ResponsiveSlideShowSwipe = () => {
65
66
  }}
66
67
  slideGroupLabel={(currentGroup, totalGroup) => `${currentGroup} of ${totalGroup}`}
67
68
  >
69
+ <SlideshowItem>
70
+ <FlexBox
71
+ style={{ border: '1px solid grey', maxWidth: 300, height: 300 }}
72
+ hAlign="center"
73
+ vAlign="center"
74
+ >
75
+ <Link href="#">A link</Link>
76
+ <Button>A button</Button>
77
+ </FlexBox>
78
+ </SlideshowItem>
68
79
  {slides.map((slide) => (
69
80
  <SlideshowItem key={`${slide}`}>
70
81
  <FlexBox
@@ -1,11 +1,10 @@
1
1
  import React, { forwardRef } from 'react';
2
2
 
3
3
  import { SlideshowControls, SlideshowControlsProps, Theme, Slides, SlidesProps } from '@lumx/react';
4
- import { DEFAULT_OPTIONS } from '@lumx/react/hooks/useSlideshowControls';
5
4
  import { Comp, GenericProps } from '@lumx/react/utils/type';
6
5
  import { useFocusWithin } from '@lumx/react/hooks/useFocusWithin';
7
6
  import { mergeRefs } from '@lumx/react/utils/mergeRefs';
8
- import { buildSlideShowGroupId } from './SlideshowItemGroup';
7
+ import { DEFAULT_OPTIONS } from './useSlideshowControls';
9
8
 
10
9
  /**
11
10
  * Defines the props of the component.
@@ -14,7 +13,7 @@ export interface SlideshowProps
14
13
  extends GenericProps,
15
14
  Pick<SlidesProps, 'autoPlay' | 'slidesId' | 'id' | 'theme' | 'fillHeight' | 'groupBy' | 'slideGroupLabel'> {
16
15
  /** current slide active */
17
- activeIndex?: SlidesProps['activeIndex'];
16
+ activeIndex?: number;
18
17
  /** Interval between each slide when automatic rotation is enabled. */
19
18
  interval?: number;
20
19
  /** Props to pass to the slideshow controls (minus those already set by the Slideshow props). */
@@ -134,27 +133,14 @@ export const Slideshow: Comp<SlideshowProps, HTMLDivElement> = forwardRef((props
134
133
  parentRef={slideshow}
135
134
  theme={theme}
136
135
  isAutoPlaying={isAutoPlaying}
137
- nextButtonProps={{
138
- 'aria-controls': slideshowSlidesId,
139
- ...slideshowControlsProps.nextButtonProps,
140
- }}
141
- previousButtonProps={{
142
- 'aria-controls': slideshowSlidesId,
143
- ...slideshowControlsProps.previousButtonProps,
144
- }}
145
136
  playButtonProps={
146
137
  autoPlay
147
138
  ? {
148
- 'aria-controls': slideshowSlidesId,
149
139
  onClick: toggleForcePause,
150
140
  ...slideshowControlsProps.playButtonProps,
151
141
  }
152
142
  : undefined
153
143
  }
154
- paginationItemProps={(index) => ({
155
- 'aria-controls': buildSlideShowGroupId(slideshowSlidesId, index),
156
- ...slideshowControlsProps.paginationItemProps?.(index),
157
- })}
158
144
  />
159
145
  </div>
160
146
  ) : undefined
@@ -78,11 +78,10 @@ export const ControllingSlideshow = ({ images = Object.values(LANDSCAPE_IMAGES),
78
78
  parentRef={slideshow}
79
79
  theme={theme}
80
80
  isAutoPlaying={isAutoPlaying}
81
- nextButtonProps={{ label: 'Next', 'aria-controls': slideshowSlidesId }}
82
- previousButtonProps={{ label: 'Previous', 'aria-controls': slideshowSlidesId }}
81
+ nextButtonProps={{ label: 'Next' }}
82
+ previousButtonProps={{ label: 'Previous' }}
83
83
  playButtonProps={{
84
84
  label: 'Play/Pause',
85
- 'aria-controls': slideshowSlidesId,
86
85
  onClick: toggleForcePause,
87
86
  }}
88
87
  paginationItemLabel={(index) => `Slide ${index}`}
@@ -1,16 +1,18 @@
1
- import React, { forwardRef, RefObject, useCallback, useMemo } from 'react';
1
+ import React, { forwardRef, RefObject, useCallback, useState } from 'react';
2
2
 
3
3
  import classNames from 'classnames';
4
4
  import range from 'lodash/range';
5
5
 
6
6
  import { mdiChevronLeft, mdiChevronRight, mdiPlayCircleOutline, mdiPauseCircleOutline } from '@lumx/icons';
7
- import { Emphasis, IconButton, IconButtonProps, Theme } from '@lumx/react';
7
+ import { Emphasis, IconButton, IconButtonProps, Slides, Theme } from '@lumx/react';
8
8
  import { Comp, GenericProps, HasTheme } from '@lumx/react/utils/type';
9
9
  import { getRootClassName, handleBasicClasses } from '@lumx/react/utils/className';
10
10
  import { WINDOW } from '@lumx/react/constants';
11
- import { useSlideshowControls, DEFAULT_OPTIONS } from '@lumx/react/hooks/useSlideshowControls';
12
- import { useRovingTabIndex } from '@lumx/react/hooks/useRovingTabIndex';
11
+ import { useKeyNavigate } from '@lumx/react/components/slideshow/useKeyNavigate';
12
+ import { useMergeRefs } from '@lumx/react/utils/mergeRefs';
13
13
 
14
+ import { buildSlideShowGroupId } from '@lumx/react/components/slideshow/SlideshowItemGroup';
15
+ import { DEFAULT_OPTIONS, useSlideshowControls } from './useSlideshowControls';
14
16
  import { useSwipeNavigate } from './useSwipeNavigate';
15
17
  import { PAGINATION_ITEM_SIZE, PAGINATION_ITEMS_MAX } from './constants';
16
18
  import { usePaginationVisibleRange } from './usePaginationVisibleRange';
@@ -34,11 +36,11 @@ export interface SlideshowControlsProps extends GenericProps, HasTheme {
34
36
  /** Number of slides. */
35
37
  slidesCount: number;
36
38
  /** On next button click callback. */
37
- onNextClick?(loopback?: boolean): void;
39
+ onNextClick?(loopBack?: boolean): void;
38
40
  /** On pagination change callback. */
39
41
  onPaginationClick?(index: number): void;
40
42
  /** On previous button click callback. */
41
- onPreviousClick?(loopback?: boolean): void;
43
+ onPreviousClick?(loopBack?: boolean): void;
42
44
  /** whether the slideshow is currently playing */
43
45
  isAutoPlaying?: boolean;
44
46
  /**
@@ -100,7 +102,7 @@ const InternalSlideshowControls: Comp<SlideshowControlsProps, HTMLDivElement> =
100
102
  ...forwardedProps
101
103
  } = props;
102
104
 
103
- let parent;
105
+ let parent: HTMLElement | null | undefined;
104
106
  if (WINDOW) {
105
107
  // Checking window object to avoid errors in SSR.
106
108
  parent = parentRef instanceof HTMLElement ? parentRef : parentRef?.current;
@@ -109,33 +111,30 @@ const InternalSlideshowControls: Comp<SlideshowControlsProps, HTMLDivElement> =
109
111
  // Listen to touch swipe navigate left & right.
110
112
  useSwipeNavigate(
111
113
  parent,
112
- // Go next without loopback.
114
+ // Go next without loop back.
113
115
  useCallback(() => onNextClick?.(false), [onNextClick]),
114
- // Go previous without loopback.
116
+ // Go previous without loop back.
115
117
  useCallback(() => onPreviousClick?.(false), [onPreviousClick]),
116
118
  );
117
119
 
118
- /**
119
- * Add roving tab index pattern to pagination items and activate slide on focus.
120
- */
121
- useRovingTabIndex({
122
- parentRef: paginationRef,
123
- elementSelector: 'button',
124
- keepTabIndex: true,
125
- onElementFocus: (element) => {
126
- element.click();
127
- },
128
- });
120
+ const [focusedIndex, setFocusedIndex] = useState<number | null>(null);
121
+ const onButtonFocus = useCallback((index: number) => () => setFocusedIndex(index), [setFocusedIndex]);
122
+ const onFocusOut = useCallback(() => setFocusedIndex(null), [setFocusedIndex]);
129
123
 
130
124
  // Pagination "bullet" range.
131
- const visibleRange = usePaginationVisibleRange(activeIndex as number, slidesCount);
125
+ const visibleRange = usePaginationVisibleRange(focusedIndex ?? (activeIndex as number), slidesCount);
132
126
 
133
127
  // Inline style of wrapper element.
134
128
  const wrapperStyle = { transform: `translateX(-${PAGINATION_ITEM_SIZE * visibleRange.min}px)` };
135
129
 
130
+ const controlsRef = React.useRef<HTMLDivElement>(null);
131
+ useKeyNavigate(controlsRef.current, onNextClick, onPreviousClick);
132
+
133
+ const slideshowSlidesId = React.useMemo(() => parent?.querySelector(`.${Slides.className}__slides`)?.id, [parent]);
134
+
136
135
  return (
137
136
  <div
138
- ref={ref}
137
+ ref={useMergeRefs(ref, controlsRef)}
139
138
  {...forwardedProps}
140
139
  className={classNames(className, handleBasicClasses({ prefix: CLASSNAME, theme }), {
141
140
  [`${CLASSNAME}--has-infinite-pagination`]: slidesCount > PAGINATION_ITEMS_MAX,
@@ -148,64 +147,53 @@ const InternalSlideshowControls: Comp<SlideshowControlsProps, HTMLDivElement> =
148
147
  color={theme === Theme.dark ? 'light' : 'dark'}
149
148
  emphasis={Emphasis.low}
150
149
  onClick={onPreviousClick}
150
+ aria-controls={slideshowSlidesId}
151
151
  />
152
+
152
153
  <div ref={paginationRef} className={`${CLASSNAME}__pagination`}>
153
154
  <div
154
155
  className={`${CLASSNAME}__pagination-items`}
155
156
  style={wrapperStyle}
156
- role="tablist"
157
157
  {...paginationProps}
158
+ onBlur={onFocusOut}
158
159
  >
159
- {useMemo(
160
- () =>
161
- range(slidesCount).map((index) => {
162
- const isOnEdge =
163
- index !== 0 &&
164
- index !== slidesCount - 1 &&
165
- (index === visibleRange.min || index === visibleRange.max);
166
- const isActive = activeIndex === index;
167
- const isOutRange = index < visibleRange.min || index > visibleRange.max;
168
- const {
169
- className: itemClassName = undefined,
170
- label = undefined,
171
- ...itemProps
172
- } = paginationItemProps ? paginationItemProps(index) : {};
173
-
174
- const ariaLabel =
175
- label || paginationItemLabel?.(index) || `${index + 1} / ${slidesCount}`;
176
-
177
- return (
178
- <button
179
- className={classNames(
180
- handleBasicClasses({
181
- prefix: `${CLASSNAME}__pagination-item`,
182
- isActive,
183
- isOnEdge,
184
- isOutRange,
185
- }),
186
- itemClassName,
187
- )}
188
- key={index}
189
- type="button"
190
- tabIndex={isActive ? undefined : -1}
191
- role="tab"
192
- aria-selected={isActive}
193
- onClick={() => onPaginationClick?.(index)}
194
- aria-label={ariaLabel}
195
- {...itemProps}
196
- />
197
- );
198
- }),
199
- [
200
- slidesCount,
201
- visibleRange.min,
202
- visibleRange.max,
203
- activeIndex,
204
- paginationItemProps,
205
- paginationItemLabel,
206
- onPaginationClick,
207
- ],
208
- )}
160
+ {range(slidesCount).map((index) => {
161
+ const isOnEdge =
162
+ index !== 0 &&
163
+ index !== slidesCount - 1 &&
164
+ (index === visibleRange.min || index === visibleRange.max);
165
+ const isActive = activeIndex === index;
166
+ const isOutRange = index < visibleRange.min || index > visibleRange.max;
167
+ const {
168
+ className: itemClassName = undefined,
169
+ label = undefined,
170
+ ...itemProps
171
+ } = paginationItemProps ? paginationItemProps(index) : {};
172
+
173
+ const ariaLabel = label || paginationItemLabel?.(index) || `${index + 1} / ${slidesCount}`;
174
+
175
+ return (
176
+ <button
177
+ className={classNames(
178
+ handleBasicClasses({
179
+ prefix: `${CLASSNAME}__pagination-item`,
180
+ isActive,
181
+ isOnEdge,
182
+ isOutRange,
183
+ }),
184
+ itemClassName,
185
+ )}
186
+ key={index}
187
+ type="button"
188
+ aria-current={isActive || undefined}
189
+ aria-controls={buildSlideShowGroupId(slideshowSlidesId, index)}
190
+ onClick={() => onPaginationClick?.(index)}
191
+ onFocus={onButtonFocus(index)}
192
+ aria-label={ariaLabel}
193
+ {...itemProps}
194
+ />
195
+ );
196
+ })}
209
197
  </div>
210
198
  </div>
211
199
 
@@ -216,6 +204,7 @@ const InternalSlideshowControls: Comp<SlideshowControlsProps, HTMLDivElement> =
216
204
  className={`${CLASSNAME}__play`}
217
205
  color={theme === Theme.dark ? 'light' : 'dark'}
218
206
  emphasis={Emphasis.low}
207
+ aria-controls={slideshowSlidesId}
219
208
  />
220
209
  ) : null}
221
210
 
@@ -226,6 +215,7 @@ const InternalSlideshowControls: Comp<SlideshowControlsProps, HTMLDivElement> =
226
215
  color={theme === Theme.dark ? 'light' : 'dark'}
227
216
  emphasis={Emphasis.low}
228
217
  onClick={onNextClick}
218
+ aria-controls={slideshowSlidesId}
229
219
  />
230
220
  </div>
231
221
  );
@@ -33,16 +33,7 @@ const CLASSNAME = getRootClassName(COMPONENT_NAME);
33
33
  export const SlideshowItem: Comp<SlideshowItemProps, HTMLDivElement> = forwardRef((props, ref) => {
34
34
  const { className, children, ...forwardedProps } = props;
35
35
  return (
36
- <div
37
- ref={ref}
38
- className={classNames(
39
- className,
40
- handleBasicClasses({
41
- prefix: CLASSNAME,
42
- }),
43
- )}
44
- {...forwardedProps}
45
- >
36
+ <div ref={ref} className={classNames(className, CLASSNAME)} {...forwardedProps}>
46
37
  {children}
47
38
  </div>
48
39
  );
@@ -1,19 +1,17 @@
1
- import React, { forwardRef } from 'react';
1
+ import React from 'react';
2
2
 
3
- import classNames from 'classnames';
4
- import { mergeRefs } from '@lumx/react/utils/mergeRefs';
3
+ import { getRootClassName } from '@lumx/react/utils/className';
5
4
 
6
- import { Comp, GenericProps } from '@lumx/react/utils/type';
7
- import { getRootClassName, handleBasicClasses } from '@lumx/react/utils/className';
8
5
  import { useSlideFocusManagement } from './useSlideFocusManagement';
9
6
 
10
7
  /**
11
8
  * Defines the props of the component.
12
9
  */
13
- export interface SlideshowItemGroupProps extends GenericProps {
14
- role?: 'tabpanel' | 'group';
10
+ export interface SlideshowItemGroupProps {
11
+ id?: string;
15
12
  label?: string;
16
13
  isDisplayed?: boolean;
14
+ slidesRef?: React.RefObject<HTMLDivElement>;
17
15
  }
18
16
 
19
17
  /**
@@ -26,39 +24,24 @@ const COMPONENT_NAME = 'SlideshowItemGroup';
26
24
  */
27
25
  export const CLASSNAME = getRootClassName(COMPONENT_NAME);
28
26
 
29
- export const buildSlideShowGroupId = (slidesId: string, index: number) => `${slidesId}-slide-${index}`;
27
+ export const buildSlideShowGroupId = (slidesId: string | undefined, index: number) =>
28
+ slidesId && `${slidesId}-slide-${index}`;
30
29
 
31
30
  /**
32
- * SlideshowItemGroup component.
33
- *
34
- * @param props Component props.
35
- * @param ref Component ref.
36
- * @return React element.
31
+ * Internal slideshow item group component.
37
32
  */
38
- export const SlideshowItemGroup: Comp<SlideshowItemGroupProps, HTMLDivElement> = forwardRef((props, ref) => {
39
- const { className, children, role = 'group', label, isDisplayed, ...forwardedProps } = props;
40
- const groupRef = React.useRef<HTMLDivElement>(null);
33
+ export const SlideshowItemGroup: React.FC<SlideshowItemGroupProps> = (props) => {
34
+ const { id, children, label, isDisplayed, slidesRef } = props;
41
35
 
42
- useSlideFocusManagement({ isSlideDisplayed: isDisplayed, slideRef: groupRef });
36
+ const groupRef = useSlideFocusManagement({
37
+ isSlideDisplayed: isDisplayed,
38
+ slidesRef,
39
+ });
43
40
 
44
41
  return (
45
- <div
46
- ref={mergeRefs(groupRef, ref)}
47
- role={role}
48
- className={classNames(
49
- className,
50
- handleBasicClasses({
51
- prefix: CLASSNAME,
52
- }),
53
- )}
54
- aria-roledescription="slide"
55
- aria-label={label}
56
- {...forwardedProps}
57
- >
42
+ <div id={id} ref={groupRef} role="group" className={CLASSNAME} aria-label={label} tabIndex={-1}>
58
43
  {children}
59
44
  </div>
60
45
  );
61
- });
62
-
46
+ };
63
47
  SlideshowItemGroup.displayName = COMPONENT_NAME;
64
- SlideshowItemGroup.className = CLASSNAME;