@lumx/react 3.20.0 → 3.20.1-alpha.1

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 +13 -20
  2. package/_internal/index.js.map +1 -1
  3. package/index.d.ts +6 -5
  4. package/index.js +2439 -2399
  5. package/index.js.map +1 -1
  6. package/package.json +13 -10
  7. package/src/components/alert-dialog/AlertDialog.test.tsx +2 -3
  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 +36 -6
  11. package/src/components/checkbox/Checkbox.test.tsx +3 -3
  12. package/src/components/chip/Chip.test.tsx +17 -19
  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 +5 -6
  19. package/src/components/icon/Icon.stories.tsx +4 -30
  20. package/src/components/icon/Icon.test.tsx +2 -85
  21. package/src/components/icon/Icon.tsx +7 -118
  22. package/src/components/image-lightbox/ImageLightbox.test.tsx +7 -11
  23. package/src/components/link/Link.test.tsx +11 -13
  24. package/src/components/link/Link.tsx +20 -9
  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 +10 -6
  29. package/src/components/navigation/NavigationSection.tsx +3 -4
  30. package/src/components/notification/Notification.test.tsx +3 -4
  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 +7 -8
  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 +27 -22
  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 +8 -9
  41. package/src/components/thumbnail/Thumbnail.test.tsx +5 -29
  42. package/src/components/thumbnail/Thumbnail.tsx +11 -11
  43. package/src/components/tooltip/Tooltip.test.tsx +8 -14
  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 +0 -4
  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/renderButtonOrLink.tsx +16 -0
  51. package/src/utils/type/index.ts +0 -1
  52. package/utils/index.d.ts +1 -1
  53. package/utils/index.js +1 -1
  54. package/src/utils/react/RawClickable.test.tsx +0 -153
  55. package/src/utils/react/RawClickable.tsx +0 -65
  56. package/src/utils/type/HasRequiredLinkHref.ts +0 -1
@@ -1,4 +1,3 @@
1
- import { Mock } from 'vitest';
2
1
  import React from 'react';
3
2
 
4
3
  import { Theme } from '@lumx/core/js/constants';
@@ -14,8 +13,8 @@ import { Select, SelectProps, SelectVariant } from './Select';
14
13
 
15
14
  const CLASSNAME = Select.className as string;
16
15
 
17
- vi.mock('@lumx/react/utils/browser/isFocusVisible');
18
- vi.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
16
+ jest.mock('@lumx/react/utils/browser/isFocusVisible');
17
+ jest.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
19
18
 
20
19
  /**
21
20
  * Mounts the component and returns common DOM elements / data needed in multiple tests further down.
@@ -36,7 +35,7 @@ const setup = (propsOverride: Partial<SelectProps> = {}, { wrapper }: SetupRende
36
35
  };
37
36
 
38
37
  describe(`<${Select.displayName}>`, () => {
39
- (isFocusVisible as Mock).mockReturnValue(false);
38
+ (isFocusVisible as jest.Mock).mockReturnValue(false);
40
39
 
41
40
  describe('Props', () => {
42
41
  it('should have default classNames', () => {
@@ -145,7 +144,7 @@ describe(`<${Select.displayName}>`, () => {
145
144
 
146
145
  describe('Events', () => {
147
146
  it('should trigger `onDropdownClose` on escape', async () => {
148
- const onDropdownClose = vi.fn();
147
+ const onDropdownClose = jest.fn();
149
148
  const { getDropdown } = setup({ isOpen: true, onDropdownClose });
150
149
 
151
150
  const dropdown = getDropdown();
@@ -157,7 +156,7 @@ describe(`<${Select.displayName}>`, () => {
157
156
 
158
157
  describe('should trigger `onInputClick` when the select button is clicked', () => {
159
158
  it('with input variant', async () => {
160
- const onClick = vi.fn();
159
+ const onClick = jest.fn();
161
160
  const { inputWrapper } = setup({ onInputClick: onClick, variant: SelectVariant.input });
162
161
 
163
162
  await userEvent.click(inputWrapper as any);
@@ -165,7 +164,7 @@ describe(`<${Select.displayName}>`, () => {
165
164
  });
166
165
 
167
166
  it('with chip variant', async () => {
168
- const onClick = vi.fn();
167
+ const onClick = jest.fn();
169
168
  const { chip } = setup({ onInputClick: onClick, variant: SelectVariant.chip });
170
169
 
171
170
  await userEvent.click(chip as any);
@@ -175,7 +174,7 @@ describe(`<${Select.displayName}>`, () => {
175
174
 
176
175
  it('should call onClear when clear icon is clicked in select input', async () => {
177
176
  const value = 'Value';
178
- const onClear = vi.fn();
177
+ const onClear = jest.fn();
179
178
  const { select, props } = setup({ value, onClear, clearButtonProps: { label: 'Clear' } });
180
179
 
181
180
  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
- vi.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
21
+ jest.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 = vi.fn();
147
+ const onClick = jest.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 = vi.fn();
155
+ const onClick = jest.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 = vi.fn();
164
+ const onClear = jest.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 = vi.fn();
187
+ const onClear = jest.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
- vi.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
13
+ jest.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 = vi.fn();
109
+ const onActionClick = jest.fn();
110
110
  const label = 'Side navigation item';
111
111
  const { props, toggle, link } = setup({
112
112
  label,
@@ -7,9 +7,10 @@ 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';
10
12
  import { useId } from '@lumx/react/hooks/useId';
11
13
  import { forwardRef } from '@lumx/react/utils/react/forwardRef';
12
- import { RawClickable } from '@lumx/react/utils/react/RawClickable';
13
14
 
14
15
  /**
15
16
  * Defines the props of the component.
@@ -112,15 +113,17 @@ export const SideNavigationItem = forwardRef<SideNavigationItemProps, HTMLLIElem
112
113
  >
113
114
  {shouldSplitActions ? (
114
115
  <div className={`${CLASSNAME}__wrapper`}>
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>
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
+ )}
124
127
 
125
128
  <IconButton
126
129
  {...toggleButtonProps}
@@ -133,23 +136,25 @@ export const SideNavigationItem = forwardRef<SideNavigationItemProps, HTMLLIElem
133
136
  />
134
137
  </div>
135
138
  ) : (
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 && (
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 && (
146
151
  <Icon
147
152
  className={`${CLASSNAME}__chevron`}
148
153
  icon={isOpen ? mdiChevronUp : mdiChevronDown}
149
154
  size={Size.xs}
150
155
  />
151
- )}
152
- </RawClickable>
156
+ ),
157
+ )
153
158
  )}
154
159
 
155
160
  {(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
- vi.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
10
+ jest.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
- vi.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
27
+ jest.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 = vi.fn();
89
+ const onChange = jest.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 = vi.fn();
105
+ const onChange = jest.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 = vi.fn();
118
+ const onChange = jest.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 = vi.fn();
45
+ const onHeaderClick = jest.fn();
46
46
  const { tableCell } = setup({ children: content, variant: 'head', onHeaderClick });
47
47
 
48
48
  const headerButton = within(tableCell).getByRole('button', { name: content });
@@ -1,4 +1,3 @@
1
- import { Mock } from 'vitest';
2
1
  import React from 'react';
3
2
 
4
3
  import camelCase from 'lodash/camelCase';
@@ -21,7 +20,7 @@ import { TextField, TextFieldProps } from './TextField';
21
20
 
22
21
  const CLASSNAME = TextField.className as string;
23
22
 
24
- vi.mock('@lumx/react/utils/browser/isFocusVisible');
23
+ jest.mock('@lumx/react/utils/browser/isFocusVisible');
25
24
 
26
25
  /**
27
26
  * Mounts the component and returns common DOM elements / data needed in multiple tests further down.
@@ -50,7 +49,7 @@ const setup = (propsOverride: Partial<TextFieldProps> = {}, { wrapper }: SetupRe
50
49
  };
51
50
 
52
51
  describe(`<${TextField.displayName}>`, () => {
53
- (isFocusVisible as Mock).mockReturnValue(false);
52
+ (isFocusVisible as jest.Mock).mockReturnValue(false);
54
53
 
55
54
  describe('Render', () => {
56
55
  it('should render defaults', () => {
@@ -181,7 +180,7 @@ describe(`<${TextField.displayName}>`, () => {
181
180
 
182
181
  describe('Events', () => {
183
182
  it('should trigger `onChange` when text field is changed', async () => {
184
- const onChange = vi.fn();
183
+ const onChange = jest.fn();
185
184
  const { inputNative } = setup({ value: '', name: 'name', onChange });
186
185
 
187
186
  await userEvent.tab();
@@ -193,7 +192,7 @@ describe(`<${TextField.displayName}>`, () => {
193
192
  });
194
193
 
195
194
  it('should trigger `onChange` with empty value when text field is cleared', async () => {
196
- const onChange = vi.fn();
195
+ const onChange = jest.fn();
197
196
  const { clearButton } = setup({
198
197
  value: 'initial value',
199
198
  name: 'name',
@@ -209,8 +208,8 @@ describe(`<${TextField.displayName}>`, () => {
209
208
  });
210
209
 
211
210
  it('should trigger `onChange` with empty value and `onClear` when text field is cleared', async () => {
212
- const onChange = vi.fn();
213
- const onClear = vi.fn();
211
+ const onChange = jest.fn();
212
+ const onClear = jest.fn();
214
213
  const { clearButton } = setup({
215
214
  value: 'initial value',
216
215
  name: 'name',
@@ -230,7 +229,7 @@ describe(`<${TextField.displayName}>`, () => {
230
229
 
231
230
  describe('Disabled state', () => {
232
231
  it('should render with "isDisabled"', async () => {
233
- const onChange = vi.fn();
232
+ const onChange = jest.fn();
234
233
  const { element, inputNative } = setup({
235
234
  label: 'Label',
236
235
  isDisabled: true,
@@ -256,7 +255,7 @@ describe(`<${TextField.displayName}>`, () => {
256
255
  });
257
256
 
258
257
  it('should render with "aria-disabled"', async () => {
259
- const onChange = vi.fn();
258
+ const onChange = jest.fn();
260
259
  const { element, inputNative } = setup({
261
260
  label: 'Label',
262
261
  '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, screen } from '@testing-library/react';
6
+ import { fireEvent, render } from '@testing-library/react';
7
7
  import { Thumbnail, ThumbnailProps } from './Thumbnail';
8
8
 
9
9
  const CLASSNAME = Thumbnail.className as string;
@@ -28,20 +28,9 @@ describe(`<${Thumbnail.displayName}>`, () => {
28
28
  },
29
29
  });
30
30
 
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();
31
+ describe('disabled state', () => {
32
+ it('should not be clickable when disabled from context', () => {
33
+ const onClick = jest.fn();
45
34
  const { thumbnail, container } = setup(
46
35
  { onClick, 'aria-label': 'thumbnail' },
47
36
  {
@@ -58,21 +47,8 @@ describe(`<${Thumbnail.displayName}>`, () => {
58
47
  fireEvent.click(thumbnail as HTMLElement);
59
48
  expect(onClick).not.toHaveBeenCalled();
60
49
  });
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
- });
74
50
 
75
- it('should not render link in disabled context', () => {
51
+ it('should have no href when disabled from context', () => {
76
52
  const { container, thumbnail } = setup(
77
53
  { linkAs: 'a', linkProps: { href: '#' }, 'aria-label': 'thumbnail' },
78
54
  {
@@ -22,7 +22,6 @@ 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';
26
25
  import { FocusPoint, ThumbnailSize, ThumbnailVariant } from './types';
27
26
 
28
27
  type ImgHTMLProps = ImgHTMLAttributes<HTMLImageElement>;
@@ -101,7 +100,7 @@ const DEFAULT_PROPS: Partial<ThumbnailProps> = {
101
100
  * @return React element.
102
101
  */
103
102
  export const Thumbnail = forwardRef<ThumbnailProps>((props, ref) => {
104
- const { isAnyDisabled, otherProps, disabledStateProps } = useDisableStateProps(props);
103
+ const { isAnyDisabled, otherProps } = useDisableStateProps(props);
105
104
  const defaultTheme = useTheme() || Theme.light;
106
105
  const {
107
106
  align,
@@ -152,17 +151,18 @@ export const Thumbnail = forwardRef<ThumbnailProps>((props, ref) => {
152
151
  }
153
152
 
154
153
  const isLink = Boolean(linkProps?.href || linkAs);
155
- const isClickable = !isAnyDisabled && Boolean(isLink || !!forwardedProps.onClick);
154
+ const isButton = !!forwardedProps.onClick;
155
+ const isClickable = !isAnyDisabled && (isButton || isLink);
156
156
 
157
- const Wrapper: any = isClickable ? RawClickable : 'div';
157
+ let Wrapper: any = 'div';
158
158
  const wrapperProps = { ...forwardedProps };
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
- }
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;
166
166
  }
167
167
 
168
168
  // If we have a loading placeholder image that is really loaded (complete)
@@ -1,4 +1,3 @@
1
- import { MockInstance } from 'vitest';
2
1
  import React from 'react';
3
2
 
4
3
  import { Button } from '@lumx/react';
@@ -13,18 +12,13 @@ import { Tooltip, TooltipProps } from './Tooltip';
13
12
 
14
13
  const CLASSNAME = Tooltip.className as string;
15
14
 
16
- vi.mock('@lumx/react/utils/browser/isFocusVisible');
17
- vi.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
15
+ jest.mock('@lumx/react/utils/browser/isFocusVisible');
16
+ jest.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
18
17
  // Skip delays
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
- });
18
+ jest.mock('@lumx/react/constants', () => ({
19
+ ...jest.requireActual('@lumx/react/constants'),
20
+ TOOLTIP_HOVER_DELAY: { open: 0, close: 0 },
21
+ }));
28
22
 
29
23
  /**
30
24
  * Mounts the component and returns common DOM elements / data needed in multiple tests further down.
@@ -352,7 +346,7 @@ describe(`<${Tooltip.displayName}>`, () => {
352
346
  });
353
347
 
354
348
  it('should activate on anchor focus visible and close on escape', async () => {
355
- (isFocusVisible as unknown as MockInstance).mockReturnValue(true);
349
+ (isFocusVisible as jest.Mock).mockReturnValue(true);
356
350
  let { tooltip } = await setup({
357
351
  label: 'Tooltip label',
358
352
  children: <Button>Anchor</Button>,
@@ -387,7 +381,7 @@ describe(`<${Tooltip.displayName}>`, () => {
387
381
  });
388
382
 
389
383
  it('should not activate on anchor focus if not visible', async () => {
390
- (isFocusVisible as unknown as MockInstance).mockReturnValue(false);
384
+ (isFocusVisible as jest.Mock).mockReturnValue(false);
391
385
  let { tooltip } = await setup({
392
386
  label: 'Tooltip label',
393
387
  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: vi.fn() } }}
92
+ ${'file input '} | ${{ fileInputProps: { onChange: jest.fn() } }}
93
93
  `('Events $name', ({ props }) => {
94
- const onClick = vi.fn();
94
+ const onClick = jest.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 = vi.fn();
39
+ const onClick = jest.fn();
40
40
  const { name, thumbnail } = setup({
41
41
  onClick,
42
42
  name: 'John Doe',
@@ -1,7 +1,3 @@
1
- // Extend CSSStyleDeclaration to support viewTransitionName for view transitions
2
- interface CSSStyleDeclaration {
3
- viewTransitionName: string | null;
4
- }
5
1
  /**
6
2
  * List untypped modules here to declare them as explicit any.
7
3
  */
@@ -30,7 +30,7 @@ describe('PortalProvider', () => {
30
30
  });
31
31
 
32
32
  it('should call teardown on unmount', () => {
33
- const teardownMock = vi.fn();
33
+ const teardownMock = jest.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
- vi.spyOn(Intl, 'DisplayNames').mockImplementation(() => ({
7
+ jest.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 = vi.fn();
62
+ const onClick = jest.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 = vi.fn();
69
+ const onClick = jest.fn();
70
70
  const { element } = setup({ disabled: true, onClick });
71
71
  fireEvent.click(element);
72
72
  expect(onClick).not.toHaveBeenCalled();
@@ -0,0 +1,16 @@
1
+ import React, { ReactElement, ReactNode } from 'react';
2
+ import { renderLink } from './renderLink';
3
+
4
+ interface Props {
5
+ linkAs?: any;
6
+ href?: any;
7
+ }
8
+
9
+ /**
10
+ * Render <button> HTML component, fallbacks to `<a>` when a `href` is provided or a custom component with `linkAs`.
11
+ */
12
+ export const renderButtonOrLink = <P extends Props>(props: P, ...children: ReactNode[]): ReactElement => {
13
+ const { linkAs, href, ...forwardedProps } = props;
14
+ if (linkAs || href) return renderLink(props, ...children);
15
+ return React.createElement('button', { type: 'button', ...forwardedProps }, ...children);
16
+ };
@@ -6,4 +6,3 @@ export type { HasPolymorphicAs } from './HasPolymorphicAs';
6
6
  export { isComponent } from './isComponent';
7
7
  export { isComponentType } from './isComponentType';
8
8
  export type { MaybeElementOrRef } from './MaybeElementOrRef';
9
- export type { HasRequiredLinkHref } from './HasRequiredLinkHref';
package/utils/index.d.ts CHANGED
@@ -71,7 +71,7 @@ type DisabledStateProviderProps = DisabledStateContextValue & {
71
71
  * Disabled state provider.
72
72
  * All nested LumX Design System components inherit this disabled state.
73
73
  */
74
- declare function DisabledStateProvider({ children, ...value }: DisabledStateProviderProps): React.JSX.Element;
74
+ declare function DisabledStateProvider({ children, ...value }: DisabledStateProviderProps): JSX.Element;
75
75
  /**
76
76
  * Get DisabledState context value
77
77
  */
package/utils/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { C as ClickAwayProvider, D as DisabledStateProvider, P as Portal, c as PortalProvider, u as useDisabledStateContext } from '../_internal/index.js';
1
+ export { C as ClickAwayProvider, D as DisabledStateProvider, P as Portal, b as PortalProvider, u as useDisabledStateContext } from '../_internal/index.js';
2
2
  //# sourceMappingURL=index.js.map