@lumx/react 3.19.1-alpha.7 → 3.19.1-alpha.9

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 (56) hide show
  1. package/_internal/index.js +20 -13
  2. package/_internal/index.js.map +1 -1
  3. package/index.d.ts +5 -6
  4. package/index.js +2400 -2440
  5. package/index.js.map +1 -1
  6. package/package.json +10 -13
  7. package/src/components/alert-dialog/AlertDialog.test.tsx +3 -2
  8. package/src/components/autocomplete/Autocomplete.test.tsx +3 -3
  9. package/src/components/button/Button.test.tsx +9 -9
  10. package/src/components/button/ButtonRoot.tsx +6 -36
  11. package/src/components/checkbox/Checkbox.test.tsx +3 -3
  12. package/src/components/chip/Chip.test.tsx +19 -17
  13. package/src/components/date-picker/DatePicker.test.tsx +3 -3
  14. package/src/components/date-picker/DatePickerControlled.test.tsx +6 -6
  15. package/src/components/date-picker/DatePickerField.test.tsx +3 -3
  16. package/src/components/dialog/Dialog.test.tsx +4 -4
  17. package/src/components/dropdown/Dropdown.test.tsx +3 -3
  18. package/src/components/expansion-panel/ExpansionPanel.test.tsx +6 -5
  19. package/src/components/icon/Icon.stories.tsx +30 -4
  20. package/src/components/icon/Icon.test.tsx +85 -2
  21. package/src/components/icon/Icon.tsx +118 -7
  22. package/src/components/image-lightbox/ImageLightbox.test.tsx +11 -7
  23. package/src/components/link/Link.test.tsx +13 -11
  24. package/src/components/link/Link.tsx +9 -20
  25. package/src/components/list/ListItem.test.tsx +5 -5
  26. package/src/components/message/Message.test.tsx +1 -1
  27. package/src/components/mosaic/Mosaic.test.tsx +3 -3
  28. package/src/components/navigation/NavigationItem.tsx +6 -10
  29. package/src/components/navigation/NavigationSection.tsx +4 -3
  30. package/src/components/notification/Notification.test.tsx +4 -3
  31. package/src/components/popover-dialog/PopoverDialog.test.tsx +1 -1
  32. package/src/components/radio-button/RadioButton.test.tsx +3 -3
  33. package/src/components/select/Select.test.tsx +8 -7
  34. package/src/components/select/SelectMultiple.test.tsx +5 -5
  35. package/src/components/side-navigation/SideNavigationItem.test.tsx +2 -2
  36. package/src/components/side-navigation/SideNavigationItem.tsx +22 -27
  37. package/src/components/slider/Slider.test.tsx +1 -1
  38. package/src/components/switch/Switch.test.tsx +5 -5
  39. package/src/components/table/TableCell.test.tsx +1 -1
  40. package/src/components/text-field/TextField.test.tsx +9 -8
  41. package/src/components/thumbnail/Thumbnail.test.tsx +29 -5
  42. package/src/components/thumbnail/Thumbnail.tsx +11 -11
  43. package/src/components/tooltip/Tooltip.test.tsx +14 -8
  44. package/src/components/uploader/Uploader.test.tsx +2 -2
  45. package/src/components/user-block/UserBlock.test.tsx +1 -1
  46. package/src/untypped-modules.d.ts +4 -0
  47. package/src/utils/Portal/PortalProvider.test.tsx +1 -1
  48. package/src/utils/date/getYearDisplayName.test.ts +1 -1
  49. package/src/utils/disabled/useDisableStateProps.test.tsx +2 -2
  50. package/src/utils/react/RawClickable.test.tsx +153 -0
  51. package/src/utils/react/RawClickable.tsx +65 -0
  52. package/src/utils/type/HasRequiredLinkHref.ts +1 -0
  53. package/src/utils/type/index.ts +1 -0
  54. package/utils/index.d.ts +1 -1
  55. package/utils/index.js +1 -1
  56. package/src/utils/react/renderButtonOrLink.tsx +0 -16
@@ -1,3 +1,4 @@
1
+ import { Mock } from 'vitest';
1
2
  import React from 'react';
2
3
 
3
4
  import { Theme } from '@lumx/core/js/constants';
@@ -13,8 +14,8 @@ import { Select, SelectProps, SelectVariant } from './Select';
13
14
 
14
15
  const CLASSNAME = Select.className as string;
15
16
 
16
- jest.mock('@lumx/react/utils/browser/isFocusVisible');
17
- jest.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
17
+ vi.mock('@lumx/react/utils/browser/isFocusVisible');
18
+ vi.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
18
19
 
19
20
  /**
20
21
  * Mounts the component and returns common DOM elements / data needed in multiple tests further down.
@@ -35,7 +36,7 @@ const setup = (propsOverride: Partial<SelectProps> = {}, { wrapper }: SetupRende
35
36
  };
36
37
 
37
38
  describe(`<${Select.displayName}>`, () => {
38
- (isFocusVisible as jest.Mock).mockReturnValue(false);
39
+ (isFocusVisible as Mock).mockReturnValue(false);
39
40
 
40
41
  describe('Props', () => {
41
42
  it('should have default classNames', () => {
@@ -144,7 +145,7 @@ describe(`<${Select.displayName}>`, () => {
144
145
 
145
146
  describe('Events', () => {
146
147
  it('should trigger `onDropdownClose` on escape', async () => {
147
- const onDropdownClose = jest.fn();
148
+ const onDropdownClose = vi.fn();
148
149
  const { getDropdown } = setup({ isOpen: true, onDropdownClose });
149
150
 
150
151
  const dropdown = getDropdown();
@@ -156,7 +157,7 @@ describe(`<${Select.displayName}>`, () => {
156
157
 
157
158
  describe('should trigger `onInputClick` when the select button is clicked', () => {
158
159
  it('with input variant', async () => {
159
- const onClick = jest.fn();
160
+ const onClick = vi.fn();
160
161
  const { inputWrapper } = setup({ onInputClick: onClick, variant: SelectVariant.input });
161
162
 
162
163
  await userEvent.click(inputWrapper as any);
@@ -164,7 +165,7 @@ describe(`<${Select.displayName}>`, () => {
164
165
  });
165
166
 
166
167
  it('with chip variant', async () => {
167
- const onClick = jest.fn();
168
+ const onClick = vi.fn();
168
169
  const { chip } = setup({ onInputClick: onClick, variant: SelectVariant.chip });
169
170
 
170
171
  await userEvent.click(chip as any);
@@ -174,7 +175,7 @@ describe(`<${Select.displayName}>`, () => {
174
175
 
175
176
  it('should call onClear when clear icon is clicked in select input', async () => {
176
177
  const value = 'Value';
177
- const onClear = jest.fn();
178
+ const onClear = vi.fn();
178
179
  const { select, props } = setup({ value, onClear, clearButtonProps: { label: 'Clear' } });
179
180
 
180
181
  const clearButton = within(select).getByRole('button', { name: props.clearButtonProps?.label });
@@ -18,7 +18,7 @@ import { SelectVariant } from './constants';
18
18
 
19
19
  const CLASSNAME = SelectMultiple.className as string;
20
20
 
21
- jest.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
21
+ vi.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
22
22
 
23
23
  /**
24
24
  * Mounts the component and returns common DOM elements / data needed in multiple tests further down.
@@ -144,7 +144,7 @@ describe('<SelectMultiple>', () => {
144
144
  describe('Events', () => {
145
145
  describe('should trigger `onInputClick` when the select button is clicked', () => {
146
146
  it('with input variant', async () => {
147
- const onClick = jest.fn();
147
+ const onClick = vi.fn();
148
148
  const { inputWrapper } = setup({ onInputClick: onClick, variant: SelectVariant.input });
149
149
 
150
150
  await userEvent.click(inputWrapper as any);
@@ -152,7 +152,7 @@ describe('<SelectMultiple>', () => {
152
152
  });
153
153
 
154
154
  it('with chip variant', async () => {
155
- const onClick = jest.fn();
155
+ const onClick = vi.fn();
156
156
  const { chip } = setup({ onInputClick: onClick, variant: SelectVariant.chip });
157
157
 
158
158
  await userEvent.click(chip as any);
@@ -161,7 +161,7 @@ describe('<SelectMultiple>', () => {
161
161
  });
162
162
 
163
163
  it('should call onClear when an item is clicked with the correct value', async () => {
164
- const onClear = jest.fn();
164
+ const onClear = vi.fn();
165
165
  const { valueChips } = setup({
166
166
  onClear,
167
167
  value: ['val 1', 'val 2'],
@@ -184,7 +184,7 @@ describe('<SelectMultiple>', () => {
184
184
  const value1 = 'Value 1';
185
185
  const value2 = 'Value 2';
186
186
 
187
- const onClear = jest.fn();
187
+ const onClear = vi.fn();
188
188
  const { chip } = setup({
189
189
  onClear,
190
190
  value: [value1, value2],
@@ -10,7 +10,7 @@ const CLASSNAME = SideNavigationItem.className as string;
10
10
 
11
11
  const toggleButtonProps = { label: 'Toggle' };
12
12
 
13
- jest.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
13
+ vi.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
14
14
 
15
15
  /**
16
16
  * Mounts the component and returns common DOM elements / data needed in multiple tests further down.
@@ -106,7 +106,7 @@ describe(`<${SideNavigationItem.displayName}>`, () => {
106
106
 
107
107
  describe('children and link', () => {
108
108
  it('should render with children and link', () => {
109
- const onActionClick = jest.fn();
109
+ const onActionClick = vi.fn();
110
110
  const label = 'Side navigation item';
111
111
  const { props, toggle, link } = setup({
112
112
  label,
@@ -7,10 +7,9 @@ import { mdiChevronDown, mdiChevronUp } from '@lumx/icons';
7
7
  import { Emphasis, Icon, Size, IconButton, IconButtonProps } from '@lumx/react';
8
8
  import { GenericProps, HasCloseMode, isComponent } from '@lumx/react/utils/type';
9
9
  import { getRootClassName, handleBasicClasses } from '@lumx/core/js/utils/className';
10
- import { renderLink } from '@lumx/react/utils/react/renderLink';
11
- import { renderButtonOrLink } from '@lumx/react/utils/react/renderButtonOrLink';
12
10
  import { useId } from '@lumx/react/hooks/useId';
13
11
  import { forwardRef } from '@lumx/react/utils/react/forwardRef';
12
+ import { RawClickable } from '@lumx/react/utils/react/RawClickable';
14
13
 
15
14
  /**
16
15
  * Defines the props of the component.
@@ -113,17 +112,15 @@ export const SideNavigationItem = forwardRef<SideNavigationItemProps, HTMLLIElem
113
112
  >
114
113
  {shouldSplitActions ? (
115
114
  <div className={`${CLASSNAME}__wrapper`}>
116
- {renderLink(
117
- {
118
- linkAs,
119
- ...linkProps,
120
- className: `${CLASSNAME}__link`,
121
- onClick,
122
- tabIndex: 0,
123
- },
124
- icon && <Icon className={`${CLASSNAME}__icon`} icon={icon} size={Size.xs} />,
125
- <span>{label}</span>,
126
- )}
115
+ <RawClickable
116
+ as={linkAs || (linkProps?.href ? 'a' : 'button')}
117
+ {...(linkProps as any)}
118
+ className={`${CLASSNAME}__link`}
119
+ onClick={onClick}
120
+ >
121
+ {icon && <Icon className={`${CLASSNAME}__icon`} icon={icon} size={Size.xs} />}
122
+ <span>{label}</span>
123
+ </RawClickable>
127
124
 
128
125
  <IconButton
129
126
  {...toggleButtonProps}
@@ -136,25 +133,23 @@ export const SideNavigationItem = forwardRef<SideNavigationItemProps, HTMLLIElem
136
133
  />
137
134
  </div>
138
135
  ) : (
139
- renderButtonOrLink(
140
- {
141
- linkAs,
142
- ...linkProps,
143
- className: `${CLASSNAME}__link`,
144
- tabIndex: 0,
145
- onClick,
146
- ...ariaProps,
147
- },
148
- icon && <Icon className={`${CLASSNAME}__icon`} icon={icon} size={Size.xs} />,
149
- <span>{label}</span>,
150
- hasContent && (
136
+ <RawClickable
137
+ as={linkAs || (linkProps?.href ? 'a' : 'button')}
138
+ {...linkProps}
139
+ className={`${CLASSNAME}__link`}
140
+ onClick={onClick}
141
+ {...ariaProps}
142
+ >
143
+ {icon && <Icon className={`${CLASSNAME}__icon`} icon={icon} size={Size.xs} />}
144
+ <span>{label}</span>
145
+ {hasContent && (
151
146
  <Icon
152
147
  className={`${CLASSNAME}__chevron`}
153
148
  icon={isOpen ? mdiChevronUp : mdiChevronDown}
154
149
  size={Size.xs}
155
150
  />
156
- ),
157
- )
151
+ )}
152
+ </RawClickable>
158
153
  )}
159
154
 
160
155
  {(closeMode === 'hide' || showChildren) && (
@@ -7,7 +7,7 @@ import { Slider, SliderProps } from './Slider';
7
7
 
8
8
  const CLASSNAME = Slider.className as string;
9
9
 
10
- jest.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
10
+ vi.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
11
11
 
12
12
  const setup = (props: Partial<SliderProps> = {}, { wrapper }: SetupRenderOptions = {}) => {
13
13
  render(<Slider {...(props as any)} />, { wrapper });
@@ -3,7 +3,7 @@ import React from 'react';
3
3
  import { commonTestsSuiteRTL, SetupRenderOptions } from '@lumx/react/testing/utils';
4
4
  import { render } from '@testing-library/react';
5
5
  import { getByClassName, getByTagName, queryByClassName } from '@lumx/react/testing/utils/queries';
6
- import userEvent from '@testing-library/user-event/';
6
+ import userEvent from '@testing-library/user-event';
7
7
 
8
8
  import { Switch, SwitchProps } from './Switch';
9
9
 
@@ -24,7 +24,7 @@ const setup = (propsOverride: SetupProps = {}, { wrapper }: SetupRenderOptions =
24
24
  return { switchWrapper, input, helper, label, props };
25
25
  };
26
26
 
27
- jest.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
27
+ vi.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
28
28
 
29
29
  describe(`<${Switch.displayName}>`, () => {
30
30
  describe('Props', () => {
@@ -86,7 +86,7 @@ describe(`<${Switch.displayName}>`, () => {
86
86
  });
87
87
 
88
88
  describe('Events', () => {
89
- const onChange = jest.fn();
89
+ const onChange = vi.fn();
90
90
 
91
91
  it('should trigger `onChange` when switchWrapper is clicked', async () => {
92
92
  const value = 'value';
@@ -102,7 +102,7 @@ describe(`<${Switch.displayName}>`, () => {
102
102
 
103
103
  describe('Disabled state', () => {
104
104
  it('should be disabled with isDisabled', async () => {
105
- const onChange = jest.fn();
105
+ const onChange = vi.fn();
106
106
  const { switchWrapper, input } = setup({ isDisabled: true, onChange });
107
107
 
108
108
  expect(switchWrapper).toHaveClass('lumx-switch--is-disabled');
@@ -115,7 +115,7 @@ describe(`<${Switch.displayName}>`, () => {
115
115
  });
116
116
 
117
117
  it('should be disabled with aria-disabled', async () => {
118
- const onChange = jest.fn();
118
+ const onChange = vi.fn();
119
119
  const { switchWrapper, input } = setup({ 'aria-disabled': true, onChange });
120
120
 
121
121
  expect(switchWrapper).toHaveClass('lumx-switch--is-disabled');
@@ -42,7 +42,7 @@ describe(`<${TableCell.displayName}>`, () => {
42
42
 
43
43
  it('should render header variant clickable', async () => {
44
44
  const content = 'Content';
45
- const onHeaderClick = jest.fn();
45
+ const onHeaderClick = vi.fn();
46
46
  const { tableCell } = setup({ children: content, variant: 'head', onHeaderClick });
47
47
 
48
48
  const headerButton = within(tableCell).getByRole('button', { name: content });
@@ -1,3 +1,4 @@
1
+ import { Mock } from 'vitest';
1
2
  import React from 'react';
2
3
 
3
4
  import camelCase from 'lodash/camelCase';
@@ -20,7 +21,7 @@ import { TextField, TextFieldProps } from './TextField';
20
21
 
21
22
  const CLASSNAME = TextField.className as string;
22
23
 
23
- jest.mock('@lumx/react/utils/browser/isFocusVisible');
24
+ vi.mock('@lumx/react/utils/browser/isFocusVisible');
24
25
 
25
26
  /**
26
27
  * Mounts the component and returns common DOM elements / data needed in multiple tests further down.
@@ -49,7 +50,7 @@ const setup = (propsOverride: Partial<TextFieldProps> = {}, { wrapper }: SetupRe
49
50
  };
50
51
 
51
52
  describe(`<${TextField.displayName}>`, () => {
52
- (isFocusVisible as jest.Mock).mockReturnValue(false);
53
+ (isFocusVisible as Mock).mockReturnValue(false);
53
54
 
54
55
  describe('Render', () => {
55
56
  it('should render defaults', () => {
@@ -180,7 +181,7 @@ describe(`<${TextField.displayName}>`, () => {
180
181
 
181
182
  describe('Events', () => {
182
183
  it('should trigger `onChange` when text field is changed', async () => {
183
- const onChange = jest.fn();
184
+ const onChange = vi.fn();
184
185
  const { inputNative } = setup({ value: '', name: 'name', onChange });
185
186
 
186
187
  await userEvent.tab();
@@ -192,7 +193,7 @@ describe(`<${TextField.displayName}>`, () => {
192
193
  });
193
194
 
194
195
  it('should trigger `onChange` with empty value when text field is cleared', async () => {
195
- const onChange = jest.fn();
196
+ const onChange = vi.fn();
196
197
  const { clearButton } = setup({
197
198
  value: 'initial value',
198
199
  name: 'name',
@@ -208,8 +209,8 @@ describe(`<${TextField.displayName}>`, () => {
208
209
  });
209
210
 
210
211
  it('should trigger `onChange` with empty value and `onClear` when text field is cleared', async () => {
211
- const onChange = jest.fn();
212
- const onClear = jest.fn();
212
+ const onChange = vi.fn();
213
+ const onClear = vi.fn();
213
214
  const { clearButton } = setup({
214
215
  value: 'initial value',
215
216
  name: 'name',
@@ -229,7 +230,7 @@ describe(`<${TextField.displayName}>`, () => {
229
230
 
230
231
  describe('Disabled state', () => {
231
232
  it('should render with "isDisabled"', async () => {
232
- const onChange = jest.fn();
233
+ const onChange = vi.fn();
233
234
  const { element, inputNative } = setup({
234
235
  label: 'Label',
235
236
  isDisabled: true,
@@ -255,7 +256,7 @@ describe(`<${TextField.displayName}>`, () => {
255
256
  });
256
257
 
257
258
  it('should render with "aria-disabled"', async () => {
258
- const onChange = jest.fn();
259
+ const onChange = vi.fn();
259
260
  const { element, inputNative } = setup({
260
261
  label: 'Label',
261
262
  'aria-disabled': true,
@@ -3,7 +3,7 @@ import React from 'react';
3
3
  import { DisabledStateProvider } from '@lumx/react/utils';
4
4
  import { commonTestsSuiteRTL, SetupRenderOptions } from '@lumx/react/testing/utils';
5
5
  import { queryByClassName } from '@lumx/react/testing/utils/queries';
6
- import { fireEvent, render } from '@testing-library/react';
6
+ import { fireEvent, render, screen } from '@testing-library/react';
7
7
  import { Thumbnail, ThumbnailProps } from './Thumbnail';
8
8
 
9
9
  const CLASSNAME = Thumbnail.className as string;
@@ -28,9 +28,20 @@ describe(`<${Thumbnail.displayName}>`, () => {
28
28
  },
29
29
  });
30
30
 
31
- describe('disabled state', () => {
32
- it('should not be clickable when disabled from context', () => {
33
- const onClick = jest.fn();
31
+ describe('clickable button', () => {
32
+ it('should render clickable button', async () => {
33
+ const onClick = vi.fn();
34
+ const { thumbnail } = setup({ onClick, alt: 'Name' });
35
+ const button = screen.getByRole('button', { name: 'Name' });
36
+ expect(button).toBe(thumbnail);
37
+ expect(button).toHaveAttribute('type', 'button');
38
+
39
+ fireEvent.click(thumbnail as HTMLElement);
40
+ expect(onClick).toHaveBeenCalled();
41
+ });
42
+
43
+ it('should not render button in disabled context', () => {
44
+ const onClick = vi.fn();
34
45
  const { thumbnail, container } = setup(
35
46
  { onClick, 'aria-label': 'thumbnail' },
36
47
  {
@@ -47,8 +58,21 @@ describe(`<${Thumbnail.displayName}>`, () => {
47
58
  fireEvent.click(thumbnail as HTMLElement);
48
59
  expect(onClick).not.toHaveBeenCalled();
49
60
  });
61
+ });
62
+
63
+ describe('clickable link', () => {
64
+ it('should render clickable link', async () => {
65
+ const onClick = vi.fn((evt: any) => evt.preventDefault());
66
+ const { thumbnail } = setup({ linkProps: { href: '#' }, onClick, alt: 'Name' });
67
+ const link = screen.getByRole('link');
68
+ expect(link).toBe(thumbnail);
69
+ expect(link).toHaveAttribute('href', '#');
70
+
71
+ fireEvent.click(thumbnail as HTMLElement);
72
+ expect(onClick).toHaveBeenCalled();
73
+ });
50
74
 
51
- it('should have no href when disabled from context', () => {
75
+ it('should not render link in disabled context', () => {
52
76
  const { container, thumbnail } = setup(
53
77
  { linkAs: 'a', linkProps: { href: '#' }, 'aria-label': 'thumbnail' },
54
78
  {
@@ -22,6 +22,7 @@ import { useTheme } from '@lumx/react/utils/theme/ThemeContext';
22
22
  import { forwardRef } from '@lumx/react/utils/react/forwardRef';
23
23
 
24
24
  import { useDisableStateProps } from '@lumx/react/utils/disabled';
25
+ import { RawClickable } from '@lumx/react/utils/react/RawClickable';
25
26
  import { FocusPoint, ThumbnailSize, ThumbnailVariant } from './types';
26
27
 
27
28
  type ImgHTMLProps = ImgHTMLAttributes<HTMLImageElement>;
@@ -100,7 +101,7 @@ const DEFAULT_PROPS: Partial<ThumbnailProps> = {
100
101
  * @return React element.
101
102
  */
102
103
  export const Thumbnail = forwardRef<ThumbnailProps>((props, ref) => {
103
- const { isAnyDisabled, otherProps } = useDisableStateProps(props);
104
+ const { isAnyDisabled, otherProps, disabledStateProps } = useDisableStateProps(props);
104
105
  const defaultTheme = useTheme() || Theme.light;
105
106
  const {
106
107
  align,
@@ -151,18 +152,17 @@ export const Thumbnail = forwardRef<ThumbnailProps>((props, ref) => {
151
152
  }
152
153
 
153
154
  const isLink = Boolean(linkProps?.href || linkAs);
154
- const isButton = !!forwardedProps.onClick;
155
- const isClickable = !isAnyDisabled && (isButton || isLink);
155
+ const isClickable = !isAnyDisabled && Boolean(isLink || !!forwardedProps.onClick);
156
156
 
157
- let Wrapper: any = 'div';
157
+ const Wrapper: any = isClickable ? RawClickable : 'div';
158
158
  const wrapperProps = { ...forwardedProps };
159
- if (!isAnyDisabled && isLink) {
160
- Wrapper = linkAs || 'a';
161
- Object.assign(wrapperProps, linkProps);
162
- } else if (!isAnyDisabled && isButton) {
163
- Wrapper = 'button';
164
- wrapperProps.type = forwardedProps.type || 'button';
165
- wrapperProps['aria-label'] = forwardedProps['aria-label'] || alt;
159
+ if (isClickable) {
160
+ Object.assign(wrapperProps, { as: linkAs || (linkProps?.href ? 'a' : 'button') }, disabledStateProps);
161
+ if (isLink) {
162
+ Object.assign(wrapperProps, linkProps);
163
+ } else {
164
+ wrapperProps['aria-label'] = forwardedProps['aria-label'] || alt;
165
+ }
166
166
  }
167
167
 
168
168
  // If we have a loading placeholder image that is really loaded (complete)
@@ -1,3 +1,4 @@
1
+ import { MockInstance } from 'vitest';
1
2
  import React from 'react';
2
3
 
3
4
  import { Button } from '@lumx/react';
@@ -12,13 +13,18 @@ import { Tooltip, TooltipProps } from './Tooltip';
12
13
 
13
14
  const CLASSNAME = Tooltip.className as string;
14
15
 
15
- jest.mock('@lumx/react/utils/browser/isFocusVisible');
16
- jest.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
16
+ vi.mock('@lumx/react/utils/browser/isFocusVisible');
17
+ vi.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
17
18
  // Skip delays
18
- jest.mock('@lumx/react/constants', () => ({
19
- ...jest.requireActual('@lumx/react/constants'),
20
- TOOLTIP_HOVER_DELAY: { open: 0, close: 0 },
21
- }));
19
+ vi.mock('@lumx/react/constants', async (importActual) => {
20
+ const actual = (await importActual()) as Record<string, any>;
21
+ return {
22
+ ...actual,
23
+ TOOLTIP_HOVER_DELAY: { open: 0, close: 0 },
24
+ VISUALLY_HIDDEN: actual.VISUALLY_HIDDEN,
25
+ CSS_PREFIX: actual.CSS_PREFIX,
26
+ };
27
+ });
22
28
 
23
29
  /**
24
30
  * Mounts the component and returns common DOM elements / data needed in multiple tests further down.
@@ -346,7 +352,7 @@ describe(`<${Tooltip.displayName}>`, () => {
346
352
  });
347
353
 
348
354
  it('should activate on anchor focus visible and close on escape', async () => {
349
- (isFocusVisible as jest.Mock).mockReturnValue(true);
355
+ (isFocusVisible as unknown as MockInstance).mockReturnValue(true);
350
356
  let { tooltip } = await setup({
351
357
  label: 'Tooltip label',
352
358
  children: <Button>Anchor</Button>,
@@ -381,7 +387,7 @@ describe(`<${Tooltip.displayName}>`, () => {
381
387
  });
382
388
 
383
389
  it('should not activate on anchor focus if not visible', async () => {
384
- (isFocusVisible as jest.Mock).mockReturnValue(false);
390
+ (isFocusVisible as unknown as MockInstance).mockReturnValue(false);
385
391
  let { tooltip } = await setup({
386
392
  label: 'Tooltip label',
387
393
  children: <Button>Anchor</Button>,
@@ -89,9 +89,9 @@ describe(`<${Uploader.displayName}>`, () => {
89
89
  ${'button'} | ${{}}
90
90
  ${'button isDisabled '} | ${{ isDisabled: true }}
91
91
  ${'button aria-disabled'} | ${{ 'aria-disabled': true }}
92
- ${'file input '} | ${{ fileInputProps: { onChange: jest.fn() } }}
92
+ ${'file input '} | ${{ fileInputProps: { onChange: vi.fn() } }}
93
93
  `('Events $name', ({ props }) => {
94
- const onClick = jest.fn();
94
+ const onClick = vi.fn();
95
95
  beforeEach(() => onClick.mockClear());
96
96
  const assertClick = () => {
97
97
  if (props.isDisabled || props['aria-disabled']) {
@@ -36,7 +36,7 @@ describe(`<${UserBlock.displayName}>`, () => {
36
36
  });
37
37
 
38
38
  it('should render button', async () => {
39
- const onClick = jest.fn();
39
+ const onClick = vi.fn();
40
40
  const { name, thumbnail } = setup({
41
41
  onClick,
42
42
  name: 'John Doe',
@@ -1,3 +1,7 @@
1
+ // Extend CSSStyleDeclaration to support viewTransitionName for view transitions
2
+ interface CSSStyleDeclaration {
3
+ viewTransitionName: string | null;
4
+ }
1
5
  /**
2
6
  * List untypped modules here to declare them as explicit any.
3
7
  */
@@ -30,7 +30,7 @@ describe('PortalProvider', () => {
30
30
  });
31
31
 
32
32
  it('should call teardown on unmount', () => {
33
- const teardownMock = jest.fn();
33
+ const teardownMock = vi.fn();
34
34
  const portalContainer = document.createElement('div');
35
35
  portalContainer.id = PORTAL_CONTAINER_ID;
36
36
  document.body.appendChild(portalContainer);
@@ -4,7 +4,7 @@ describe(getYearDisplayName, () => {
4
4
  beforeEach(() => {
5
5
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
6
6
  // @ts-ignore
7
- jest.spyOn(Intl, 'DisplayNames').mockImplementation(() => ({
7
+ vi.spyOn(Intl, 'DisplayNames').mockImplementation(() => ({
8
8
  resolvedOptions: () => ({
9
9
  fallback: 'code',
10
10
  locale: 'fr',
@@ -59,14 +59,14 @@ describe(useDisableStateProps.name, () => {
59
59
  });
60
60
 
61
61
  it('should forward onClick when not disabled', () => {
62
- const onClick = jest.fn();
62
+ const onClick = vi.fn();
63
63
  const { element } = setup({ onClick });
64
64
  fireEvent.click(element);
65
65
  expect(onClick).toHaveBeenCalled();
66
66
  });
67
67
 
68
68
  it('should not forward onClick when disabled', () => {
69
- const onClick = jest.fn();
69
+ const onClick = vi.fn();
70
70
  const { element } = setup({ disabled: true, onClick });
71
71
  fireEvent.click(element);
72
72
  expect(onClick).not.toHaveBeenCalled();