@lumx/react 2.2.9-alpha-exported-hooks2 → 2.2.10

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.
Files changed (268) hide show
  1. package/esm/_internal/{alertdialog.1.js → AlertDialog.js} +8 -8
  2. package/esm/_internal/AlertDialog.js.map +1 -0
  3. package/esm/_internal/{autocompletemultiple.2.js → AutocompleteMultiple.js} +9 -9
  4. package/esm/_internal/AutocompleteMultiple.js.map +1 -0
  5. package/esm/_internal/{avatar.3.js → Avatar2.js} +4 -4
  6. package/esm/_internal/Avatar2.js.map +1 -0
  7. package/esm/_internal/{badge.4.js → Badge2.js} +3 -3
  8. package/esm/_internal/Badge2.js.map +1 -0
  9. package/esm/_internal/{button.5.js → Button2.js} +5 -5
  10. package/esm/_internal/Button2.js.map +1 -0
  11. package/esm/_internal/{buttongroup.7.js → ButtonGroup.js} +3 -3
  12. package/esm/_internal/ButtonGroup.js.map +1 -0
  13. package/esm/_internal/{buttonroot.57.js → ButtonRoot.js} +4 -4
  14. package/esm/_internal/ButtonRoot.js.map +1 -0
  15. package/esm/_internal/{checkbox.8.js → Checkbox2.js} +7 -7
  16. package/esm/_internal/Checkbox2.js.map +1 -0
  17. package/esm/_internal/{chip.9.js → Chip2.js} +3 -3
  18. package/esm/_internal/Chip2.js.map +1 -0
  19. package/esm/_internal/{chipgroup.10.js → ChipGroup.js} +3 -3
  20. package/esm/_internal/ChipGroup.js.map +1 -0
  21. package/esm/_internal/{clickawayprovider.60.js → ClickAwayProvider.js} +4 -4
  22. package/esm/_internal/ClickAwayProvider.js.map +1 -0
  23. package/esm/_internal/{commentblock.11.js → CommentBlock.js} +4 -4
  24. package/esm/_internal/CommentBlock.js.map +1 -0
  25. package/esm/_internal/{datepickerfield.12.js → DatePickerField.js} +9 -9
  26. package/esm/_internal/DatePickerField.js.map +1 -0
  27. package/esm/_internal/{dialog.13.js → Dialog2.js} +12 -12
  28. package/esm/_internal/Dialog2.js.map +1 -0
  29. package/esm/_internal/{divider.14.js → Divider2.js} +3 -3
  30. package/esm/_internal/Divider2.js.map +1 -0
  31. package/esm/_internal/{draghandle.15.js → DragHandle.js} +4 -4
  32. package/esm/_internal/DragHandle.js.map +1 -0
  33. package/esm/_internal/{dropdown.16.js → Dropdown2.js} +6 -6
  34. package/esm/_internal/Dropdown2.js.map +1 -0
  35. package/esm/_internal/{expansionpanel.17.js → ExpansionPanel.js} +8 -8
  36. package/esm/_internal/ExpansionPanel.js.map +1 -0
  37. package/esm/_internal/{flag.18.js → Flag2.js} +4 -4
  38. package/esm/_internal/Flag2.js.map +1 -0
  39. package/esm/_internal/{flexbox.19.js → FlexBox.js} +3 -3
  40. package/esm/_internal/FlexBox.js.map +1 -0
  41. package/esm/_internal/{griditem.20.js → GridItem.js} +3 -3
  42. package/esm/_internal/GridItem.js.map +1 -0
  43. package/esm/_internal/{icon.21.js → Icon2.js} +6 -4
  44. package/esm/_internal/Icon2.js.map +1 -0
  45. package/esm/_internal/{iconbutton.6.js → IconButton.js} +6 -6
  46. package/esm/_internal/IconButton.js.map +1 -0
  47. package/esm/_internal/{imageblock.22.js → ImageBlock.js} +4 -4
  48. package/esm/_internal/ImageBlock.js.map +1 -0
  49. package/esm/_internal/{inputhelper.23.js → InputHelper.js} +3 -3
  50. package/esm/_internal/InputHelper.js.map +1 -0
  51. package/esm/_internal/{inputlabel.24.js → InputLabel.js} +3 -3
  52. package/esm/_internal/InputLabel.js.map +1 -0
  53. package/esm/_internal/{lightbox.25.js → Lightbox2.js} +11 -11
  54. package/esm/_internal/Lightbox2.js.map +1 -0
  55. package/esm/_internal/{link.26.js → Link2.js} +5 -5
  56. package/esm/_internal/Link2.js.map +1 -0
  57. package/esm/_internal/{linkpreview.27.js → LinkPreview.js} +5 -5
  58. package/esm/_internal/LinkPreview.js.map +1 -0
  59. package/esm/_internal/{list.28.js → List2.js} +6 -6
  60. package/esm/_internal/List2.js.map +1 -0
  61. package/esm/_internal/{listsubheader.29.js → ListSubheader.js} +3 -3
  62. package/esm/_internal/ListSubheader.js.map +1 -0
  63. package/esm/_internal/{message.30.js → Message2.js} +4 -4
  64. package/esm/_internal/Message2.js.map +1 -0
  65. package/esm/_internal/{mosaic.31.js → Mosaic2.js} +4 -4
  66. package/esm/_internal/Mosaic2.js.map +1 -0
  67. package/esm/_internal/{notification.32.js → Notification2.js} +7 -7
  68. package/esm/_internal/Notification2.js.map +1 -0
  69. package/esm/_internal/{popover.33.js → Popover2.js} +6 -6
  70. package/esm/_internal/Popover2.js.map +1 -0
  71. package/esm/_internal/{postblock.34.js → PostBlock.js} +5 -5
  72. package/esm/_internal/PostBlock.js.map +1 -0
  73. package/esm/_internal/{progress.35.js → Progress2.js} +3 -3
  74. package/esm/_internal/Progress2.js.map +1 -0
  75. package/esm/_internal/{progresstrackersteppanel.36.js → ProgressTrackerStepPanel.js} +8 -8
  76. package/esm/_internal/ProgressTrackerStepPanel.js.map +1 -0
  77. package/esm/_internal/{radiogroup.37.js → RadioGroup.js} +6 -6
  78. package/esm/_internal/RadioGroup.js.map +1 -0
  79. package/esm/_internal/{selectmultiple.38.js → SelectMultiple.js} +12 -12
  80. package/esm/_internal/SelectMultiple.js.map +1 -0
  81. package/esm/_internal/{sidenavigationitem.39.js → SideNavigationItem.js} +7 -7
  82. package/esm/_internal/SideNavigationItem.js.map +1 -0
  83. package/esm/_internal/{skeletontypography.40.js → SkeletonTypography.js} +3 -3
  84. package/esm/_internal/SkeletonTypography.js.map +1 -0
  85. package/esm/_internal/{slider.41.js → Slider2.js} +6 -6
  86. package/esm/_internal/Slider2.js.map +1 -0
  87. package/esm/_internal/{slideshowcontrols.42.js → Slides.js} +239 -121
  88. package/esm/_internal/Slides.js.map +1 -0
  89. package/esm/_internal/{switch.43.js → Switch2.js} +6 -6
  90. package/esm/_internal/Switch2.js.map +1 -0
  91. package/esm/_internal/{tabpanel.45.js → TabPanel.js} +6 -6
  92. package/esm/_internal/TabPanel.js.map +1 -0
  93. package/esm/_internal/{tablerow.44.js → TableRow.js} +4 -4
  94. package/esm/_internal/TableRow.js.map +1 -0
  95. package/esm/_internal/{textfield.46.js → TextField.js} +9 -9
  96. package/esm/_internal/TextField.js.map +1 -0
  97. package/esm/_internal/{thumbnail.47.js → Thumbnail2.js} +6 -6
  98. package/esm/_internal/Thumbnail2.js.map +1 -0
  99. package/esm/_internal/{toolbar.49.js → Toolbar2.js} +3 -3
  100. package/esm/_internal/Toolbar2.js.map +1 -0
  101. package/esm/_internal/{tooltip.50.js → Tooltip2.js} +7 -7
  102. package/esm/_internal/Tooltip2.js.map +1 -0
  103. package/esm/_internal/{uploader.51.js → Uploader2.js} +4 -4
  104. package/esm/_internal/Uploader2.js.map +1 -0
  105. package/esm/_internal/{userblock.52.js → UserBlock.js} +5 -5
  106. package/esm/_internal/UserBlock.js.map +1 -0
  107. package/esm/_internal/{_rolluppluginbabelhelpers.53.js → _rollupPluginBabelHelpers.js} +1 -1
  108. package/esm/_internal/_rollupPluginBabelHelpers.js.map +1 -0
  109. package/esm/_internal/alert-dialog.js +19 -19
  110. package/esm/_internal/autocomplete.js +20 -20
  111. package/esm/_internal/avatar.js +6 -6
  112. package/esm/_internal/badge.js +3 -3
  113. package/esm/_internal/button.js +14 -14
  114. package/esm/_internal/checkbox.js +7 -7
  115. package/esm/_internal/chip.js +4 -4
  116. package/esm/_internal/comment-block.js +7 -7
  117. package/esm/_internal/components.js +1 -1
  118. package/esm/_internal/{constants.59.js → constants.js} +1 -1
  119. package/esm/_internal/constants.js.map +1 -0
  120. package/esm/_internal/date-picker.js +18 -18
  121. package/esm/_internal/dialog.js +12 -12
  122. package/esm/_internal/divider.js +3 -3
  123. package/esm/_internal/drag-handle.js +4 -4
  124. package/esm/_internal/dropdown.js +10 -10
  125. package/esm/_internal/expansion-panel.js +16 -16
  126. package/esm/_internal/flag.js +4 -4
  127. package/esm/_internal/flex-box.js +3 -3
  128. package/esm/_internal/{getrootclassname.54.js → getRootClassName.js} +4 -3
  129. package/esm/_internal/getRootClassName.js.map +1 -0
  130. package/esm/_internal/grid.js +3 -3
  131. package/esm/_internal/icon.js +3 -3
  132. package/esm/_internal/image-block.js +6 -6
  133. package/esm/_internal/input-helper.js +3 -3
  134. package/esm/_internal/input-label.js +3 -3
  135. package/esm/_internal/lightbox.js +16 -16
  136. package/esm/_internal/link-preview.js +8 -8
  137. package/esm/_internal/link.js +5 -5
  138. package/esm/_internal/list.js +7 -7
  139. package/esm/_internal/{mergerefs.56.js → mergeRefs.js} +1 -1
  140. package/esm/_internal/mergeRefs.js.map +1 -0
  141. package/esm/_internal/message.js +4 -4
  142. package/esm/_internal/mosaic.js +6 -6
  143. package/esm/_internal/notification.js +9 -9
  144. package/esm/_internal/{partitionmulti.62.js → partitionMulti.js} +1 -1
  145. package/esm/_internal/partitionMulti.js.map +1 -0
  146. package/esm/_internal/popover.js +6 -6
  147. package/esm/_internal/post-block.js +7 -7
  148. package/esm/_internal/progress-tracker.js +9 -9
  149. package/esm/_internal/progress.js +3 -3
  150. package/esm/_internal/radio-button.js +6 -6
  151. package/esm/_internal/{renderlink.65.js → renderLink.js} +2 -2
  152. package/esm/_internal/renderLink.js.map +1 -0
  153. package/esm/_internal/select.js +19 -19
  154. package/esm/_internal/side-navigation.js +14 -14
  155. package/esm/_internal/skeleton.js +3 -3
  156. package/esm/_internal/slider.js +6 -6
  157. package/esm/_internal/slideshow.js +14 -14
  158. package/esm/_internal/switch.js +6 -6
  159. package/esm/_internal/table.js +4 -4
  160. package/esm/_internal/tabs.js +7 -7
  161. package/esm/_internal/text-field.js +15 -15
  162. package/esm/_internal/thumbnail.js +6 -6
  163. package/esm/_internal/toolbar.js +3 -3
  164. package/esm/_internal/tooltip.js +8 -8
  165. package/esm/_internal/{type.64.js → type.js} +1 -1
  166. package/esm/_internal/type.js.map +1 -0
  167. package/esm/_internal/{types.48.js → types.js} +3 -2
  168. package/esm/_internal/types.js.map +1 -0
  169. package/esm/_internal/uploader.js +4 -4
  170. package/esm/_internal/{usedelayedvisibility.63.js → useDelayedVisibility.js} +2 -2
  171. package/esm/_internal/useDelayedVisibility.js.map +1 -0
  172. package/esm/_internal/{usedisablebodyscroll.61.js → useDisableBodyScroll.js} +1 -1
  173. package/esm/_internal/useDisableBodyScroll.js.map +1 -0
  174. package/esm/_internal/{usefocustrap.58.js → useFocusTrap.js} +2 -2
  175. package/esm/_internal/useFocusTrap.js.map +1 -0
  176. package/esm/_internal/{userovingtabindex.66.js → useRovingTabIndex.js} +3 -3
  177. package/esm/_internal/useRovingTabIndex.js.map +1 -0
  178. package/esm/_internal/user-block.js +9 -9
  179. package/esm/index.js +89 -0
  180. package/{index.js.map → esm/index.js.map} +1 -1
  181. package/esm/{_internal/index.55.js → index2.js} +1 -1
  182. package/esm/index2.js.map +1 -0
  183. package/package.json +10 -11
  184. package/src/components/slideshow/Slides.tsx +115 -0
  185. package/src/components/slideshow/Slideshow.stories.tsx +35 -0
  186. package/src/components/slideshow/Slideshow.test.tsx +1 -1
  187. package/src/components/slideshow/Slideshow.tsx +68 -90
  188. package/src/components/slideshow/SlideshowControls.stories.tsx +76 -40
  189. package/src/components/slideshow/SlideshowControls.tsx +36 -4
  190. package/src/components/slideshow/SlideshowItem.tsx +19 -3
  191. package/src/components/slideshow/__snapshots__/Slideshow.test.tsx.snap +125 -232
  192. package/src/components/slideshow/index.ts +1 -0
  193. package/src/components/thumbnail/index.ts +1 -0
  194. package/src/hooks/useFocusWithin.ts +2 -2
  195. package/src/hooks/useSlideshowControls.ts +29 -12
  196. package/src/stories/generated/Thumbnail/Demos.stories.tsx +3 -1
  197. package/types.d.ts +2672 -0
  198. package/esm/_internal/_rolluppluginbabelhelpers.53.js.map +0 -1
  199. package/esm/_internal/alertdialog.1.js.map +0 -1
  200. package/esm/_internal/autocompletemultiple.2.js.map +0 -1
  201. package/esm/_internal/avatar.3.js.map +0 -1
  202. package/esm/_internal/badge.4.js.map +0 -1
  203. package/esm/_internal/button.5.js.map +0 -1
  204. package/esm/_internal/buttongroup.7.js.map +0 -1
  205. package/esm/_internal/buttonroot.57.js.map +0 -1
  206. package/esm/_internal/checkbox.8.js.map +0 -1
  207. package/esm/_internal/chip.9.js.map +0 -1
  208. package/esm/_internal/chipgroup.10.js.map +0 -1
  209. package/esm/_internal/clickawayprovider.60.js.map +0 -1
  210. package/esm/_internal/commentblock.11.js.map +0 -1
  211. package/esm/_internal/constants.59.js.map +0 -1
  212. package/esm/_internal/datepickerfield.12.js.map +0 -1
  213. package/esm/_internal/dialog.13.js.map +0 -1
  214. package/esm/_internal/divider.14.js.map +0 -1
  215. package/esm/_internal/draghandle.15.js.map +0 -1
  216. package/esm/_internal/dropdown.16.js.map +0 -1
  217. package/esm/_internal/expansionpanel.17.js.map +0 -1
  218. package/esm/_internal/flag.18.js.map +0 -1
  219. package/esm/_internal/flexbox.19.js.map +0 -1
  220. package/esm/_internal/getrootclassname.54.js.map +0 -1
  221. package/esm/_internal/griditem.20.js.map +0 -1
  222. package/esm/_internal/icon.21.js.map +0 -1
  223. package/esm/_internal/iconbutton.6.js.map +0 -1
  224. package/esm/_internal/imageblock.22.js.map +0 -1
  225. package/esm/_internal/index.55.js.map +0 -1
  226. package/esm/_internal/inputhelper.23.js.map +0 -1
  227. package/esm/_internal/inputlabel.24.js.map +0 -1
  228. package/esm/_internal/lightbox.25.js.map +0 -1
  229. package/esm/_internal/link.26.js.map +0 -1
  230. package/esm/_internal/linkpreview.27.js.map +0 -1
  231. package/esm/_internal/list.28.js.map +0 -1
  232. package/esm/_internal/listsubheader.29.js.map +0 -1
  233. package/esm/_internal/mergerefs.56.js.map +0 -1
  234. package/esm/_internal/message.30.js.map +0 -1
  235. package/esm/_internal/mosaic.31.js.map +0 -1
  236. package/esm/_internal/notification.32.js.map +0 -1
  237. package/esm/_internal/partitionmulti.62.js.map +0 -1
  238. package/esm/_internal/popover.33.js.map +0 -1
  239. package/esm/_internal/postblock.34.js.map +0 -1
  240. package/esm/_internal/progress.35.js.map +0 -1
  241. package/esm/_internal/progresstrackersteppanel.36.js.map +0 -1
  242. package/esm/_internal/radiogroup.37.js.map +0 -1
  243. package/esm/_internal/renderlink.65.js.map +0 -1
  244. package/esm/_internal/selectmultiple.38.js.map +0 -1
  245. package/esm/_internal/sidenavigationitem.39.js.map +0 -1
  246. package/esm/_internal/skeletontypography.40.js.map +0 -1
  247. package/esm/_internal/slider.41.js.map +0 -1
  248. package/esm/_internal/slideshowcontrols.42.js.map +0 -1
  249. package/esm/_internal/switch.43.js.map +0 -1
  250. package/esm/_internal/tablerow.44.js.map +0 -1
  251. package/esm/_internal/tabpanel.45.js.map +0 -1
  252. package/esm/_internal/textfield.46.js.map +0 -1
  253. package/esm/_internal/thumbnail.47.js.map +0 -1
  254. package/esm/_internal/toolbar.49.js.map +0 -1
  255. package/esm/_internal/tooltip.50.js.map +0 -1
  256. package/esm/_internal/type.64.js.map +0 -1
  257. package/esm/_internal/types.48.js.map +0 -1
  258. package/esm/_internal/uploader.51.js.map +0 -1
  259. package/esm/_internal/usedelayedvisibility.63.js.map +0 -1
  260. package/esm/_internal/usedisablebodyscroll.61.js.map +0 -1
  261. package/esm/_internal/usefocustrap.58.js.map +0 -1
  262. package/esm/_internal/userblock.52.js.map +0 -1
  263. package/esm/_internal/userovingtabindex.66.js.map +0 -1
  264. package/hooks/useFocusWithin.d.ts +0 -16
  265. package/hooks/useFocusWithin.js +0 -28
  266. package/hooks/useFocusWithin.js.map +0 -1
  267. package/index.d.ts +0 -2723
  268. package/index.js +0 -90
@@ -40,6 +40,40 @@ export const Simple = ({ theme }: any) => {
40
40
  );
41
41
  };
42
42
 
43
+ export const SimpleWithAutoPlay = ({ theme }: any) => {
44
+ const images = thumbnailsKnob(6);
45
+ const activeIndex = number('Active index', 0);
46
+ const groupBy = number('Group by', 1);
47
+ const interval = number('Autoplay interval (in milliseconds)', 1000);
48
+
49
+ return (
50
+ <Slideshow
51
+ activeIndex={activeIndex}
52
+ autoPlay
53
+ interval={interval}
54
+ slideshowControlsProps={{
55
+ nextButtonProps: { label: 'Next' },
56
+ previousButtonProps: { label: 'Previous' },
57
+ playButtonProps: { label: 'Play/Pause' },
58
+ }}
59
+ theme={theme}
60
+ groupBy={groupBy}
61
+ style={{ width: '50%' }}
62
+ >
63
+ {images.map(({ image, alt }, index) => (
64
+ <SlideshowItem key={`${image}-${index}`}>
65
+ <ImageBlock
66
+ thumbnailProps={{ aspectRatio: AspectRatio.horizontal, loading: 'eager' }}
67
+ image={image}
68
+ alt={alt}
69
+ theme={theme}
70
+ />
71
+ </SlideshowItem>
72
+ ))}
73
+ </Slideshow>
74
+ );
75
+ };
76
+
43
77
  export const ResponsiveSlideShowSwipe = () => {
44
78
  const slides = range(3);
45
79
  return (
@@ -52,6 +86,7 @@ export const ResponsiveSlideShowSwipe = () => {
52
86
  </ul>
53
87
  <FlexBox vAlign="center">
54
88
  <Slideshow
89
+ activeIndex={0}
55
90
  slideshowControlsProps={{
56
91
  nextButtonProps: { label: 'Next' },
57
92
  previousButtonProps: { label: 'Previous' },
@@ -35,5 +35,5 @@ describe(`<${Slideshow.displayName}>`, () => {
35
35
  });
36
36
 
37
37
  // Common tests suite.
38
- commonTestsSuite(setup, { className: 'wrapper', prop: 'wrapper' }, { className: CLASSNAME });
38
+ commonTestsSuite(setup, { prop: 'wrapper' }, { className: CLASSNAME });
39
39
  });
@@ -1,25 +1,19 @@
1
- import React, { CSSProperties, forwardRef } from 'react';
1
+ import React, { forwardRef } from 'react';
2
2
 
3
- import classNames from 'classnames';
4
-
5
- import { SlideshowControls, SlideshowControlsProps, Theme } from '@lumx/react';
3
+ import { SlideshowControls, SlideshowControlsProps, Theme, Slides, SlidesProps } from '@lumx/react';
6
4
  import { DEFAULT_OPTIONS } from '@lumx/react/hooks/useSlideshowControls';
7
- import { FULL_WIDTH_PERCENT } from '@lumx/react/components/slideshow/constants';
8
- import { Comp, GenericProps, getRootClassName, handleBasicClasses } from '@lumx/react/utils';
5
+ import { Comp, GenericProps } from '@lumx/react/utils';
6
+ import { useFocusWithin } from '@lumx/react/hooks/useFocusWithin';
9
7
  import { mergeRefs } from '@lumx/react/utils/mergeRefs';
10
8
 
11
9
  /**
12
10
  * Defines the props of the component.
13
11
  */
14
- export interface SlideshowProps extends GenericProps {
15
- /** Index of the current slide. */
16
- activeIndex?: number;
17
- /** Whether the automatic rotation of the slideshow is enabled or not. */
18
- autoPlay?: boolean;
19
- /** Whether the image has to fill its container height or not. */
20
- fillHeight?: boolean;
21
- /** Number of slides to group together. */
22
- groupBy?: number;
12
+ export interface SlideshowProps
13
+ extends GenericProps,
14
+ Pick<SlidesProps, 'autoPlay' | 'slidesId' | 'id' | 'theme' | 'fillHeight' | 'groupBy'> {
15
+ /** current slide active */
16
+ activeIndex?: SlidesProps['activeIndex'];
23
17
  /** Interval between each slide when automatic rotation is enabled. */
24
18
  interval?: number;
25
19
  /** Props to pass to the slideshow controls (minus those already set by the Slideshow props). */
@@ -34,26 +28,10 @@ export interface SlideshowProps extends GenericProps {
34
28
  | 'parentRef'
35
29
  | 'theme'
36
30
  >;
37
- /** Theme adapting the component to light or dark background. */
38
- theme?: Theme;
39
31
  /** Callback when slide changes */
40
32
  onChange?(index: number): void;
41
- /** slideshow HTML id attribute */
42
- id?: string;
43
- /** slides wrapper HTML id attribute */
44
- slidesId?: string;
45
33
  }
46
34
 
47
- /**
48
- * Component display name.
49
- */
50
- const COMPONENT_NAME = 'Slideshow';
51
-
52
- /**
53
- * Component default class name and class prefix.
54
- */
55
- const CLASSNAME = getRootClassName(COMPONENT_NAME);
56
-
57
35
  /**
58
36
  * Component default props.
59
37
  */
@@ -102,6 +80,10 @@ export const Slideshow: Comp<SlideshowProps, HTMLDivElement> = forwardRef((props
102
80
  onPaginationClick,
103
81
  onPreviousClick,
104
82
  slideshow,
83
+ stopAutoPlay,
84
+ startAutoPlay,
85
+ isForcePaused,
86
+ setIsForcePaused,
105
87
  } = SlideshowControls.useSlideshowControls({
106
88
  activeIndex,
107
89
  defaultActiveIndex: DEFAULT_PROPS.activeIndex as number,
@@ -114,72 +96,68 @@ export const Slideshow: Comp<SlideshowProps, HTMLDivElement> = forwardRef((props
114
96
  slidesId,
115
97
  });
116
98
 
117
- // Inline style of wrapper element.
118
- const wrapperStyle: CSSProperties = { transform: `translateX(-${FULL_WIDTH_PERCENT * currentIndex}%)` };
99
+ useFocusWithin({
100
+ element: slideshow,
101
+ onFocusIn: stopAutoPlay,
102
+ onFocusOut: startAutoPlay,
103
+ });
119
104
 
120
- /* eslint-disable jsx-a11y/no-noninteractive-tabindex */
121
105
  return (
122
- <section
106
+ <Slides
107
+ activeIndex={currentIndex}
123
108
  id={slideshowId}
109
+ className={className}
110
+ theme={theme}
111
+ fillHeight={fillHeight}
112
+ groupBy={groupBy}
113
+ isAutoPlaying={isAutoPlaying}
114
+ autoPlay={autoPlay}
115
+ slidesId={slideshowSlidesId}
116
+ setIsAutoPlaying={setIsAutoPlaying}
117
+ startIndexVisible={startIndexVisible}
118
+ endIndexVisible={endIndexVisible}
119
+ interval={interval}
124
120
  ref={mergeRefs(ref, setSlideshow)}
121
+ afterSlides={
122
+ slideshowControlsProps && slidesCount > 1 ? (
123
+ <div className={`${Slides.className}__controls`}>
124
+ <SlideshowControls
125
+ {...slideshowControlsProps}
126
+ activeIndex={currentIndex}
127
+ onPaginationClick={onPaginationClick}
128
+ onNextClick={onNextClick}
129
+ onPreviousClick={onPreviousClick}
130
+ slidesCount={slidesCount}
131
+ parentRef={slideshow}
132
+ theme={theme}
133
+ isAutoPlaying={isAutoPlaying}
134
+ nextButtonProps={{
135
+ 'aria-controls': slideshowSlidesId,
136
+ ...slideshowControlsProps.nextButtonProps,
137
+ }}
138
+ previousButtonProps={{
139
+ 'aria-controls': slideshowSlidesId,
140
+ ...slideshowControlsProps.previousButtonProps,
141
+ }}
142
+ playButtonProps={
143
+ autoPlay
144
+ ? {
145
+ 'aria-controls': slideshowSlidesId,
146
+ onClick: () => setIsForcePaused(!isForcePaused),
147
+ ...slideshowControlsProps.playButtonProps,
148
+ }
149
+ : undefined
150
+ }
151
+ />
152
+ </div>
153
+ ) : undefined
154
+ }
125
155
  {...forwardedProps}
126
- className={classNames(className, handleBasicClasses({ prefix: CLASSNAME, theme }), {
127
- [`${CLASSNAME}--fill-height`]: fillHeight,
128
- [`${CLASSNAME}--group-by-${groupBy}`]: Boolean(groupBy),
129
- })}
130
- aria-roledescription="carousel"
131
- aria-live={isAutoPlaying ? 'off' : 'polite'}
132
156
  >
133
- <div
134
- id={slideshowSlidesId}
135
- className={`${CLASSNAME}__slides`}
136
- onMouseEnter={() => setIsAutoPlaying(false)}
137
- onMouseLeave={() => setIsAutoPlaying(Boolean(autoPlay))}
138
- >
139
- <div className={`${CLASSNAME}__wrapper`} style={wrapperStyle}>
140
- {React.Children.map(children, (child: React.ReactNode, index: number) => {
141
- if (React.isValidElement(child)) {
142
- const isCurrentlyVisible = index >= startIndexVisible && index <= endIndexVisible;
143
-
144
- return React.cloneElement(child, {
145
- style: !isCurrentlyVisible
146
- ? { visibility: 'hidden', ...(child.props.style || {}) }
147
- : child.props.style || {},
148
- 'aria-hidden': !isCurrentlyVisible,
149
- });
150
- }
151
-
152
- return null;
153
- })}
154
- </div>
155
- </div>
156
-
157
- {slideshowControlsProps && slidesCount > 1 && (
158
- <div className={`${CLASSNAME}__controls`}>
159
- <SlideshowControls
160
- {...slideshowControlsProps}
161
- activeIndex={currentIndex}
162
- onPaginationClick={onPaginationClick}
163
- onNextClick={onNextClick}
164
- onPreviousClick={onPreviousClick}
165
- slidesCount={slidesCount}
166
- parentRef={slideshow}
167
- theme={theme}
168
- nextButtonProps={{
169
- 'aria-controls': slideshowSlidesId,
170
- ...slideshowControlsProps.nextButtonProps,
171
- }}
172
- previousButtonProps={{
173
- 'aria-controls': slideshowSlidesId,
174
- ...slideshowControlsProps.previousButtonProps,
175
- }}
176
- />
177
- </div>
178
- )}
179
- </section>
157
+ {children}
158
+ </Slides>
180
159
  );
181
160
  });
182
161
 
183
- Slideshow.displayName = COMPONENT_NAME;
184
- Slideshow.className = CLASSNAME;
162
+ Slideshow.displayName = 'Slideshow';
185
163
  Slideshow.defaultProps = DEFAULT_PROPS;
@@ -1,7 +1,8 @@
1
1
  import React from 'react';
2
2
 
3
- import { AspectRatio, ImageBlock, Slideshow, SlideshowControls, SlideshowItem } from '@lumx/react';
3
+ import { AspectRatio, ImageBlock, Slides, SlideshowControls, SlideshowItem } from '@lumx/react';
4
4
  import { thumbnailsKnob } from '@lumx/react/stories/knobs/thumbnailsKnob';
5
+ import { useFocusWithin } from '@lumx/react/hooks/useFocusWithin';
5
6
 
6
7
  export default { title: 'LumX components/slideshow/Slideshow controls' };
7
8
 
@@ -30,53 +31,88 @@ export const Simple = () => {
30
31
  };
31
32
 
32
33
  export const ControllingSlideshow = ({ theme }: any) => {
33
- const items = thumbnailsKnob(6);
34
- const slideshowStyle = {
35
- width: '50%',
36
- };
34
+ const images = thumbnailsKnob(6);
37
35
 
38
36
  const {
39
- activeIndex,
40
- setActiveIndex,
37
+ activeIndex: currentIndex,
38
+ slideshowId,
39
+ setSlideshow,
40
+ isAutoPlaying,
41
+ slideshowSlidesId,
42
+ setIsAutoPlaying,
43
+ startIndexVisible,
44
+ endIndexVisible,
45
+ slidesCount,
41
46
  onNextClick,
42
- onPreviousClick,
43
47
  onPaginationClick,
48
+ onPreviousClick,
49
+ slideshow,
50
+ isForcePaused,
51
+ setIsForcePaused,
52
+ stopAutoPlay,
53
+ startAutoPlay,
44
54
  } = SlideshowControls.useSlideshowControls({
55
+ activeIndex: 0,
56
+ defaultActiveIndex: 0,
57
+ autoPlay: true,
45
58
  itemsCount: 6,
59
+ groupBy: 1,
60
+ });
61
+
62
+ useFocusWithin({
63
+ element: slideshow,
64
+ onFocusIn: stopAutoPlay,
65
+ onFocusOut: startAutoPlay,
46
66
  });
47
67
 
68
+ /* eslint-disable jsx-a11y/no-noninteractive-tabindex */
48
69
  return (
49
- <div style={{ height: 400, width: 500, position: 'relative' }}>
50
- <Slideshow
51
- activeIndex={activeIndex}
52
- theme={theme}
53
- autoPlay
54
- groupBy={1}
55
- style={slideshowStyle}
56
- onChange={setActiveIndex}
57
- >
58
- {items.map(({ image, alt }) => (
59
- <SlideshowItem key={image}>
60
- <ImageBlock
61
- image={image}
62
- alt={alt}
63
- thumbnailProps={{ aspectRatio: AspectRatio.vertical }}
64
- theme={theme}
65
- />
66
- </SlideshowItem>
67
- ))}
68
- </Slideshow>
69
- <div style={{ position: 'absolute', bottom: 0, right: -24 }}>
70
- <SlideshowControls
71
- activeIndex={activeIndex}
72
- slidesCount={items.length}
73
- onNextClick={onNextClick}
74
- onPreviousClick={onPreviousClick}
75
- onPaginationClick={onPaginationClick}
76
- nextButtonProps={{ label: 'Next' }}
77
- previousButtonProps={{ label: 'Previous' }}
78
- />
79
- </div>
80
- </div>
70
+ <Slides
71
+ activeIndex={currentIndex}
72
+ id={slideshowId}
73
+ ref={setSlideshow}
74
+ theme={theme}
75
+ isAutoPlaying={isAutoPlaying}
76
+ autoPlay
77
+ slidesId={slideshowSlidesId}
78
+ setIsAutoPlaying={setIsAutoPlaying}
79
+ startIndexVisible={startIndexVisible}
80
+ endIndexVisible={endIndexVisible}
81
+ groupBy={1}
82
+ style={{ width: '50%' }}
83
+ afterSlides={
84
+ <div className={`${Slides.className}__controls`}>
85
+ <SlideshowControls
86
+ activeIndex={currentIndex}
87
+ onPaginationClick={onPaginationClick}
88
+ onNextClick={onNextClick}
89
+ onPreviousClick={onPreviousClick}
90
+ slidesCount={slidesCount}
91
+ parentRef={slideshow}
92
+ theme={theme}
93
+ isAutoPlaying={isAutoPlaying}
94
+ nextButtonProps={{ label: 'Next', 'aria-controls': slideshowSlidesId }}
95
+ previousButtonProps={{ label: 'Previous', 'aria-controls': slideshowSlidesId }}
96
+ playButtonProps={{
97
+ label: 'Play/Pause',
98
+ 'aria-controls': slideshowSlidesId,
99
+ onClick: () => setIsForcePaused(!isForcePaused),
100
+ }}
101
+ paginationItemLabel={(index) => `Slide ${index}`}
102
+ />
103
+ </div>
104
+ }
105
+ >
106
+ {images.map(({ image, alt }, index) => (
107
+ <SlideshowItem key={`${image}-${index}`}>
108
+ <ImageBlock
109
+ thumbnailProps={{ aspectRatio: AspectRatio.horizontal, loading: 'eager' }}
110
+ image={image}
111
+ alt={alt}
112
+ theme={theme}
113
+ />
114
+ </SlideshowItem>
115
+ ))}
116
+ </Slides>
81
117
  );
82
118
  };
@@ -3,7 +3,7 @@ import React, { forwardRef, RefObject, useCallback, useMemo } from 'react';
3
3
  import classNames from 'classnames';
4
4
  import range from 'lodash/range';
5
5
 
6
- import { mdiChevronLeft, mdiChevronRight } from '@lumx/icons';
6
+ import { mdiChevronLeft, mdiChevronRight, mdiPlayCircleOutline, mdiPauseCircleOutline } from '@lumx/icons';
7
7
  import { Emphasis, IconButton, IconButtonProps, Theme } from '@lumx/react';
8
8
  import { Comp, GenericProps, getRootClassName, handleBasicClasses } from '@lumx/react/utils';
9
9
  import { WINDOW } from '@lumx/react/constants';
@@ -24,7 +24,7 @@ export interface SlideshowControlsProps extends GenericProps {
24
24
  nextButtonProps: Pick<IconButtonProps, 'label'> &
25
25
  Omit<IconButtonProps, 'label' | 'onClick' | 'icon' | 'emphasis' | 'color'>;
26
26
  /** Reference to the parent element on which we want to listen touch swipe. */
27
- parentRef?: RefObject<HTMLDivElement> | HTMLDivElement;
27
+ parentRef?: RefObject<HTMLDivElement> | HTMLDivElement | null;
28
28
  /** Props to pass to the previous button (minus those already set by the SlideshowControls props). */
29
29
  previousButtonProps: Pick<IconButtonProps, 'label'> &
30
30
  Omit<IconButtonProps, 'label' | 'onClick' | 'icon' | 'emphasis' | 'color'>;
@@ -38,6 +38,13 @@ export interface SlideshowControlsProps extends GenericProps {
38
38
  onPaginationClick?(index: number): void;
39
39
  /** On previous button click callback. */
40
40
  onPreviousClick?(loopback?: boolean): void;
41
+ /** whether the slideshow is currently playing */
42
+ isAutoPlaying?: boolean;
43
+ /** function to be executed in order to retrieve the label for the pagination item */
44
+ paginationItemLabel?: (index: number) => string;
45
+ /** Props to pass to the lay button (minus those already set by the SlideshowControls props). */
46
+ playButtonProps?: Pick<IconButtonProps, 'label'> &
47
+ Omit<IconButtonProps, 'label' | 'onClick' | 'icon' | 'emphasis' | 'color'>;
41
48
  }
42
49
 
43
50
  /**
@@ -77,6 +84,9 @@ const InternalSlideshowControls: Comp<SlideshowControlsProps, HTMLDivElement> =
77
84
  previousButtonProps,
78
85
  slidesCount,
79
86
  theme,
87
+ isAutoPlaying = false,
88
+ playButtonProps,
89
+ paginationItemLabel,
80
90
  ...forwardedProps
81
91
  } = props;
82
92
 
@@ -130,7 +140,6 @@ const InternalSlideshowControls: Comp<SlideshowControlsProps, HTMLDivElement> =
130
140
  const isActive = activeIndex === index;
131
141
  const isOutRange = index < visibleRange.min || index > visibleRange.max;
132
142
  return (
133
- // eslint-disable-next-line jsx-a11y/control-has-associated-label
134
143
  <button
135
144
  className={classNames(
136
145
  handleBasicClasses({
@@ -143,13 +152,36 @@ const InternalSlideshowControls: Comp<SlideshowControlsProps, HTMLDivElement> =
143
152
  key={index}
144
153
  type="button"
145
154
  onClick={() => onPaginationClick?.(index)}
155
+ {...{
156
+ 'aria-label': paginationItemLabel
157
+ ? paginationItemLabel(index)
158
+ : `${index + 1} / ${slidesCount}`,
159
+ }}
146
160
  />
147
161
  );
148
162
  }),
149
- [slidesCount, visibleRange.min, visibleRange.max, activeIndex, onPaginationClick],
163
+ [
164
+ slidesCount,
165
+ visibleRange.min,
166
+ visibleRange.max,
167
+ activeIndex,
168
+ paginationItemLabel,
169
+ onPaginationClick,
170
+ ],
150
171
  )}
151
172
  </div>
152
173
  </div>
174
+
175
+ {playButtonProps ? (
176
+ <IconButton
177
+ {...playButtonProps}
178
+ icon={isAutoPlaying ? mdiPauseCircleOutline : mdiPlayCircleOutline}
179
+ className={`${CLASSNAME}__play`}
180
+ color={theme === Theme.dark ? 'light' : 'dark'}
181
+ emphasis={Emphasis.low}
182
+ />
183
+ ) : null}
184
+
153
185
  <IconButton
154
186
  {...nextButtonProps}
155
187
  icon={mdiChevronRight}
@@ -1,13 +1,22 @@
1
- import React, { forwardRef } from 'react';
1
+ import React, { forwardRef, useState } from 'react';
2
2
 
3
3
  import classNames from 'classnames';
4
4
 
5
5
  import { Comp, GenericProps, getRootClassName, handleBasicClasses } from '@lumx/react/utils';
6
6
 
7
+ import { useDelayedVisibility } from '@lumx/react/hooks/useDelayedVisibility';
8
+
9
+ import { SLIDESHOW_TRANSITION_DURATION } from '@lumx/core/js/constants';
10
+
7
11
  /**
8
12
  * Defines the props of the component.
9
13
  */
10
- export type SlideshowItemProps = GenericProps;
14
+ export interface SlideshowItemProps extends GenericProps {
15
+ /** whether the slideshow item is currently visible */
16
+ isCurrentlyVisible?: boolean;
17
+ /** interval in which slides are automatically shown */
18
+ interval?: number;
19
+ }
11
20
 
12
21
  /**
13
22
  * Component display name.
@@ -27,7 +36,12 @@ const CLASSNAME = getRootClassName(COMPONENT_NAME);
27
36
  * @return React element.
28
37
  */
29
38
  export const SlideshowItem: Comp<SlideshowItemProps, HTMLDivElement> = forwardRef((props, ref) => {
30
- const { className, children, ...forwardedProps } = props;
39
+ const { className, children, isCurrentlyVisible = false, ...forwardedProps } = props;
40
+ const [isVisible, setIsVisible] = useState<boolean>(isCurrentlyVisible);
41
+
42
+ useDelayedVisibility(isCurrentlyVisible, SLIDESHOW_TRANSITION_DURATION, (isNowVisible) => {
43
+ setIsVisible(isNowVisible);
44
+ });
31
45
 
32
46
  return (
33
47
  <div
@@ -41,6 +55,8 @@ export const SlideshowItem: Comp<SlideshowItemProps, HTMLDivElement> = forwardRe
41
55
  aria-roledescription="slide"
42
56
  role="group"
43
57
  {...forwardedProps}
58
+ style={!isVisible ? { visibility: 'hidden', ...(forwardedProps.style || {}) } : forwardedProps.style || {}}
59
+ aria-hidden={!isVisible}
44
60
  >
45
61
  {children}
46
62
  </div>