@lumx/react 3.20.1-alpha.5 → 3.20.1-alpha.7

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 (230) hide show
  1. package/_internal/index.js.map +1 -1
  2. package/index.d.ts +35 -34
  3. package/index.js +778 -651
  4. package/index.js.map +1 -1
  5. package/package.json +13 -12
  6. package/src/components/alert-dialog/AlertDialog.stories.tsx +1 -1
  7. package/src/components/alert-dialog/AlertDialog.test.tsx +3 -4
  8. package/src/components/autocomplete/Autocomplete.stories.tsx +1 -1
  9. package/src/components/autocomplete/Autocomplete.test.tsx +3 -5
  10. package/src/components/autocomplete/Autocomplete.tsx +1 -1
  11. package/src/components/autocomplete/AutocompleteMultiple.stories.tsx +1 -1
  12. package/src/components/autocomplete/AutocompleteMultiple.test.tsx +0 -2
  13. package/src/components/autocomplete/AutocompleteMultiple.tsx +1 -1
  14. package/src/components/avatar/Avatar.stories.tsx +0 -2
  15. package/src/components/avatar/Avatar.test.tsx +0 -2
  16. package/src/components/avatar/Avatar.tsx +1 -1
  17. package/src/components/badge/Badge.stories.tsx +0 -1
  18. package/src/components/badge/Badge.test.tsx +0 -2
  19. package/src/components/badge/Badge.tsx +1 -1
  20. package/src/components/badge/BadgeWrapper.stories.tsx +0 -1
  21. package/src/components/badge/BadgeWrapper.test.tsx +0 -2
  22. package/src/components/badge/BadgeWrapper.tsx +1 -1
  23. package/src/components/button/Button.stories.tsx +0 -1
  24. package/src/components/button/Button.test.tsx +9 -11
  25. package/src/components/button/Button.tsx +0 -2
  26. package/src/components/button/ButtonGroup.stories.tsx +0 -2
  27. package/src/components/button/ButtonGroup.test.tsx +0 -2
  28. package/src/components/button/ButtonGroup.tsx +0 -2
  29. package/src/components/button/ButtonRoot.tsx +7 -37
  30. package/src/components/button/IconButton.test.tsx +0 -2
  31. package/src/components/button/IconButton.tsx +0 -2
  32. package/src/components/checkbox/Checkbox.test.tsx +3 -5
  33. package/src/components/chip/Chip.stories.tsx +0 -2
  34. package/src/components/chip/Chip.test.tsx +19 -19
  35. package/src/components/chip/Chip.tsx +1 -1
  36. package/src/components/chip/ChipGroup.stories.tsx +0 -2
  37. package/src/components/chip/ChipGroup.test.tsx +0 -2
  38. package/src/components/chip/ChipGroup.tsx +1 -1
  39. package/src/components/comment-block/CommentBlock.stories.tsx +0 -1
  40. package/src/components/comment-block/CommentBlock.test.tsx +0 -1
  41. package/src/components/comment-block/CommentBlock.tsx +1 -1
  42. package/src/components/date-picker/DatePicker.test.tsx +3 -5
  43. package/src/components/date-picker/DatePicker.tsx +1 -1
  44. package/src/components/date-picker/DatePickerControlled.test.tsx +6 -8
  45. package/src/components/date-picker/DatePickerField.test.tsx +3 -5
  46. package/src/components/dialog/Dialog.test.tsx +4 -6
  47. package/src/components/divider/Divider.test.tsx +0 -2
  48. package/src/components/divider/Divider.tsx +0 -2
  49. package/src/components/drag-handle/DragHandle.test.tsx +0 -2
  50. package/src/components/drag-handle/DragHandle.tsx +0 -2
  51. package/src/components/dropdown/Dropdown.stories.tsx +1 -1
  52. package/src/components/dropdown/Dropdown.test.tsx +3 -3
  53. package/src/components/dropdown/Dropdown.tsx +1 -1
  54. package/src/components/expansion-panel/ExpansionPanel.test.tsx +6 -7
  55. package/src/components/flag/Flag.test.tsx +0 -2
  56. package/src/components/flag/Flag.tsx +0 -2
  57. package/src/components/flex-box/FlexBox.stories.tsx +0 -2
  58. package/src/components/flex-box/FlexBox.test.tsx +0 -1
  59. package/src/components/flex-box/FlexBox.tsx +1 -1
  60. package/src/components/generic-block/GenericBlock.test.tsx +1 -1
  61. package/src/components/grid/Grid.tsx +0 -2
  62. package/src/components/grid/GridItem.tsx +0 -2
  63. package/src/components/grid-column/GridColumn.stories.tsx +0 -1
  64. package/src/components/grid-column/GridColumn.test.jsx +0 -2
  65. package/src/components/grid-column/GridColumn.tsx +1 -1
  66. package/src/components/heading/Heading.stories.tsx +0 -1
  67. package/src/components/heading/Heading.test.tsx +0 -2
  68. package/src/components/heading/Heading.tsx +0 -2
  69. package/src/components/heading/HeadingLevelProvider.tsx +1 -1
  70. package/src/components/icon/Icon.stories.tsx +30 -4
  71. package/src/components/icon/Icon.test.tsx +85 -4
  72. package/src/components/icon/Icon.tsx +0 -2
  73. package/src/components/image-block/ImageBlock.stories.tsx +0 -2
  74. package/src/components/image-block/ImageBlock.test.tsx +0 -1
  75. package/src/components/image-block/ImageBlock.tsx +1 -1
  76. package/src/components/image-block/ImageCaption.tsx +1 -1
  77. package/src/components/image-lightbox/ImageLightbox.stories.tsx +0 -1
  78. package/src/components/image-lightbox/ImageLightbox.test.tsx +11 -9
  79. package/src/components/image-lightbox/types.ts +0 -2
  80. package/src/components/inline-list/InlineList.stories.tsx +0 -1
  81. package/src/components/inline-list/InlineList.test.tsx +0 -2
  82. package/src/components/inline-list/InlineList.tsx +1 -1
  83. package/src/components/input-helper/InputHelper.test.tsx +0 -2
  84. package/src/components/input-helper/InputHelper.tsx +1 -1
  85. package/src/components/input-label/InputLabel.stories.tsx +0 -2
  86. package/src/components/input-label/InputLabel.test.tsx +0 -2
  87. package/src/components/input-label/InputLabel.tsx +1 -1
  88. package/src/components/lightbox/Lightbox.test.tsx +0 -2
  89. package/src/components/lightbox/Lightbox.tsx +1 -1
  90. package/src/components/link/Link.stories.tsx +0 -1
  91. package/src/components/link/Link.test.tsx +13 -13
  92. package/src/components/link/Link.tsx +9 -22
  93. package/src/components/link-preview/LinkPreview.test.tsx +0 -2
  94. package/src/components/link-preview/LinkPreview.tsx +0 -2
  95. package/src/components/list/List.stories.tsx +1 -1
  96. package/src/components/list/List.test.tsx +0 -2
  97. package/src/components/list/List.tsx +1 -1
  98. package/src/components/list/ListDivider.test.tsx +0 -2
  99. package/src/components/list/ListDivider.tsx +0 -2
  100. package/src/components/list/ListItem.test.tsx +5 -7
  101. package/src/components/list/ListItem.tsx +1 -1
  102. package/src/components/list/ListSubheader.test.tsx +0 -2
  103. package/src/components/list/ListSubheader.tsx +1 -1
  104. package/src/components/message/Message.test.tsx +1 -2
  105. package/src/components/message/Message.tsx +1 -1
  106. package/src/components/mosaic/Mosaic.test.tsx +3 -5
  107. package/src/components/mosaic/Mosaic.tsx +1 -1
  108. package/src/components/navigation/Navigation.stories.tsx +0 -2
  109. package/src/components/navigation/Navigation.test.tsx +0 -2
  110. package/src/components/navigation/Navigation.tsx +0 -2
  111. package/src/components/navigation/NavigationItem.test.tsx +0 -2
  112. package/src/components/navigation/NavigationItem.tsx +7 -11
  113. package/src/components/navigation/NavigationSection.test.tsx +0 -2
  114. package/src/components/navigation/NavigationSection.tsx +5 -4
  115. package/src/components/notification/Notification.test.tsx +4 -5
  116. package/src/components/notification/Notification.tsx +1 -1
  117. package/src/components/popover/Popover.test.tsx +0 -2
  118. package/src/components/popover/Popover.tsx +1 -1
  119. package/src/components/popover/usePopoverStyle.tsx +1 -1
  120. package/src/components/popover-dialog/PopoverDialog.test.tsx +1 -2
  121. package/src/components/popover-dialog/PopoverDialog.tsx +0 -2
  122. package/src/components/post-block/PostBlock.test.tsx +0 -2
  123. package/src/components/post-block/PostBlock.tsx +1 -1
  124. package/src/components/progress/Progress.tsx +0 -2
  125. package/src/components/progress/ProgressCircular.stories.tsx +0 -1
  126. package/src/components/progress/ProgressCircular.test.tsx +0 -2
  127. package/src/components/progress/ProgressCircular.tsx +0 -2
  128. package/src/components/progress/ProgressLinear.test.tsx +0 -2
  129. package/src/components/progress/ProgressLinear.tsx +0 -2
  130. package/src/components/progress-tracker/ProgressTracker.stories.tsx +1 -1
  131. package/src/components/progress-tracker/ProgressTracker.test.tsx +0 -2
  132. package/src/components/progress-tracker/ProgressTrackerProvider.test.tsx +0 -2
  133. package/src/components/progress-tracker/ProgressTrackerProvider.tsx +1 -1
  134. package/src/components/progress-tracker/ProgressTrackerStep.test.tsx +0 -2
  135. package/src/components/progress-tracker/ProgressTrackerStep.tsx +1 -1
  136. package/src/components/progress-tracker/ProgressTrackerStepPanel.test.tsx +0 -2
  137. package/src/components/progress-tracker/ProgressTrackerStepPanel.tsx +0 -2
  138. package/src/components/radio-button/RadioButton.test.tsx +3 -5
  139. package/src/components/radio-button/RadioButton.tsx +1 -1
  140. package/src/components/radio-button/RadioGroup.stories.tsx +1 -1
  141. package/src/components/radio-button/RadioGroup.test.tsx +0 -2
  142. package/src/components/radio-button/RadioGroup.tsx +1 -1
  143. package/src/components/select/Select.stories.tsx +1 -1
  144. package/src/components/select/Select.test.tsx +8 -9
  145. package/src/components/select/Select.tsx +1 -1
  146. package/src/components/select/SelectMultiple.stories.tsx +1 -1
  147. package/src/components/select/SelectMultiple.test.tsx +5 -7
  148. package/src/components/select/SelectMultiple.tsx +1 -1
  149. package/src/components/select/WithSelectContext.tsx +1 -1
  150. package/src/components/select/constants.ts +1 -1
  151. package/src/components/side-navigation/SideNavigation.test.tsx +0 -2
  152. package/src/components/side-navigation/SideNavigation.tsx +1 -1
  153. package/src/components/side-navigation/SideNavigationItem.test.tsx +2 -4
  154. package/src/components/side-navigation/SideNavigationItem.tsx +23 -28
  155. package/src/components/skeleton/SkeletonCircle.test.tsx +0 -2
  156. package/src/components/skeleton/SkeletonCircle.tsx +0 -2
  157. package/src/components/skeleton/SkeletonRectangle.test.tsx +0 -2
  158. package/src/components/skeleton/SkeletonRectangle.tsx +0 -2
  159. package/src/components/skeleton/SkeletonTypography.stories.tsx +0 -2
  160. package/src/components/skeleton/SkeletonTypography.test.tsx +0 -2
  161. package/src/components/skeleton/SkeletonTypography.tsx +1 -1
  162. package/src/components/slider/Slider.test.tsx +1 -3
  163. package/src/components/slider/Slider.tsx +1 -1
  164. package/src/components/slideshow/Slideshow.stories.tsx +0 -1
  165. package/src/components/slideshow/Slideshow.test.tsx +0 -2
  166. package/src/components/slideshow/SlideshowControls.stories.tsx +0 -2
  167. package/src/components/slideshow/SlideshowItem.tsx +0 -2
  168. package/src/components/slideshow/useSlideFocusManagement.tsx +1 -1
  169. package/src/components/switch/Switch.test.tsx +5 -7
  170. package/src/components/switch/Switch.tsx +1 -1
  171. package/src/components/table/Table.test.tsx +0 -2
  172. package/src/components/table/Table.tsx +0 -2
  173. package/src/components/table/TableBody.test.tsx +0 -2
  174. package/src/components/table/TableBody.tsx +0 -2
  175. package/src/components/table/TableCell.test.tsx +1 -3
  176. package/src/components/table/TableCell.tsx +0 -2
  177. package/src/components/table/TableHeader.test.tsx +0 -2
  178. package/src/components/table/TableHeader.tsx +0 -2
  179. package/src/components/table/TableRow.test.tsx +0 -2
  180. package/src/components/table/TableRow.tsx +0 -2
  181. package/src/components/tabs/Tab.test.tsx +0 -2
  182. package/src/components/tabs/Tab.tsx +1 -1
  183. package/src/components/tabs/TabList.test.tsx +0 -2
  184. package/src/components/tabs/TabPanel.test.tsx +0 -2
  185. package/src/components/tabs/TabPanel.tsx +0 -2
  186. package/src/components/tabs/TabProvider.test.tsx +0 -2
  187. package/src/components/tabs/TabProvider.tsx +1 -1
  188. package/src/components/tabs/Tabs.stories.tsx +1 -1
  189. package/src/components/text/Text.stories.tsx +1 -1
  190. package/src/components/text/Text.test.tsx +0 -2
  191. package/src/components/text/Text.tsx +0 -2
  192. package/src/components/text-field/TextField.test.tsx +9 -10
  193. package/src/components/text-field/TextField.tsx +1 -1
  194. package/src/components/thumbnail/Thumbnail.test.tsx +29 -7
  195. package/src/components/thumbnail/Thumbnail.tsx +11 -11
  196. package/src/components/toolbar/Toolbar.tsx +1 -1
  197. package/src/components/tooltip/Tooltip.stories.tsx +2 -1
  198. package/src/components/tooltip/Tooltip.test.tsx +14 -8
  199. package/src/components/uploader/Uploader.test.tsx +2 -4
  200. package/src/components/user-block/UserBlock.stories.tsx +0 -2
  201. package/src/components/user-block/UserBlock.test.tsx +1 -3
  202. package/src/hooks/useId.test.tsx +0 -1
  203. package/src/hooks/useInfiniteScroll.tsx +1 -1
  204. package/src/hooks/usePreviousValue.ts +0 -1
  205. package/src/stories/decorators/withChromaticForceScreenSize.tsx +0 -1
  206. package/src/stories/decorators/withNestedProps.tsx +0 -1
  207. package/src/stories/decorators/withThemedBackground.tsx +0 -2
  208. package/src/stories/decorators/withWrapper.tsx +0 -2
  209. package/src/stories/utils/CustomLink.tsx +0 -1
  210. package/src/testing/utils/ThemeSentinel.tsx +0 -1
  211. package/src/untypped-modules.d.ts +4 -0
  212. package/src/utils/ClickAwayProvider/ClickAwayProvider.stories.jsx +1 -1
  213. package/src/utils/ClickAwayProvider/ClickAwayProvider.tsx +1 -1
  214. package/src/utils/MaterialThemeSwitcher/MaterialThemeSwitcher.tsx +1 -1
  215. package/src/utils/Portal/Portal.test.tsx +0 -1
  216. package/src/utils/Portal/PortalProvider.stories.jsx +0 -1
  217. package/src/utils/Portal/PortalProvider.test.tsx +1 -2
  218. package/src/utils/date/getYearDisplayName.test.ts +1 -1
  219. package/src/utils/disabled/DisabledStateProvider.stories.tsx +0 -2
  220. package/src/utils/disabled/useDisableStateProps.test.tsx +2 -2
  221. package/src/utils/react/OnBeforeUnmount.tsx +1 -1
  222. package/src/utils/react/RawClickable.test.tsx +153 -0
  223. package/src/utils/react/RawClickable.tsx +65 -0
  224. package/src/utils/react/skipRender.tsx +2 -2
  225. package/src/utils/react/wrapChildrenIconWithSpaces.test.tsx +1 -1
  226. package/src/utils/type/HasPolymorphicAs.ts +0 -2
  227. package/src/utils/type/HasRequiredLinkHref.ts +1 -0
  228. package/src/utils/type/index.ts +1 -0
  229. package/utils/index.d.ts +6 -6
  230. package/src/utils/react/renderButtonOrLink.tsx +0 -16
@@ -1,4 +1,4 @@
1
- import React, { Children, isValidElement } from 'react';
1
+ import { Children, isValidElement } from 'react';
2
2
 
3
3
  import classNames from 'classnames';
4
4
 
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { Kind, Theme } from '@lumx/react';
4
2
  import { commonTestsSuiteRTL, SetupRenderOptions } from '@lumx/react/testing/utils';
5
3
  import { getByClassName } from '@lumx/react/testing/utils/queries';
@@ -1,4 +1,4 @@
1
- import React, { ReactNode } from 'react';
1
+ import { ReactNode } from 'react';
2
2
 
3
3
  import classNames from 'classnames';
4
4
 
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { Typography } from '@lumx/react';
4
2
 
5
3
  import { InputLabel } from './InputLabel';
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { Theme, Typography } from '@lumx/react';
4
2
  import { getByClassName } from '@lumx/react/testing/utils/queries';
5
3
  import { getTypographyClassName } from '@lumx/core/js/utils/className';
@@ -1,4 +1,4 @@
1
- import React, { ReactNode } from 'react';
1
+ import { ReactNode } from 'react';
2
2
 
3
3
  import classNames from 'classnames';
4
4
 
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { commonTestsSuiteRTL, SetupRenderOptions } from '@lumx/react/testing/utils';
4
2
  import { queryByClassName } from '@lumx/react/testing/utils/queries';
5
3
  import { render, screen } from '@testing-library/react';
@@ -1,4 +1,4 @@
1
- import React, { RefObject, useRef, useEffect, AriaAttributes } from 'react';
1
+ import { RefObject, useRef, useEffect, AriaAttributes } from 'react';
2
2
 
3
3
  import classNames from 'classnames';
4
4
 
@@ -10,7 +10,6 @@ import {
10
10
  TypographyTitleCustom,
11
11
  GenericBlock,
12
12
  } from '@lumx/react';
13
- import React from 'react';
14
13
  import { getSelectArgType } from '@lumx/react/stories/controls/selectArgType';
15
14
  import { colorArgType, colorVariantArgType } from '@lumx/react/stories/controls/color';
16
15
  import { iconArgType } from '@lumx/react/stories/controls/icons';
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { ColorPalette, ColorVariant, Icon, Typography } from '@lumx/react';
4
2
  import { commonTestsSuiteRTL } from '@lumx/react/testing/utils';
5
3
  import { getByClassName, queryAllByClassName, queryByClassName } from '@lumx/react/testing/utils/queries';
@@ -51,7 +49,7 @@ describe(`<${Link.displayName}>`, () => {
51
49
 
52
50
  it('should render a button', () => {
53
51
  const name = 'Link';
54
- const onClick = jest.fn();
52
+ const onClick = vi.fn();
55
53
  const { link } = setup({ onClick, children: name });
56
54
  expect(link).toBe(screen.queryByRole('button', { name }));
57
55
  });
@@ -75,7 +73,7 @@ describe(`<${Link.displayName}>`, () => {
75
73
 
76
74
  describe('Disabled state', () => {
77
75
  it('should render disabled button', async () => {
78
- const onClick = jest.fn();
76
+ const onClick = vi.fn();
79
77
  const { link } = setup({ children: 'Label', isDisabled: true, onClick });
80
78
  expect(link).toHaveAttribute('disabled');
81
79
  await userEvent.click(link);
@@ -83,25 +81,28 @@ describe(`<${Link.displayName}>`, () => {
83
81
  });
84
82
 
85
83
  it('should render disabled link', async () => {
86
- const onClick = jest.fn();
84
+ const onClick = vi.fn();
87
85
  const { link } = setup({ children: 'Label', isDisabled: true, href: 'https://example.com', onClick });
88
- // Disabled link do not exist so we fallback to a button
89
- expect(screen.queryByRole('link')).not.toBeInTheDocument();
90
- expect(link).toHaveAttribute('disabled');
86
+ expect(screen.queryByRole('link')).toBeInTheDocument();
87
+ expect(link).toHaveAttribute('aria-disabled');
88
+ // Simulate standard disabled state (not focusable)
89
+ expect(link).toHaveAttribute('tabindex', '-1');
91
90
  await userEvent.click(link);
92
91
  expect(onClick).not.toHaveBeenCalled();
93
92
  });
94
93
 
95
94
  it('should render aria-disabled button', async () => {
96
- const onClick = jest.fn();
95
+ const onClick = vi.fn();
97
96
  const { link } = setup({ children: 'Label', 'aria-disabled': true, onClick });
98
- expect(link).toHaveAttribute('aria-disabled');
97
+ expect(screen.queryByRole('button')).toBeInTheDocument();
98
+ expect(link).toHaveAttribute('aria-disabled', 'true');
99
+ expect(link).not.toHaveAttribute('tabindex');
99
100
  await userEvent.click(link);
100
101
  expect(onClick).not.toHaveBeenCalled();
101
102
  });
102
103
 
103
104
  it('should render aria-disabled link', async () => {
104
- const onClick = jest.fn();
105
+ const onClick = vi.fn();
105
106
  const { link } = setup({
106
107
  children: 'Label',
107
108
  'aria-disabled': true,
@@ -109,8 +110,7 @@ describe(`<${Link.displayName}>`, () => {
109
110
  onClick,
110
111
  });
111
112
  expect(link).toHaveAccessibleName('Label');
112
- // Disabled link do not exist so we fallback to a button
113
- expect(screen.queryByRole('link')).not.toBeInTheDocument();
113
+ expect(screen.queryByRole('link')).toBeInTheDocument();
114
114
  expect(link).toHaveAttribute('aria-disabled', 'true');
115
115
  await userEvent.click(link);
116
116
  expect(onClick).not.toHaveBeenCalled();
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import classNames from 'classnames';
4
2
 
5
3
  import { ColorVariant, ColorWithVariants, Icon, Typography } from '@lumx/react';
@@ -12,8 +10,9 @@ import {
12
10
  } from '@lumx/core/js/utils/className';
13
11
  import { forwardRef } from '@lumx/react/utils/react/forwardRef';
14
12
  import { wrapChildrenIconWithSpaces } from '@lumx/react/utils/react/wrapChildrenIconWithSpaces';
15
- import { useDisableStateProps } from '@lumx/react/utils/disabled/useDisableStateProps';
16
13
  import { HasAriaDisabled } from '@lumx/react/utils/type/HasAriaDisabled';
14
+ import { RawClickable } from '@lumx/react/utils/react/RawClickable';
15
+ import { useDisableStateProps } from '@lumx/react/utils/disabled';
17
16
 
18
17
  type HTMLAnchorProps = React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>;
19
18
 
@@ -67,38 +66,26 @@ const CLASSNAME = getRootClassName(COMPONENT_NAME);
67
66
  * @return React element.
68
67
  */
69
68
  export const Link = forwardRef<LinkProps, HTMLAnchorElement | HTMLButtonElement>((props, ref) => {
70
- const { isAnyDisabled, disabledStateProps, otherProps } = useDisableStateProps(props);
69
+ const { disabledStateProps, otherProps } = useDisableStateProps(props);
71
70
  const {
72
71
  children,
73
72
  className,
74
73
  color: propColor,
75
74
  colorVariant: propColorVariant,
76
- href,
77
75
  leftIcon,
78
- linkAs,
79
76
  rightIcon,
80
- target,
81
77
  typography,
78
+ linkAs,
82
79
  ...forwardedProps
83
80
  } = otherProps;
84
81
  const [color, colorVariant] = resolveColorWithVariants(propColor, propColorVariant);
85
82
 
86
- const isLink = linkAs || href;
87
- const Component = isLink && !isAnyDisabled ? linkAs || 'a' : 'button';
88
- const baseProps: React.ComponentProps<typeof Component> = {};
89
- if (Component === 'button') {
90
- baseProps.type = 'button';
91
- Object.assign(baseProps, disabledStateProps);
92
- } else if (isLink) {
93
- baseProps.href = href;
94
- baseProps.target = target;
95
- }
96
-
97
83
  return (
98
- <Component
99
- ref={ref}
84
+ <RawClickable
85
+ ref={ref as any}
86
+ as={linkAs || (forwardedProps.href ? 'a' : 'button')}
100
87
  {...forwardedProps}
101
- {...baseProps}
88
+ {...disabledStateProps}
102
89
  className={classNames(
103
90
  className,
104
91
  handleBasicClasses({ prefix: CLASSNAME, color, colorVariant, hasTypography: !!typography }),
@@ -112,7 +99,7 @@ export const Link = forwardRef<LinkProps, HTMLAnchorElement | HTMLButtonElement>
112
99
  {rightIcon && <Icon icon={rightIcon} className={`${CLASSNAME}__right-icon`} />}
113
100
  </>,
114
101
  )}
115
- </Component>
102
+ </RawClickable>
116
103
  );
117
104
  });
118
105
  Link.displayName = COMPONENT_NAME;
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { commonTestsSuiteRTL, SetupRenderOptions } from '@lumx/react/testing/utils';
4
2
  import { Size, Theme } from '@lumx/core/js/constants';
5
3
  import { Thumbnail } from '@lumx/react';
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import classNames from 'classnames';
4
2
 
5
3
  import {
@@ -1,4 +1,4 @@
1
- import React, { useRef } from 'react';
1
+ import { useRef } from 'react';
2
2
 
3
3
  import { mdiAccount, mdiOpenInNew } from '@lumx/icons';
4
4
  import { Icon, ListDivider, ListProps, ListSubheader, Size } from '@lumx/react';
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { commonTestsSuiteRTL } from '@lumx/react/testing/utils';
4
2
 
5
3
  import { render } from '@testing-library/react';
@@ -1,4 +1,4 @@
1
- import React, { Key, ReactNode, SyntheticEvent, useRef } from 'react';
1
+ import { Key, ReactNode, SyntheticEvent, useRef } from 'react';
2
2
 
3
3
  import classNames from 'classnames';
4
4
 
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { commonTestsSuiteRTL } from '@lumx/react/testing/utils';
4
2
 
5
3
  import { queryByClassName } from '@lumx/react/testing/utils/queries';
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import classNames from 'classnames';
4
2
 
5
3
  import { GenericProps } from '@lumx/react/utils/type';
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { commonTestsSuiteRTL, SetupRenderOptions } from '@lumx/react/testing/utils';
4
2
  import { render, screen } from '@testing-library/react';
5
3
  import { getByClassName, queryByClassName } from '@lumx/react/testing/utils/queries';
@@ -29,7 +27,7 @@ describe(`<${ListItem.displayName}>`, () => {
29
27
  });
30
28
 
31
29
  it('should render as a button', () => {
32
- setup({ children: 'Label', onItemSelected: jest.fn() });
30
+ setup({ children: 'Label', onItemSelected: vi.fn() });
33
31
  expect(screen.getByRole('button', { name: 'Label' })).toBeInTheDocument();
34
32
  });
35
33
 
@@ -41,7 +39,7 @@ describe(`<${ListItem.displayName}>`, () => {
41
39
 
42
40
  describe('Disabled state', () => {
43
41
  it('should render disabled list item button', async () => {
44
- const onItemSelected = jest.fn();
42
+ const onItemSelected = vi.fn();
45
43
  const { link } = setup({ children: 'Label', isDisabled: true, onItemSelected });
46
44
  expect(link).toHaveAttribute('aria-disabled', 'true');
47
45
  // The `renderLink` util removes the onClick handler but `user-event` will also not fire events on disabled elements.
@@ -50,7 +48,7 @@ describe(`<${ListItem.displayName}>`, () => {
50
48
  });
51
49
 
52
50
  it('should render disabled list item link', async () => {
53
- const onItemSelected = jest.fn();
51
+ const onItemSelected = vi.fn();
54
52
  const { link } = setup({
55
53
  children: 'Label',
56
54
  isDisabled: true,
@@ -64,7 +62,7 @@ describe(`<${ListItem.displayName}>`, () => {
64
62
  });
65
63
 
66
64
  it('should render aria-disabled list item button', async () => {
67
- const onItemSelected = jest.fn();
65
+ const onItemSelected = vi.fn();
68
66
  const { link } = setup({ children: 'Label', 'aria-disabled': true, onItemSelected });
69
67
  expect(link).toHaveAttribute('aria-disabled', 'true');
70
68
  if (link) await userEvent.click(link);
@@ -72,7 +70,7 @@ describe(`<${ListItem.displayName}>`, () => {
72
70
  });
73
71
 
74
72
  it('should render aria-disabled list item link', async () => {
75
- const onItemSelected = jest.fn();
73
+ const onItemSelected = vi.fn();
76
74
  const { link } = setup({
77
75
  children: 'Label',
78
76
  'aria-disabled': true,
@@ -1,4 +1,4 @@
1
- import React, { ReactNode, Ref, SyntheticEvent, useMemo } from 'react';
1
+ import { ReactNode, Ref, SyntheticEvent, useMemo } from 'react';
2
2
 
3
3
  import classNames from 'classnames';
4
4
  import isEmpty from 'lodash/isEmpty';
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { commonTestsSuiteRTL } from '@lumx/react/testing/utils';
4
2
  import { render } from '@testing-library/react';
5
3
  import { queryByClassName } from '@lumx/react/testing/utils/queries';
@@ -1,4 +1,4 @@
1
- import React, { ReactNode } from 'react';
1
+ import { ReactNode } from 'react';
2
2
 
3
3
  import classNames from 'classnames';
4
4
 
@@ -1,7 +1,6 @@
1
1
  import { commonTestsSuiteRTL } from '@lumx/react/testing/utils';
2
2
  import { Kind } from '@lumx/react';
3
3
 
4
- import React from 'react';
5
4
  import { queryByRole, render } from '@testing-library/react';
6
5
  import { getByClassName, queryByClassName } from '@lumx/react/testing/utils/queries';
7
6
  import { mdiAbTesting } from '@lumx/icons';
@@ -54,7 +53,7 @@ describe(`<${Message.displayName}>`, () => {
54
53
  });
55
54
 
56
55
  it('should render close button', async () => {
57
- const onClick = jest.fn();
56
+ const onClick = vi.fn();
58
57
  const { closeButton } = setup({
59
58
  hasBackground: true,
60
59
  kind: 'info',
@@ -1,4 +1,4 @@
1
- import React, { ReactNode } from 'react';
1
+ import { ReactNode } from 'react';
2
2
 
3
3
  import classNames from 'classnames';
4
4
 
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { Mosaic, MosaicProps } from '@lumx/react/components/mosaic/Mosaic';
4
2
  import { render, screen, within } from '@testing-library/react';
5
3
  import { getByClassName, queryAllByClassName, queryByClassName } from '@lumx/react/testing/utils/queries';
@@ -32,7 +30,7 @@ describe(`<${Mosaic.displayName}>`, () => {
32
30
  expect(mosaic).toHaveClass(`${CLASSNAME}--has-${count}-thumbnail${count > 1 ? 's' : ''}`);
33
31
  expect(thumbnails.length).toBe(count);
34
32
  for (const thumbnail of thumbnails) {
35
- expect(within(thumbnail).queryByRole('img')).toBeInTheDocument();
33
+ expect(within(thumbnail).queryByAltText('')).toBeInTheDocument();
36
34
  }
37
35
  });
38
36
 
@@ -47,8 +45,8 @@ describe(`<${Mosaic.displayName}>`, () => {
47
45
  });
48
46
 
49
47
  it('should render clickable', async () => {
50
- const onClick = jest.fn();
51
- const onImageClick = jest.fn();
48
+ const onClick = vi.fn();
49
+ const onImageClick = vi.fn();
52
50
  const { thumbnails } = setup({
53
51
  thumbnails: generateThumbnails(6),
54
52
  onImageClick,
@@ -1,4 +1,4 @@
1
- import React, { MouseEventHandler, useMemo } from 'react';
1
+ import { MouseEventHandler, useMemo } from 'react';
2
2
 
3
3
  import classNames from 'classnames';
4
4
  import take from 'lodash/take';
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import {
4
2
  mdiHome,
5
3
  mdiMessageTextOutline,
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { commonTestsSuiteRTL, SetupRenderOptions } from '@lumx/react/testing/utils';
4
2
  import { render } from '@testing-library/react';
5
3
  import { getAllByClassName, getByClassName } from '@lumx/react/testing/utils/queries';
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import classNames from 'classnames';
4
2
 
5
3
  import { HasAriaLabelOrLabelledBy, HasClassName, HasTheme } from '@lumx/react/utils/type';
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { commonTestsSuiteRTL } from '@lumx/react/testing/utils';
4
2
  import { render } from '@testing-library/react';
5
3
  import { getByClassName } from '@lumx/react/testing/utils/queries';
@@ -1,11 +1,12 @@
1
- import React, { ElementType, ReactNode } from 'react';
1
+ import { ElementType, ReactNode } from 'react';
2
2
  import { Icon, Placement, Size, Tooltip, Text } from '@lumx/react';
3
3
  import { getRootClassName, handleBasicClasses } from '@lumx/core/js/utils/className';
4
- import { ComponentRef, HasClassName, HasPolymorphicAs, HasTheme } from '@lumx/react/utils/type';
4
+ import { ComponentRef, HasClassName, HasPolymorphicAs, HasRequiredLinkHref, HasTheme } from '@lumx/react/utils/type';
5
5
  import classNames from 'classnames';
6
6
  import { forwardRefPolymorphic } from '@lumx/react/utils/react/forwardRefPolymorphic';
7
7
  import { useTheme } from '@lumx/react/utils/theme/ThemeContext';
8
8
  import { useOverflowTooltipLabel } from '@lumx/react/hooks/useOverflowTooltipLabel';
9
+ import { RawClickable } from '@lumx/react/utils/react/RawClickable';
9
10
 
10
11
  type BaseNavigationItemProps = {
11
12
  /** Icon (SVG path). */
@@ -16,9 +17,6 @@ type BaseNavigationItemProps = {
16
17
  isCurrentPage?: boolean;
17
18
  };
18
19
 
19
- /** Make `href` required when `as` is `a` */
20
- type RequiredLinkHref<E> = E extends 'a' ? { href: string } : Record<string, unknown>;
21
-
22
20
  /**
23
21
  * Navigation item props
24
22
  */
@@ -26,7 +24,7 @@ export type NavigationItemProps<E extends ElementType = 'a'> = HasPolymorphicAs<
26
24
  HasTheme &
27
25
  HasClassName &
28
26
  BaseNavigationItemProps &
29
- RequiredLinkHref<E>;
27
+ HasRequiredLinkHref<E>;
30
28
 
31
29
  /**
32
30
  * Component display name.
@@ -44,8 +42,6 @@ export const NavigationItem = Object.assign(
44
42
  const theme = useTheme();
45
43
  const { tooltipLabel, labelRef } = useOverflowTooltipLabel(label);
46
44
 
47
- const buttonProps = Element === 'button' ? { type: 'button' } : {};
48
-
49
45
  return (
50
46
  <li
51
47
  className={classNames(
@@ -57,14 +53,14 @@ export const NavigationItem = Object.assign(
57
53
  )}
58
54
  >
59
55
  <Tooltip label={tooltipLabel} placement={Placement.TOP}>
60
- <Element
56
+ <RawClickable
57
+ as={Element}
61
58
  className={handleBasicClasses({
62
59
  prefix: `${CLASSNAME}__link`,
63
60
  isSelected: isCurrentPage,
64
61
  })}
65
62
  ref={ref as React.Ref<any>}
66
63
  aria-current={isCurrentPage ? 'page' : undefined}
67
- {...buttonProps}
68
64
  {...forwardedProps}
69
65
  >
70
66
  {icon ? (
@@ -74,7 +70,7 @@ export const NavigationItem = Object.assign(
74
70
  <Text as="span" truncate className={`${CLASSNAME}__label`} ref={labelRef}>
75
71
  {label}
76
72
  </Text>
77
- </Element>
73
+ </RawClickable>
78
74
  </Tooltip>
79
75
  </li>
80
76
  );
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { commonTestsSuiteRTL, RenderWrapper } from '@lumx/react/testing/utils';
4
2
  import { render, screen } from '@testing-library/react';
5
3
  import { getByClassName, queryByClassName } from '@lumx/react/testing/utils/queries';
@@ -1,4 +1,4 @@
1
- import React, { useRef, useState, useContext } from 'react';
1
+ import { useRef, useState, useContext } from 'react';
2
2
 
3
3
  import { mdiChevronDown, mdiChevronUp } from '@lumx/icons';
4
4
  import { Icon, Size, Text, Orientation, Popover, Placement, Theme } from '@lumx/react';
@@ -9,6 +9,7 @@ import { ThemeProvider, useTheme } from '@lumx/react/utils/theme/ThemeContext';
9
9
  import { useId } from '@lumx/react/hooks/useId';
10
10
  import { forwardRef } from '@lumx/react/utils/react/forwardRef';
11
11
 
12
+ import { RawClickable } from '@lumx/react/utils/react/RawClickable';
12
13
  import { CLASSNAME as ITEM_CLASSNAME } from './NavigationItem';
13
14
  import { NavigationContext } from './context';
14
15
 
@@ -52,7 +53,8 @@ export const NavigationSection = forwardRef<NavigationSectionProps, HTMLLIElemen
52
53
  )}
53
54
  ref={ref}
54
55
  >
55
- <button
56
+ <RawClickable<'button'>
57
+ as="button"
56
58
  {...forwardedProps}
57
59
  aria-controls={sectionId}
58
60
  aria-expanded={isOpen}
@@ -62,7 +64,6 @@ export const NavigationSection = forwardRef<NavigationSectionProps, HTMLLIElemen
62
64
  setIsOpen(!isOpen);
63
65
  event.stopPropagation();
64
66
  }}
65
- type="button"
66
67
  >
67
68
  {icon ? <Icon className={`${ITEM_CLASSNAME}__icon`} icon={icon} size={Size.xs} /> : null}
68
69
 
@@ -73,7 +74,7 @@ export const NavigationSection = forwardRef<NavigationSectionProps, HTMLLIElemen
73
74
  className={classNames(`${ITEM_CLASSNAME}__icon`, `${CLASSNAME}__chevron`)}
74
75
  icon={isOpen ? mdiChevronUp : mdiChevronDown}
75
76
  />
76
- </button>
77
+ </RawClickable>
77
78
  {isOpen &&
78
79
  (isDropdown ? (
79
80
  <Popover
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { Kind } from '@lumx/react';
4
2
  import { render, within, screen } from '@testing-library/react';
5
3
  import { queryByClassName } from '@lumx/react/testing/utils/queries';
@@ -44,8 +42,8 @@ describe(`<${Notification.displayName}>`, () => {
44
42
  });
45
43
 
46
44
  it('should render content & action', async () => {
47
- const onClick = jest.fn();
48
- const onActionClick = jest.fn();
45
+ const onClick = vi.fn();
46
+ const onActionClick = vi.fn();
49
47
  const content = 'Content';
50
48
  const actionLabel = 'actionLabel';
51
49
  const { notification, action, actionButton } = setup({ content, actionLabel, onClick, onActionClick });
@@ -81,8 +79,9 @@ describe(`<${Notification.displayName}>`, () => {
81
79
 
82
80
  it('should forward styles', () => {
83
81
  const { notification } = setup({ style: { color: 'red' } });
82
+
84
83
  expect(notification).toBeInTheDocument();
85
- expect(notification).toHaveStyle('color: red');
84
+ expect(notification).toHaveStyle('color: rgb(255, 0, 0)');
86
85
  });
87
86
 
88
87
  // Common tests suite.
@@ -1,4 +1,4 @@
1
- import React, { useRef } from 'react';
1
+ import { useRef } from 'react';
2
2
 
3
3
  import classNames from 'classnames';
4
4
  import isFunction from 'lodash/isFunction';
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { commonTestsSuiteRTL, SetupRenderOptions } from '@lumx/react/testing/utils';
4
2
  import { render, screen } from '@testing-library/react';
5
3
  import { ThemeSentinel } from '@lumx/react/testing/utils/ThemeSentinel';
@@ -1,4 +1,4 @@
1
- import React, { ReactNode, RefObject, useRef } from 'react';
1
+ import { ReactNode, RefObject, useRef } from 'react';
2
2
 
3
3
  import classNames from 'classnames';
4
4
 
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useMemo, useState } from 'react';
1
+ import { useEffect, useMemo, useState } from 'react';
2
2
  import memoize from 'lodash/memoize';
3
3
  import { detectOverflow } from '@popperjs/core';
4
4
 
@@ -1,4 +1,3 @@
1
- import React from 'react';
2
1
  import { render, screen, within } from '@testing-library/react';
3
2
  import userEvent from '@testing-library/user-event';
4
3
 
@@ -6,7 +5,7 @@ import { Heading, HeadingLevelProvider } from '@lumx/react';
6
5
  import { WithButtonTrigger, WithIconButtonTrigger } from './PopoverDialog.stories';
7
6
  import { PopoverDialog } from './PopoverDialog';
8
7
 
9
- jest.mock('@lumx/react/utils/browser/isFocusVisible');
8
+ vi.mock('@lumx/react/utils/browser/isFocusVisible');
10
9
 
11
10
  describe(`<${PopoverDialog.displayName}>`, () => {
12
11
  it('should open and init focus', async () => {
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import classNames from 'classnames';
4
2
 
5
3
  import { HasAriaLabelOrLabelledBy } from '@lumx/react/utils/type';
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import { commonTestsSuiteRTL, SetupRenderOptions } from '@lumx/react/testing/utils';
4
2
  import { render } from '@testing-library/react';
5
3
  import { queryByClassName } from '@lumx/react/testing/utils/queries';
@@ -1,4 +1,4 @@
1
- import React, { ReactNode } from 'react';
1
+ import { ReactNode } from 'react';
2
2
 
3
3
  import classNames from 'classnames';
4
4
  import isObject from 'lodash/isObject';
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  import classNames from 'classnames';
4
2
 
5
3
  import { Theme } from '@lumx/react';
@@ -1,4 +1,3 @@
1
- import React from 'react';
2
1
  import { ProgressCircular, ProgressCircularSize, Size, Text } from '@lumx/react';
3
2
  import { getSelectArgType } from '@lumx/react/stories/controls/selectArgType';
4
3
  import { withCombinations } from '@lumx/react/stories/decorators/withCombinations';