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

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