@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.
- package/_internal/index.js +20 -13
- package/_internal/index.js.map +1 -1
- package/index.d.ts +5 -6
- package/index.js +2400 -2440
- package/index.js.map +1 -1
- package/package.json +10 -13
- package/src/components/alert-dialog/AlertDialog.test.tsx +3 -2
- package/src/components/autocomplete/Autocomplete.test.tsx +3 -3
- package/src/components/button/Button.test.tsx +9 -9
- package/src/components/button/ButtonRoot.tsx +6 -36
- package/src/components/checkbox/Checkbox.test.tsx +3 -3
- package/src/components/chip/Chip.test.tsx +19 -17
- package/src/components/date-picker/DatePicker.test.tsx +3 -3
- package/src/components/date-picker/DatePickerControlled.test.tsx +6 -6
- package/src/components/date-picker/DatePickerField.test.tsx +3 -3
- package/src/components/dialog/Dialog.test.tsx +4 -4
- package/src/components/dropdown/Dropdown.test.tsx +3 -3
- package/src/components/expansion-panel/ExpansionPanel.test.tsx +6 -5
- package/src/components/icon/Icon.stories.tsx +30 -4
- package/src/components/icon/Icon.test.tsx +85 -2
- package/src/components/icon/Icon.tsx +118 -7
- package/src/components/image-lightbox/ImageLightbox.test.tsx +11 -7
- package/src/components/link/Link.test.tsx +13 -11
- package/src/components/link/Link.tsx +9 -20
- package/src/components/list/ListItem.test.tsx +5 -5
- package/src/components/message/Message.test.tsx +1 -1
- package/src/components/mosaic/Mosaic.test.tsx +3 -3
- package/src/components/navigation/NavigationItem.tsx +6 -10
- package/src/components/navigation/NavigationSection.tsx +4 -3
- package/src/components/notification/Notification.test.tsx +4 -3
- package/src/components/popover-dialog/PopoverDialog.test.tsx +1 -1
- package/src/components/radio-button/RadioButton.test.tsx +3 -3
- package/src/components/select/Select.test.tsx +8 -7
- package/src/components/select/SelectMultiple.test.tsx +5 -5
- package/src/components/side-navigation/SideNavigationItem.test.tsx +2 -2
- package/src/components/side-navigation/SideNavigationItem.tsx +22 -27
- package/src/components/slider/Slider.test.tsx +1 -1
- package/src/components/switch/Switch.test.tsx +5 -5
- package/src/components/table/TableCell.test.tsx +1 -1
- package/src/components/text-field/TextField.test.tsx +9 -8
- package/src/components/thumbnail/Thumbnail.test.tsx +29 -5
- package/src/components/thumbnail/Thumbnail.tsx +11 -11
- package/src/components/tooltip/Tooltip.test.tsx +14 -8
- package/src/components/uploader/Uploader.test.tsx +2 -2
- package/src/components/user-block/UserBlock.test.tsx +1 -1
- package/src/untypped-modules.d.ts +4 -0
- package/src/utils/Portal/PortalProvider.test.tsx +1 -1
- package/src/utils/date/getYearDisplayName.test.ts +1 -1
- package/src/utils/disabled/useDisableStateProps.test.tsx +2 -2
- package/src/utils/react/RawClickable.test.tsx +153 -0
- package/src/utils/react/RawClickable.tsx +65 -0
- package/src/utils/type/HasRequiredLinkHref.ts +1 -0
- package/src/utils/type/index.ts +1 -0
- package/utils/index.d.ts +1 -1
- package/utils/index.js +1 -1
- 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
|
-
|
|
17
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
117
|
-
{
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
|
|
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
|
-
|
|
140
|
-
{
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
212
|
-
const onClear =
|
|
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 =
|
|
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 =
|
|
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('
|
|
32
|
-
it('should
|
|
33
|
-
const onClick =
|
|
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
|
|
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
|
|
155
|
-
const isClickable = !isAnyDisabled && (isButton || isLink);
|
|
155
|
+
const isClickable = !isAnyDisabled && Boolean(isLink || !!forwardedProps.onClick);
|
|
156
156
|
|
|
157
|
-
|
|
157
|
+
const Wrapper: any = isClickable ? RawClickable : 'div';
|
|
158
158
|
const wrapperProps = { ...forwardedProps };
|
|
159
|
-
if (
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
|
|
16
|
-
|
|
16
|
+
vi.mock('@lumx/react/utils/browser/isFocusVisible');
|
|
17
|
+
vi.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
|
|
17
18
|
// Skip delays
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
|
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
|
|
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:
|
|
92
|
+
${'file input '} | ${{ fileInputProps: { onChange: vi.fn() } }}
|
|
93
93
|
`('Events $name', ({ props }) => {
|
|
94
|
-
const onClick =
|
|
94
|
+
const onClick = vi.fn();
|
|
95
95
|
beforeEach(() => onClick.mockClear());
|
|
96
96
|
const assertClick = () => {
|
|
97
97
|
if (props.isDisabled || props['aria-disabled']) {
|
|
@@ -30,7 +30,7 @@ describe('PortalProvider', () => {
|
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
it('should call teardown on unmount', () => {
|
|
33
|
-
const teardownMock =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
69
|
+
const onClick = vi.fn();
|
|
70
70
|
const { element } = setup({ disabled: true, onClick });
|
|
71
71
|
fireEvent.click(element);
|
|
72
72
|
expect(onClick).not.toHaveBeenCalled();
|