@lumx/react 2.2.6 → 2.2.9-alpha-exported-hooks1

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 (296) hide show
  1. package/esm/_internal/{_rollupPluginBabelHelpers.js → _rolluppluginbabelhelpers.53.js} +1 -1
  2. package/esm/_internal/_rolluppluginbabelhelpers.53.js.map +1 -0
  3. package/esm/_internal/alert-dialog.js +19 -19
  4. package/esm/_internal/{AlertDialog.js → alertdialog.1.js} +8 -8
  5. package/esm/_internal/alertdialog.1.js.map +1 -0
  6. package/esm/_internal/autocomplete.js +20 -21
  7. package/esm/_internal/autocomplete.js.map +1 -1
  8. package/esm/_internal/{AutocompleteMultiple.js → autocompletemultiple.2.js} +9 -9
  9. package/esm/_internal/autocompletemultiple.2.js.map +1 -0
  10. package/esm/_internal/{Avatar2.js → avatar.3.js} +4 -4
  11. package/esm/_internal/avatar.3.js.map +1 -0
  12. package/esm/_internal/avatar.js +6 -6
  13. package/esm/_internal/{Badge2.js → badge.4.js} +3 -3
  14. package/esm/_internal/badge.4.js.map +1 -0
  15. package/esm/_internal/badge.js +3 -3
  16. package/esm/_internal/{Button2.js → button.5.js} +5 -5
  17. package/esm/_internal/button.5.js.map +1 -0
  18. package/esm/_internal/button.js +14 -15
  19. package/esm/_internal/button.js.map +1 -1
  20. package/esm/_internal/{ButtonGroup.js → buttongroup.7.js} +3 -3
  21. package/esm/_internal/buttongroup.7.js.map +1 -0
  22. package/esm/_internal/{ButtonRoot.js → buttonroot.57.js} +4 -4
  23. package/esm/_internal/buttonroot.57.js.map +1 -0
  24. package/esm/_internal/{Checkbox2.js → checkbox.8.js} +7 -7
  25. package/esm/_internal/checkbox.8.js.map +1 -0
  26. package/esm/_internal/checkbox.js +7 -7
  27. package/esm/_internal/{Chip2.js → chip.9.js} +3 -3
  28. package/esm/_internal/chip.9.js.map +1 -0
  29. package/esm/_internal/chip.js +4 -4
  30. package/esm/_internal/{ChipGroup.js → chipgroup.10.js} +3 -3
  31. package/esm/_internal/chipgroup.10.js.map +1 -0
  32. package/esm/_internal/{ClickAwayProvider.js → clickawayprovider.60.js} +4 -4
  33. package/esm/_internal/clickawayprovider.60.js.map +1 -0
  34. package/esm/_internal/comment-block.js +7 -7
  35. package/esm/_internal/{CommentBlock.js → commentblock.11.js} +4 -4
  36. package/esm/_internal/commentblock.11.js.map +1 -0
  37. package/esm/_internal/components.js +1 -1
  38. package/esm/_internal/{constants.js → constants.59.js} +1 -1
  39. package/esm/_internal/constants.59.js.map +1 -0
  40. package/esm/_internal/date-picker.js +18 -19
  41. package/esm/_internal/date-picker.js.map +1 -1
  42. package/esm/_internal/{DatePickerField.js → datepickerfield.12.js} +9 -9
  43. package/esm/_internal/datepickerfield.12.js.map +1 -0
  44. package/esm/_internal/{Dialog2.js → dialog.13.js} +12 -12
  45. package/esm/_internal/dialog.13.js.map +1 -0
  46. package/esm/_internal/dialog.js +12 -12
  47. package/esm/_internal/{Divider2.js → divider.14.js} +3 -3
  48. package/esm/_internal/divider.14.js.map +1 -0
  49. package/esm/_internal/divider.js +3 -3
  50. package/esm/_internal/drag-handle.js +4 -4
  51. package/esm/_internal/{DragHandle.js → draghandle.15.js} +4 -4
  52. package/esm/_internal/draghandle.15.js.map +1 -0
  53. package/esm/_internal/{Dropdown2.js → dropdown.16.js} +6 -6
  54. package/esm/_internal/dropdown.16.js.map +1 -0
  55. package/esm/_internal/dropdown.js +10 -10
  56. package/esm/_internal/expansion-panel.js +16 -17
  57. package/esm/_internal/expansion-panel.js.map +1 -1
  58. package/esm/_internal/{ExpansionPanel.js → expansionpanel.17.js} +8 -8
  59. package/esm/_internal/expansionpanel.17.js.map +1 -0
  60. package/esm/_internal/{Flag2.js → flag.18.js} +4 -4
  61. package/esm/_internal/flag.18.js.map +1 -0
  62. package/esm/_internal/flag.js +4 -4
  63. package/esm/_internal/flex-box.js +3 -3
  64. package/esm/_internal/{FlexBox.js → flexbox.19.js} +3 -3
  65. package/esm/_internal/flexbox.19.js.map +1 -0
  66. package/esm/_internal/{getRootClassName.js → getrootclassname.54.js} +21 -3
  67. package/esm/_internal/getrootclassname.54.js.map +1 -0
  68. package/esm/_internal/grid.js +3 -3
  69. package/esm/_internal/{GridItem.js → griditem.20.js} +3 -3
  70. package/esm/_internal/griditem.20.js.map +1 -0
  71. package/esm/_internal/{Icon2.js → icon.21.js} +8 -5
  72. package/esm/_internal/icon.21.js.map +1 -0
  73. package/esm/_internal/icon.js +3 -3
  74. package/esm/_internal/{IconButton.js → iconbutton.6.js} +6 -6
  75. package/esm/_internal/iconbutton.6.js.map +1 -0
  76. package/esm/_internal/image-block.js +6 -6
  77. package/esm/_internal/{ImageBlock.js → imageblock.22.js} +4 -4
  78. package/esm/_internal/imageblock.22.js.map +1 -0
  79. package/esm/{index2.js → _internal/index.55.js} +1 -1
  80. package/esm/_internal/index.55.js.map +1 -0
  81. package/esm/_internal/input-helper.js +3 -3
  82. package/esm/_internal/input-label.js +3 -3
  83. package/esm/_internal/{InputHelper.js → inputhelper.23.js} +3 -3
  84. package/esm/_internal/inputhelper.23.js.map +1 -0
  85. package/esm/_internal/{InputLabel.js → inputlabel.24.js} +3 -3
  86. package/esm/_internal/inputlabel.24.js.map +1 -0
  87. package/esm/_internal/{Lightbox2.js → lightbox.25.js} +17 -15
  88. package/esm/_internal/lightbox.25.js.map +1 -0
  89. package/esm/_internal/lightbox.js +16 -17
  90. package/esm/_internal/lightbox.js.map +1 -1
  91. package/esm/_internal/link-preview.js +8 -8
  92. package/esm/_internal/{Link2.js → link.26.js} +5 -5
  93. package/esm/_internal/link.26.js.map +1 -0
  94. package/esm/_internal/link.js +5 -5
  95. package/esm/_internal/{LinkPreview.js → linkpreview.27.js} +5 -5
  96. package/esm/_internal/linkpreview.27.js.map +1 -0
  97. package/esm/_internal/{List2.js → list.28.js} +6 -6
  98. package/esm/_internal/list.28.js.map +1 -0
  99. package/esm/_internal/list.js +7 -7
  100. package/esm/_internal/{ListSubheader.js → listsubheader.29.js} +3 -3
  101. package/esm/_internal/listsubheader.29.js.map +1 -0
  102. package/esm/_internal/{mergeRefs.js → mergerefs.56.js} +1 -1
  103. package/esm/_internal/mergerefs.56.js.map +1 -0
  104. package/esm/_internal/{Message2.js → message.30.js} +4 -4
  105. package/esm/_internal/message.30.js.map +1 -0
  106. package/esm/_internal/message.js +4 -4
  107. package/esm/_internal/{Mosaic2.js → mosaic.31.js} +4 -4
  108. package/esm/_internal/mosaic.31.js.map +1 -0
  109. package/esm/_internal/mosaic.js +6 -6
  110. package/esm/_internal/{Notification2.js → notification.32.js} +9 -8
  111. package/esm/_internal/notification.32.js.map +1 -0
  112. package/esm/_internal/notification.js +9 -9
  113. package/esm/_internal/{partitionMulti.js → partitionmulti.62.js} +1 -1
  114. package/esm/_internal/partitionmulti.62.js.map +1 -0
  115. package/esm/_internal/{Popover2.js → popover.33.js} +6 -6
  116. package/esm/_internal/popover.33.js.map +1 -0
  117. package/esm/_internal/popover.js +6 -6
  118. package/esm/_internal/post-block.js +7 -7
  119. package/esm/_internal/{PostBlock.js → postblock.34.js} +5 -5
  120. package/esm/_internal/postblock.34.js.map +1 -0
  121. package/esm/_internal/progress-tracker.js +9 -9
  122. package/esm/_internal/{Progress2.js → progress.35.js} +3 -3
  123. package/esm/_internal/progress.35.js.map +1 -0
  124. package/esm/_internal/progress.js +3 -3
  125. package/esm/_internal/{ProgressTrackerStepPanel.js → progresstrackersteppanel.36.js} +8 -8
  126. package/esm/_internal/progresstrackersteppanel.36.js.map +1 -0
  127. package/esm/_internal/radio-button.js +6 -6
  128. package/esm/_internal/{RadioGroup.js → radiogroup.37.js} +6 -6
  129. package/esm/_internal/radiogroup.37.js.map +1 -0
  130. package/esm/_internal/{renderLink.js → renderlink.65.js} +2 -2
  131. package/esm/_internal/renderlink.65.js.map +1 -0
  132. package/esm/_internal/select.js +19 -20
  133. package/esm/_internal/select.js.map +1 -1
  134. package/esm/_internal/{SelectMultiple.js → selectmultiple.38.js} +12 -12
  135. package/esm/_internal/selectmultiple.38.js.map +1 -0
  136. package/esm/_internal/side-navigation.js +14 -15
  137. package/esm/_internal/side-navigation.js.map +1 -1
  138. package/esm/_internal/{SideNavigationItem.js → sidenavigationitem.39.js} +7 -7
  139. package/esm/_internal/sidenavigationitem.39.js.map +1 -0
  140. package/esm/_internal/skeleton.js +3 -3
  141. package/esm/_internal/{SkeletonTypography.js → skeletontypography.40.js} +3 -3
  142. package/esm/_internal/skeletontypography.40.js.map +1 -0
  143. package/esm/_internal/{Slider2.js → slider.41.js} +6 -6
  144. package/esm/_internal/slider.41.js.map +1 -0
  145. package/esm/_internal/slider.js +6 -6
  146. package/esm/_internal/slideshow.js +15 -14
  147. package/esm/_internal/slideshow.js.map +1 -1
  148. package/esm/_internal/{SlideshowControls.js → slideshowcontrols.42.js} +218 -101
  149. package/esm/_internal/slideshowcontrols.42.js.map +1 -0
  150. package/esm/_internal/{Switch2.js → switch.43.js} +6 -6
  151. package/esm/_internal/switch.43.js.map +1 -0
  152. package/esm/_internal/switch.js +6 -6
  153. package/esm/_internal/table.js +4 -4
  154. package/esm/_internal/{TableRow.js → tablerow.44.js} +4 -4
  155. package/esm/_internal/tablerow.44.js.map +1 -0
  156. package/esm/_internal/{TabPanel.js → tabpanel.45.js} +6 -6
  157. package/esm/_internal/tabpanel.45.js.map +1 -0
  158. package/esm/_internal/tabs.js +7 -7
  159. package/esm/_internal/text-field.js +15 -16
  160. package/esm/_internal/text-field.js.map +1 -1
  161. package/esm/_internal/{TextField.js → textfield.46.js} +9 -9
  162. package/esm/_internal/textfield.46.js.map +1 -0
  163. package/esm/_internal/{Thumbnail2.js → thumbnail.47.js} +7 -7
  164. package/esm/_internal/thumbnail.47.js.map +1 -0
  165. package/esm/_internal/thumbnail.js +6 -6
  166. package/esm/_internal/{Toolbar2.js → toolbar.49.js} +3 -3
  167. package/esm/_internal/toolbar.49.js.map +1 -0
  168. package/esm/_internal/toolbar.js +3 -3
  169. package/esm/_internal/{Tooltip2.js → tooltip.50.js} +116 -119
  170. package/esm/_internal/tooltip.50.js.map +1 -0
  171. package/esm/_internal/tooltip.js +8 -9
  172. package/esm/_internal/tooltip.js.map +1 -1
  173. package/esm/_internal/{type.js → type.64.js} +1 -1
  174. package/esm/_internal/type.64.js.map +1 -0
  175. package/esm/_internal/{types.js → types.48.js} +2 -3
  176. package/esm/_internal/types.48.js.map +1 -0
  177. package/esm/_internal/{Uploader2.js → uploader.51.js} +4 -4
  178. package/esm/_internal/uploader.51.js.map +1 -0
  179. package/esm/_internal/uploader.js +4 -4
  180. package/esm/_internal/{useDelayedVisibility.js → usedelayedvisibility.63.js} +2 -2
  181. package/esm/_internal/usedelayedvisibility.63.js.map +1 -0
  182. package/esm/_internal/{useDisableBodyScroll.js → usedisablebodyscroll.61.js} +1 -1
  183. package/esm/_internal/usedisablebodyscroll.61.js.map +1 -0
  184. package/esm/_internal/{useFocusTrap.js → usefocustrap.58.js} +2 -2
  185. package/esm/_internal/usefocustrap.58.js.map +1 -0
  186. package/esm/_internal/user-block.js +9 -9
  187. package/esm/_internal/{UserBlock.js → userblock.52.js} +5 -5
  188. package/esm/_internal/userblock.52.js.map +1 -0
  189. package/esm/_internal/{useRovingTabIndex.js → userovingtabindex.66.js} +3 -3
  190. package/esm/_internal/userovingtabindex.66.js.map +1 -0
  191. package/hooks/useFocusWithin.d.ts +16 -0
  192. package/hooks/useFocusWithin.js +28 -0
  193. package/hooks/useFocusWithin.js.map +1 -0
  194. package/index.d.ts +2723 -0
  195. package/index.js +90 -0
  196. package/{esm/index.js.map → index.js.map} +1 -1
  197. package/package.json +9 -10
  198. package/src/components/alert-dialog/AlertDialog.test.tsx +1 -0
  199. package/src/components/autocomplete/AutocompleteMultiple.tsx +3 -1
  200. package/src/components/button/__snapshots__/IconButton.test.tsx.snap +0 -5
  201. package/src/components/icon/Icon.tsx +6 -2
  202. package/src/components/image-block/ImageBlock.stories.tsx +1 -2
  203. package/src/components/lightbox/Lightbox.stories.tsx +1 -0
  204. package/src/components/lightbox/Lightbox.tsx +5 -3
  205. package/src/components/notification/Notification.tsx +1 -0
  206. package/src/components/select/SelectMultiple.tsx +0 -1
  207. package/src/components/slideshow/Slideshow.stories.tsx +1 -1
  208. package/src/components/slideshow/Slideshow.tsx +76 -112
  209. package/src/components/slideshow/SlideshowControls.stories.tsx +18 -12
  210. package/src/components/slideshow/SlideshowControls.tsx +11 -7
  211. package/src/components/slideshow/SlideshowItem.tsx +4 -1
  212. package/src/components/slideshow/__snapshots__/Slideshow.test.tsx.snap +52 -17
  213. package/src/components/tabs/state.ts +0 -1
  214. package/src/components/thumbnail/Thumbnail.stories.tsx +25 -1
  215. package/src/components/thumbnail/Thumbnail.test.tsx +9 -1
  216. package/src/components/thumbnail/Thumbnail.tsx +3 -0
  217. package/src/components/thumbnail/__snapshots__/Thumbnail.test.tsx.snap +26 -0
  218. package/src/components/thumbnail/index.ts +0 -1
  219. package/src/components/tooltip/Tooltip.tsx +1 -2
  220. package/src/components/tooltip/useTooltipOpen.tsx +90 -91
  221. package/src/constants.ts +7 -1
  222. package/src/hooks/useFocusWithin.ts +33 -0
  223. package/src/hooks/useSlideshowControls.ts +213 -0
  224. package/src/utils/browserDoesNotSupportHover.test.js +24 -0
  225. package/src/utils/browserDoesNotSupportHover.ts +2 -0
  226. package/src/utils/index.tsx +0 -2
  227. package/src/utils/mergeRefs.ts +1 -1
  228. package/esm/_internal/AlertDialog.js.map +0 -1
  229. package/esm/_internal/AutocompleteMultiple.js.map +0 -1
  230. package/esm/_internal/Avatar2.js.map +0 -1
  231. package/esm/_internal/Badge2.js.map +0 -1
  232. package/esm/_internal/Button2.js.map +0 -1
  233. package/esm/_internal/ButtonGroup.js.map +0 -1
  234. package/esm/_internal/ButtonRoot.js.map +0 -1
  235. package/esm/_internal/Checkbox2.js.map +0 -1
  236. package/esm/_internal/Chip2.js.map +0 -1
  237. package/esm/_internal/ChipGroup.js.map +0 -1
  238. package/esm/_internal/ClickAwayProvider.js.map +0 -1
  239. package/esm/_internal/CommentBlock.js.map +0 -1
  240. package/esm/_internal/DatePickerField.js.map +0 -1
  241. package/esm/_internal/Dialog2.js.map +0 -1
  242. package/esm/_internal/Divider2.js.map +0 -1
  243. package/esm/_internal/DragHandle.js.map +0 -1
  244. package/esm/_internal/Dropdown2.js.map +0 -1
  245. package/esm/_internal/ExpansionPanel.js.map +0 -1
  246. package/esm/_internal/Flag2.js.map +0 -1
  247. package/esm/_internal/FlexBox.js.map +0 -1
  248. package/esm/_internal/GridItem.js.map +0 -1
  249. package/esm/_internal/Icon2.js.map +0 -1
  250. package/esm/_internal/IconButton.js.map +0 -1
  251. package/esm/_internal/ImageBlock.js.map +0 -1
  252. package/esm/_internal/InputHelper.js.map +0 -1
  253. package/esm/_internal/InputLabel.js.map +0 -1
  254. package/esm/_internal/Lightbox2.js.map +0 -1
  255. package/esm/_internal/Link2.js.map +0 -1
  256. package/esm/_internal/LinkPreview.js.map +0 -1
  257. package/esm/_internal/List2.js.map +0 -1
  258. package/esm/_internal/ListSubheader.js.map +0 -1
  259. package/esm/_internal/Message2.js.map +0 -1
  260. package/esm/_internal/Mosaic2.js.map +0 -1
  261. package/esm/_internal/Notification2.js.map +0 -1
  262. package/esm/_internal/Popover2.js.map +0 -1
  263. package/esm/_internal/PostBlock.js.map +0 -1
  264. package/esm/_internal/Progress2.js.map +0 -1
  265. package/esm/_internal/ProgressTrackerStepPanel.js.map +0 -1
  266. package/esm/_internal/RadioGroup.js.map +0 -1
  267. package/esm/_internal/SelectMultiple.js.map +0 -1
  268. package/esm/_internal/SideNavigationItem.js.map +0 -1
  269. package/esm/_internal/SkeletonTypography.js.map +0 -1
  270. package/esm/_internal/Slider2.js.map +0 -1
  271. package/esm/_internal/SlideshowControls.js.map +0 -1
  272. package/esm/_internal/Switch2.js.map +0 -1
  273. package/esm/_internal/TabPanel.js.map +0 -1
  274. package/esm/_internal/TableRow.js.map +0 -1
  275. package/esm/_internal/TextField.js.map +0 -1
  276. package/esm/_internal/Thumbnail2.js.map +0 -1
  277. package/esm/_internal/Toolbar2.js.map +0 -1
  278. package/esm/_internal/Tooltip2.js.map +0 -1
  279. package/esm/_internal/Uploader2.js.map +0 -1
  280. package/esm/_internal/UserBlock.js.map +0 -1
  281. package/esm/_internal/_rollupPluginBabelHelpers.js.map +0 -1
  282. package/esm/_internal/constants.js.map +0 -1
  283. package/esm/_internal/getRootClassName.js.map +0 -1
  284. package/esm/_internal/mergeRefs.js.map +0 -1
  285. package/esm/_internal/partitionMulti.js.map +0 -1
  286. package/esm/_internal/renderLink.js.map +0 -1
  287. package/esm/_internal/type.js.map +0 -1
  288. package/esm/_internal/types.js.map +0 -1
  289. package/esm/_internal/useDelayedVisibility.js.map +0 -1
  290. package/esm/_internal/useDisableBodyScroll.js.map +0 -1
  291. package/esm/_internal/useFocusTrap.js.map +0 -1
  292. package/esm/_internal/useRovingTabIndex.js.map +0 -1
  293. package/esm/index.js +0 -89
  294. package/esm/index2.js.map +0 -1
  295. package/src/utils/htmlDecode.ts +0 -13
  296. package/types.d.ts +0 -2575
@@ -7,6 +7,7 @@ import { mdiChevronLeft, mdiChevronRight } 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';
10
+ import { useSlideshowControls, DEFAULT_OPTIONS } from '@lumx/react/hooks/useSlideshowControls';
10
11
 
11
12
  import { useSwipeNavigate } from './useSwipeNavigate';
12
13
  import { useKeyNavigate } from './useKeyNavigate';
@@ -64,7 +65,7 @@ const DEFAULT_PROPS: Partial<SlideshowControlsProps> = {
64
65
  * @param ref Component ref.
65
66
  * @return React element.
66
67
  */
67
- export const SlideshowControls: Comp<SlideshowControlsProps, HTMLDivElement> = forwardRef((props, ref) => {
68
+ const InternalSlideshowControls: Comp<SlideshowControlsProps, HTMLDivElement> = forwardRef((props, ref) => {
68
69
  const {
69
70
  activeIndex,
70
71
  className,
@@ -116,7 +117,6 @@ export const SlideshowControls: Comp<SlideshowControlsProps, HTMLDivElement> = f
116
117
  color={theme === Theme.dark ? 'light' : 'dark'}
117
118
  emphasis={Emphasis.low}
118
119
  onClick={onPreviousClick}
119
- tabIndex={-1}
120
120
  />
121
121
  <div className={`${CLASSNAME}__pagination`}>
122
122
  <div className={`${CLASSNAME}__pagination-items`} style={wrapperStyle}>
@@ -143,7 +143,6 @@ export const SlideshowControls: Comp<SlideshowControlsProps, HTMLDivElement> = f
143
143
  key={index}
144
144
  type="button"
145
145
  onClick={() => onPaginationClick?.(index)}
146
- tabIndex={-1}
147
146
  />
148
147
  );
149
148
  }),
@@ -158,11 +157,16 @@ export const SlideshowControls: Comp<SlideshowControlsProps, HTMLDivElement> = f
158
157
  color={theme === Theme.dark ? 'light' : 'dark'}
159
158
  emphasis={Emphasis.low}
160
159
  onClick={onNextClick}
161
- tabIndex={-1}
162
160
  />
163
161
  </div>
164
162
  );
165
163
  });
166
- SlideshowControls.displayName = COMPONENT_NAME;
167
- SlideshowControls.className = CLASSNAME;
168
- SlideshowControls.defaultProps = DEFAULT_PROPS;
164
+
165
+ InternalSlideshowControls.displayName = COMPONENT_NAME;
166
+ InternalSlideshowControls.className = CLASSNAME;
167
+ InternalSlideshowControls.defaultProps = DEFAULT_PROPS;
168
+
169
+ export const SlideshowControls = Object.assign(InternalSlideshowControls, {
170
+ useSlideshowControls,
171
+ useSlideshowControlsDefaultOptions: DEFAULT_OPTIONS,
172
+ });
@@ -32,17 +32,20 @@ export const SlideshowItem: Comp<SlideshowItemProps, HTMLDivElement> = forwardRe
32
32
  return (
33
33
  <div
34
34
  ref={ref}
35
- {...forwardedProps}
36
35
  className={classNames(
37
36
  className,
38
37
  handleBasicClasses({
39
38
  prefix: CLASSNAME,
40
39
  }),
41
40
  )}
41
+ aria-roledescription="slide"
42
+ role="group"
43
+ {...forwardedProps}
42
44
  >
43
45
  {children}
44
46
  </div>
45
47
  );
46
48
  });
49
+
47
50
  SlideshowItem.displayName = COMPONENT_NAME;
48
51
  SlideshowItem.className = CLASSNAME;
@@ -2,17 +2,22 @@
2
2
 
3
3
  exports[`<Slideshow> Snapshots and structure should render story 'Simple' 1`] = `
4
4
  Array [
5
- <div
5
+ <section
6
+ aria-live="polite"
7
+ aria-roledescription="carousel"
6
8
  className="lumx-slideshow lumx-slideshow--theme-light lumx-slideshow--group-by-1"
9
+ id="slideshow1"
7
10
  style={
8
11
  Object {
9
12
  "width": "50%",
10
13
  }
11
14
  }
12
- tabIndex={0}
13
15
  >
14
16
  <div
15
17
  className="lumx-slideshow__slides"
18
+ id="slideshow-slides2"
19
+ onMouseEnter={[Function]}
20
+ onMouseLeave={[Function]}
16
21
  >
17
22
  <div
18
23
  className="lumx-slideshow__wrapper"
@@ -23,7 +28,9 @@ Array [
23
28
  }
24
29
  >
25
30
  <SlideshowItem
26
- key="/demo-assets/landscape1.jpg-0"
31
+ aria-hidden={false}
32
+ key=".$/demo-assets/landscape1.jpg-0"
33
+ style={Object {}}
27
34
  >
28
35
  <ImageBlock
29
36
  align="left"
@@ -34,12 +41,15 @@ Array [
34
41
  thumbnailProps={
35
42
  Object {
36
43
  "aspectRatio": "horizontal",
44
+ "loading": "eager",
37
45
  }
38
46
  }
39
47
  />
40
48
  </SlideshowItem>
41
49
  <SlideshowItem
42
- key="/demo-assets/landscape1-s200.jpg-1"
50
+ aria-hidden={false}
51
+ key=".$/demo-assets/landscape1-s200.jpg-1"
52
+ style={Object {}}
43
53
  >
44
54
  <ImageBlock
45
55
  align="left"
@@ -50,12 +60,19 @@ Array [
50
60
  thumbnailProps={
51
61
  Object {
52
62
  "aspectRatio": "horizontal",
63
+ "loading": "eager",
53
64
  }
54
65
  }
55
66
  />
56
67
  </SlideshowItem>
57
68
  <SlideshowItem
58
- key="/demo-assets/landscape2.jpg-2"
69
+ aria-hidden={true}
70
+ key=".$/demo-assets/landscape2.jpg-2"
71
+ style={
72
+ Object {
73
+ "visibility": "hidden",
74
+ }
75
+ }
59
76
  >
60
77
  <ImageBlock
61
78
  align="left"
@@ -66,12 +83,19 @@ Array [
66
83
  thumbnailProps={
67
84
  Object {
68
85
  "aspectRatio": "horizontal",
86
+ "loading": "eager",
69
87
  }
70
88
  }
71
89
  />
72
90
  </SlideshowItem>
73
91
  <SlideshowItem
74
- key="/demo-assets/landscape3.jpg-3"
92
+ aria-hidden={true}
93
+ key=".$/demo-assets/landscape3.jpg-3"
94
+ style={
95
+ Object {
96
+ "visibility": "hidden",
97
+ }
98
+ }
75
99
  >
76
100
  <ImageBlock
77
101
  align="left"
@@ -82,12 +106,19 @@ Array [
82
106
  thumbnailProps={
83
107
  Object {
84
108
  "aspectRatio": "horizontal",
109
+ "loading": "eager",
85
110
  }
86
111
  }
87
112
  />
88
113
  </SlideshowItem>
89
114
  <SlideshowItem
90
- key="/demo-assets/portrait1.jpg-4"
115
+ aria-hidden={true}
116
+ key=".$/demo-assets/portrait1.jpg-4"
117
+ style={
118
+ Object {
119
+ "visibility": "hidden",
120
+ }
121
+ }
91
122
  >
92
123
  <ImageBlock
93
124
  align="left"
@@ -98,12 +129,19 @@ Array [
98
129
  thumbnailProps={
99
130
  Object {
100
131
  "aspectRatio": "horizontal",
132
+ "loading": "eager",
101
133
  }
102
134
  }
103
135
  />
104
136
  </SlideshowItem>
105
137
  <SlideshowItem
106
- key="/demo-assets/portrait1-s200.jpg-5"
138
+ aria-hidden={true}
139
+ key=".$/demo-assets/portrait1-s200.jpg-5"
140
+ style={
141
+ Object {
142
+ "visibility": "hidden",
143
+ }
144
+ }
107
145
  >
108
146
  <ImageBlock
109
147
  align="left"
@@ -114,6 +152,7 @@ Array [
114
152
  thumbnailProps={
115
153
  Object {
116
154
  "aspectRatio": "horizontal",
155
+ "loading": "eager",
117
156
  }
118
157
  }
119
158
  />
@@ -127,6 +166,7 @@ Array [
127
166
  activeIndex={0}
128
167
  nextButtonProps={
129
168
  Object {
169
+ "aria-controls": "slideshow-slides2",
130
170
  "label": "Next",
131
171
  }
132
172
  }
@@ -135,6 +175,7 @@ Array [
135
175
  onPreviousClick={[Function]}
136
176
  previousButtonProps={
137
177
  Object {
178
+ "aria-controls": "slideshow-slides2",
138
179
  "label": "Previous",
139
180
  }
140
181
  }
@@ -142,11 +183,12 @@ Array [
142
183
  theme="light"
143
184
  />
144
185
  </div>
145
- </div>,
186
+ </section>,
146
187
  <div
147
188
  className="lumx-slideshow-controls lumx-slideshow-controls--theme-light lumx-slideshow-controls--has-infinite-pagination"
148
189
  >
149
190
  <IconButton
191
+ aria-controls="slideshow-slides4"
150
192
  className="lumx-slideshow-controls__navigation"
151
193
  color="dark"
152
194
  emphasis="low"
@@ -154,7 +196,6 @@ Array [
154
196
  label="Previous"
155
197
  onClick={[Function]}
156
198
  size="m"
157
- tabIndex={-1}
158
199
  theme="light"
159
200
  />
160
201
  <div
@@ -172,47 +213,42 @@ Array [
172
213
  className="lumx-slideshow-controls__pagination-item lumx-slideshow-controls__pagination-item--is-active"
173
214
  key="0"
174
215
  onClick={[Function]}
175
- tabIndex={-1}
176
216
  type="button"
177
217
  />
178
218
  <button
179
219
  className="lumx-slideshow-controls__pagination-item"
180
220
  key="1"
181
221
  onClick={[Function]}
182
- tabIndex={-1}
183
222
  type="button"
184
223
  />
185
224
  <button
186
225
  className="lumx-slideshow-controls__pagination-item"
187
226
  key="2"
188
227
  onClick={[Function]}
189
- tabIndex={-1}
190
228
  type="button"
191
229
  />
192
230
  <button
193
231
  className="lumx-slideshow-controls__pagination-item"
194
232
  key="3"
195
233
  onClick={[Function]}
196
- tabIndex={-1}
197
234
  type="button"
198
235
  />
199
236
  <button
200
237
  className="lumx-slideshow-controls__pagination-item lumx-slideshow-controls__pagination-item--is-on-edge"
201
238
  key="4"
202
239
  onClick={[Function]}
203
- tabIndex={-1}
204
240
  type="button"
205
241
  />
206
242
  <button
207
243
  className="lumx-slideshow-controls__pagination-item lumx-slideshow-controls__pagination-item--is-out-range"
208
244
  key="5"
209
245
  onClick={[Function]}
210
- tabIndex={-1}
211
246
  type="button"
212
247
  />
213
248
  </div>
214
249
  </div>
215
250
  <IconButton
251
+ aria-controls="slideshow-slides4"
216
252
  className="lumx-slideshow-controls__navigation"
217
253
  color="dark"
218
254
  emphasis="low"
@@ -220,7 +256,6 @@ Array [
220
256
  label="Next"
221
257
  onClick={[Function]}
222
258
  size="m"
223
- tabIndex={-1}
224
259
  theme="light"
225
260
  />
226
261
  </div>,
@@ -1,5 +1,4 @@
1
1
  import { Dispatch, createContext, useCallback, useContext, useEffect, useMemo } from 'react';
2
- import { clamp } from '@lumx/react/utils/clamp';
3
2
  import { uid } from 'uid';
4
3
 
5
4
  type TabType = 'tab' | 'tabPanel';
@@ -18,7 +18,6 @@ import { enumKnob } from '@lumx/react/stories/knobs/enumKnob';
18
18
  import { focusKnob } from '@lumx/react/stories/knobs/focusKnob';
19
19
  import { sizeKnob } from '@lumx/react/stories/knobs/sizeKnob';
20
20
  import { action } from '@storybook/addon-actions';
21
- import classNames from 'classnames';
22
21
  import { CustomLink } from '@lumx/react/stories/utils/CustomLink';
23
22
 
24
23
  export default { title: 'LumX components/thumbnail/Thumbnail' };
@@ -84,6 +83,31 @@ export const WithBadge = () => {
84
83
  );
85
84
  };
86
85
 
86
+ export const WithCustomImageClassName = () => {
87
+ const thumbnailSize = sizeKnob('Size', Size.l);
88
+ const variant = select('Variant', ThumbnailVariant, ThumbnailVariant.rounded);
89
+ const badgeColor = select('Badge color', ColorPalette, ColorPalette.primary);
90
+ const activateFallback = boolean('Activate fallback', false);
91
+ const image = imageKnob();
92
+ return (
93
+ <Thumbnail
94
+ alt="Image alt text"
95
+ image={activateFallback ? '' : image}
96
+ variant={variant}
97
+ aspectRatio={AspectRatio.square}
98
+ size={thumbnailSize}
99
+ badge={
100
+ <Badge color={badgeColor}>
101
+ <Icon icon={mdiAbTesting} />
102
+ </Badge>
103
+ }
104
+ imgProps={{
105
+ className: 'custom-image-class-name',
106
+ }}
107
+ />
108
+ );
109
+ };
110
+
87
111
  export const FocusPoint = () => {
88
112
  const focusPoint = { x: focusKnob('Focus X ', -0.2), y: focusKnob('Focus Y', -0.3) };
89
113
  const aspectRatio = enumKnob('Aspect ratio', [undefined, ...Object.values(AspectRatio)], AspectRatio.wide);
@@ -5,7 +5,14 @@ import 'jest-enzyme';
5
5
  import { commonTestsSuite, itShouldRenderStories } from '@lumx/react/testing/utils';
6
6
 
7
7
  import { Thumbnail, ThumbnailProps } from './Thumbnail';
8
- import { Clickable, ClickableCustomLink, ClickableLink, Default, WithBadge } from './Thumbnail.stories';
8
+ import {
9
+ Clickable,
10
+ ClickableCustomLink,
11
+ ClickableLink,
12
+ Default,
13
+ WithBadge,
14
+ WithCustomImageClassName,
15
+ } from './Thumbnail.stories';
9
16
 
10
17
  const CLASSNAME = Thumbnail.className as string;
11
18
 
@@ -28,6 +35,7 @@ describe(`<${Thumbnail.displayName}>`, () => {
28
35
  ClickableLink,
29
36
  ClickableCustomLink,
30
37
  WithBadge,
38
+ WithCustomImageClassName,
31
39
  },
32
40
  Thumbnail,
33
41
  );
@@ -105,6 +105,8 @@ export const Thumbnail: Comp<ThumbnailProps> = forwardRef((props, ref) => {
105
105
  crossOrigin,
106
106
  fallback,
107
107
  fillHeight,
108
+ // `focusPoint` needs to be here to remove it from `forwardedProps`.
109
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
108
110
  focusPoint,
109
111
  image,
110
112
  imgProps,
@@ -194,6 +196,7 @@ export const Thumbnail: Comp<ThumbnailProps> = forwardRef((props, ref) => {
194
196
  isLoading,
195
197
  hasDefinedSize: Boolean(imgProps?.height && imgProps.width),
196
198
  }),
199
+ imgProps?.className,
197
200
  )}
198
201
  crossOrigin={crossOrigin}
199
202
  src={image}
@@ -102,3 +102,29 @@ exports[`<Thumbnail> Snapshots and structure should render story 'WithBadge' 1`]
102
102
  </Badge>
103
103
  </div>
104
104
  `;
105
+
106
+ exports[`<Thumbnail> Snapshots and structure should render story 'WithCustomImageClassName' 1`] = `
107
+ <div
108
+ className="lumx-thumbnail lumx-thumbnail--aspect-ratio-square lumx-thumbnail--size-l lumx-thumbnail--theme-light lumx-thumbnail--variant-rounded lumx-thumbnail--is-loading lumx-thumbnail--has-badge"
109
+ >
110
+ <div
111
+ className="lumx-thumbnail__background"
112
+ >
113
+ <img
114
+ alt="Image alt text"
115
+ className="lumx-thumbnail__image lumx-thumbnail__image--is-loading custom-image-class-name"
116
+ loading="lazy"
117
+ src="/demo-assets/landscape1.jpg"
118
+ style={Object {}}
119
+ />
120
+ </div>
121
+ <Badge
122
+ className="lumx-thumbnail__badge"
123
+ color="primary"
124
+ >
125
+ <Icon
126
+ icon="M4 2A2 2 0 0 0 2 4V12H4V8H6V12H8V4A2 2 0 0 0 6 2H4M4 4H6V6H4M22 15.5V14A2 2 0 0 0 20 12H16V22H20A2 2 0 0 0 22 20V18.5A1.54 1.54 0 0 0 20.5 17A1.54 1.54 0 0 0 22 15.5M20 20H18V18H20V20M20 16H18V14H20M5.79 21.61L4.21 20.39L18.21 2.39L19.79 3.61Z"
127
+ />
128
+ </Badge>
129
+ </div>
130
+ `;
@@ -1,3 +1,2 @@
1
1
  export * from './Thumbnail';
2
2
  export * from './types';
3
- export { useFocusPointStyle } from '@lumx/react/components/thumbnail/useFocusPointStyle';
@@ -49,7 +49,6 @@ const CLASSNAME = getRootClassName(COMPONENT_NAME);
49
49
  * Component default props.
50
50
  */
51
51
  const DEFAULT_PROPS: Partial<TooltipProps> = {
52
- delay: 500,
53
52
  placement: Placement.BOTTOM,
54
53
  };
55
54
 
@@ -90,7 +89,7 @@ export const Tooltip: Comp<TooltipProps, HTMLDivElement> = forwardRef((props, re
90
89
  });
91
90
 
92
91
  const position = attributes?.popper?.['data-popper-placement'] ?? placement;
93
- const isOpen = useTooltipOpen(delay as number, anchorElement) || forceOpen;
92
+ const isOpen = useTooltipOpen(delay, anchorElement) || forceOpen;
94
93
  const wrappedChildren = useInjectTooltipRef(children, setAnchorElement, isOpen as boolean, id);
95
94
 
96
95
  return (
@@ -1,60 +1,7 @@
1
- import { Callback, onEscapePressed } from '@lumx/react/utils';
2
- import { useEffect, useRef, useState } from 'react';
3
- import pull from 'lodash/pull';
4
- import debounce from 'lodash/debounce';
5
-
6
- type Tooltip = { open: Callback; close: Callback; anchorElement: HTMLElement };
7
-
8
- /**
9
- * This singleton handle a global `mouseover` event listener on the `document` in order to toggle tooltips when
10
- * entering and leaving their anchor element.
11
- */
12
- const tooltipMouseToggle = (() => {
13
- /** List of tooltips to toggle on anchor enter/leave. */
14
- let tooltips: Array<Tooltip> | undefined;
15
-
16
- /** Global listener added on the document. */
17
- let globalListener: undefined | ((evt: MouseEvent) => void);
18
-
19
- function addGlobalListener() {
20
- if (globalListener) return;
21
- globalListener = debounce((evt) => {
22
- if (!tooltips || !evt.target) return;
23
- for (const { open, close, anchorElement } of tooltips) {
24
- if (anchorElement.contains(evt.target as any)) {
25
- open();
26
- } else {
27
- close();
28
- }
29
- }
30
- }, 10);
31
- document.addEventListener('mouseover', globalListener);
32
- }
33
-
34
- function removeGlobalListener() {
35
- if (!globalListener) return;
36
- document.removeEventListener('mouseover', globalListener);
37
- globalListener = undefined;
38
- }
39
-
40
- return {
41
- addTooltip(tooltip: Tooltip) {
42
- if (!tooltips) {
43
- tooltips = [];
44
- addGlobalListener();
45
- }
46
- tooltips.push(tooltip);
47
- },
48
- removeTooltip(actions: Tooltip) {
49
- if (!tooltips) return;
50
- pull(tooltips, actions);
51
- if (tooltips.length === 0) {
52
- removeGlobalListener();
53
- tooltips = undefined;
54
- }
55
- },
56
- };
57
- })();
1
+ import { onEscapePressed } from '@lumx/react/utils';
2
+ import { useEffect, useState } from 'react';
3
+ import { browserDoesNotSupportHover } from '@lumx/react/utils/browserDoesNotSupportHover';
4
+ import { TOOLTIP_HOVER_DELAY, TOOLTIP_LONG_PRESS_DELAY } from '@lumx/react/constants';
58
5
 
59
6
  /**
60
7
  * Hook controlling tooltip visibility using mouse hover the anchor and delay.
@@ -63,50 +10,102 @@ const tooltipMouseToggle = (() => {
63
10
  * @param anchorElement Tooltip anchor element.
64
11
  * @return whether or not to show the tooltip.
65
12
  */
66
- export function useTooltipOpen(delay: number, anchorElement: HTMLElement | null): boolean {
67
- const timer = useRef<number>();
68
- const shouldOpen = useRef<boolean>(false);
13
+ export function useTooltipOpen(delay: number | undefined, anchorElement: HTMLElement | null): boolean {
69
14
  const [isOpen, setIsOpen] = useState(false);
70
15
 
71
16
  useEffect(() => {
72
17
  if (!anchorElement) {
73
18
  return undefined;
74
19
  }
75
- const tooltip: Tooltip = {
76
- anchorElement,
77
- open() {
78
- if (!shouldOpen.current) {
79
- shouldOpen.current = true;
80
- timer.current = setTimeout(() => {
81
- setIsOpen(shouldOpen.current);
82
- }, delay) as any;
83
- }
84
- },
85
- close() {
86
- if (timer.current) {
87
- clearTimeout(timer.current);
88
- timer.current = undefined;
89
- }
90
- if (shouldOpen.current) {
91
- shouldOpen.current = false;
92
- setIsOpen(shouldOpen.current);
93
- }
94
- },
20
+ let timer: number | undefined;
21
+ let openStartTime: number | undefined;
22
+ let shouldOpen: boolean | undefined;
23
+
24
+ // Run timer to defer updating the isOpen state.
25
+ const deferUpdate = (duration: number) => {
26
+ if (timer) clearTimeout(timer);
27
+ timer = setTimeout(() => {
28
+ setIsOpen(!!shouldOpen);
29
+ }, duration) as any;
95
30
  };
96
- const keydown = onEscapePressed(tooltip.close);
97
31
 
98
- tooltipMouseToggle.addTooltip(tooltip);
99
- anchorElement.addEventListener('focusin', tooltip.open);
100
- anchorElement.addEventListener('focusout', tooltip.close);
101
- anchorElement.addEventListener('keydown', keydown);
32
+ const hoverNotSupported = browserDoesNotSupportHover();
33
+ const hasTouch = 'ontouchstart' in window;
34
+
35
+ // Adapt open/close delay
36
+ const openDelay = delay || (hoverNotSupported ? TOOLTIP_LONG_PRESS_DELAY.open : TOOLTIP_HOVER_DELAY.open);
37
+ const closeDelay = hoverNotSupported ? TOOLTIP_LONG_PRESS_DELAY.close : TOOLTIP_HOVER_DELAY.close;
38
+
39
+ // Open (or/and cancel closing) of tooltip.
40
+ const open = () => {
41
+ if (shouldOpen && !timer) return;
42
+ shouldOpen = true;
43
+ openStartTime = Date.now();
44
+ deferUpdate(openDelay);
45
+ };
46
+
47
+ // Close or cancel opening of tooltip
48
+ const close = (overrideDelay = closeDelay) => {
49
+ if (!shouldOpen && !timer) return;
50
+ shouldOpen = false;
51
+ deferUpdate(overrideDelay);
52
+ };
53
+ const closeImmediately = () => close(0);
54
+
55
+ /**
56
+ * Handle touchend event
57
+ * If `touchend` comes before the open delay => cancel tooltip (close immediate).
58
+ * Else if `touchend` comes after the open delay => tooltip takes priority, the anchor's default touch end event is prevented.
59
+ */
60
+ const touchEnd = (evt: Event) => {
61
+ if (!openStartTime) return;
62
+ if (Date.now() - openStartTime >= openDelay) {
63
+ // Tooltip take priority, event prevented.
64
+ evt.stopPropagation();
65
+ evt.preventDefault();
66
+ anchorElement.focus();
67
+ // Close with delay.
68
+ close();
69
+ } else {
70
+ // Close immediately.
71
+ closeImmediately();
72
+ }
73
+ };
74
+
75
+ // Adapt event to browsers with or without `hover` support.
76
+ const events: Array<[Node, Event['type'], any]> = hoverNotSupported
77
+ ? [
78
+ [anchorElement, hasTouch ? 'touchstart' : 'mousedown', open],
79
+ [anchorElement, hasTouch ? 'touchend' : 'mouseup', touchEnd],
80
+ ]
81
+ : [
82
+ [anchorElement, 'mouseenter', open],
83
+ [anchorElement, 'mouseleave', close],
84
+ [anchorElement, 'mouseup', closeImmediately],
85
+ ];
86
+
87
+ // Events always applied no matter the browser:.
88
+ events.push(
89
+ // Open on focus.
90
+ [anchorElement, 'focusin', open],
91
+ // Close on lost focus.
92
+ [anchorElement, 'focusout', closeImmediately],
93
+ // Close on ESC keydown
94
+ [anchorElement, 'keydown', onEscapePressed(closeImmediately)],
95
+ );
96
+
97
+ // Attach events
98
+ for (const [node, eventType, evenHandler] of events) {
99
+ node.addEventListener(eventType, evenHandler);
100
+ }
102
101
  return () => {
103
- tooltipMouseToggle.removeTooltip(tooltip);
104
- anchorElement.removeEventListener('focusin', tooltip.open);
105
- anchorElement.removeEventListener('focusout', tooltip.close);
106
- anchorElement.removeEventListener('keydown', keydown);
107
- tooltip.close();
102
+ // Detach events.
103
+ for (const [node, eventType, evenHandler] of events) {
104
+ node.removeEventListener(eventType, evenHandler);
105
+ }
106
+ closeImmediately();
108
107
  };
109
- }, [anchorElement, delay, timer, shouldOpen]);
108
+ }, [anchorElement, delay]);
110
109
 
111
110
  return isOpen;
112
111
  }
package/src/constants.ts CHANGED
@@ -1,4 +1,10 @@
1
- export { CSS_PREFIX, DIALOG_TRANSITION_DURATION, NOTIFICATION_TRANSITION_DURATION } from '@lumx/core/js/constants';
1
+ export {
2
+ CSS_PREFIX,
3
+ DIALOG_TRANSITION_DURATION,
4
+ NOTIFICATION_TRANSITION_DURATION,
5
+ TOOLTIP_HOVER_DELAY,
6
+ TOOLTIP_LONG_PRESS_DELAY,
7
+ } from '@lumx/core/js/constants';
2
8
 
3
9
  /**
4
10
  * Optional global `window` instance (not defined when running SSR).