@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.
- package/_internal/index.js +13 -20
- package/_internal/index.js.map +1 -1
- package/index.d.ts +6 -5
- package/index.js +2439 -2399
- package/index.js.map +1 -1
- package/package.json +13 -10
- package/src/components/alert-dialog/AlertDialog.test.tsx +2 -3
- package/src/components/autocomplete/Autocomplete.test.tsx +3 -3
- package/src/components/button/Button.test.tsx +9 -9
- package/src/components/button/ButtonRoot.tsx +36 -6
- package/src/components/checkbox/Checkbox.test.tsx +3 -3
- package/src/components/chip/Chip.test.tsx +17 -19
- 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 +5 -6
- package/src/components/icon/Icon.stories.tsx +4 -30
- package/src/components/icon/Icon.test.tsx +2 -85
- package/src/components/icon/Icon.tsx +7 -118
- package/src/components/image-lightbox/ImageLightbox.test.tsx +7 -11
- package/src/components/link/Link.test.tsx +11 -13
- package/src/components/link/Link.tsx +20 -9
- 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 +10 -6
- package/src/components/navigation/NavigationSection.tsx +3 -4
- package/src/components/notification/Notification.test.tsx +3 -4
- 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 +7 -8
- 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 +27 -22
- 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 +8 -9
- package/src/components/thumbnail/Thumbnail.test.tsx +5 -29
- package/src/components/thumbnail/Thumbnail.tsx +11 -11
- package/src/components/tooltip/Tooltip.test.tsx +8 -14
- 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 +0 -4
- 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/renderButtonOrLink.tsx +16 -0
- package/src/utils/type/index.ts +0 -1
- package/utils/index.d.ts +1 -1
- package/utils/index.js +1 -1
- package/src/utils/react/RawClickable.test.tsx +0 -153
- package/src/utils/react/RawClickable.tsx +0 -65
- 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
|
-
|
|
18
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
213
|
-
const onClear =
|
|
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 =
|
|
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 =
|
|
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
|
|
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('
|
|
32
|
-
it('should
|
|
33
|
-
const onClick =
|
|
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
|
|
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
|
|
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
|
|
154
|
+
const isButton = !!forwardedProps.onClick;
|
|
155
|
+
const isClickable = !isAnyDisabled && (isButton || isLink);
|
|
156
156
|
|
|
157
|
-
|
|
157
|
+
let Wrapper: any = 'div';
|
|
158
158
|
const wrapperProps = { ...forwardedProps };
|
|
159
|
-
if (
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
-
|
|
17
|
-
|
|
15
|
+
jest.mock('@lumx/react/utils/browser/isFocusVisible');
|
|
16
|
+
jest.mock('@lumx/react/hooks/useId', () => ({ useId: () => ':r1:' }));
|
|
18
17
|
// Skip delays
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
|
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
|
|
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:
|
|
92
|
+
${'file input '} | ${{ fileInputProps: { onChange: jest.fn() } }}
|
|
93
93
|
`('Events $name', ({ props }) => {
|
|
94
|
-
const onClick =
|
|
94
|
+
const onClick = jest.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 = 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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
+
};
|
package/src/utils/type/index.ts
CHANGED
|
@@ -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):
|
|
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,
|
|
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
|