@lumx/react 3.18.2-alpha.1 → 3.18.2-alpha.3
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/index.js +10 -5
- package/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/button/ButtonRoot.tsx +1 -0
- package/src/components/thumbnail/Thumbnail.test.tsx +40 -3
- package/src/components/thumbnail/Thumbnail.tsx +6 -4
- package/src/utils/disabled/DisabledStateProvider.stories.tsx +5 -1
- package/src/utils/disabled/useDisableStateProps.test.tsx +74 -0
package/package.json
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
"url": "https://github.com/lumapps/design-system/issues"
|
|
7
7
|
},
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@lumx/core": "^3.18.2-alpha.
|
|
10
|
-
"@lumx/icons": "^3.18.2-alpha.
|
|
9
|
+
"@lumx/core": "^3.18.2-alpha.3",
|
|
10
|
+
"@lumx/icons": "^3.18.2-alpha.3",
|
|
11
11
|
"@popperjs/core": "^2.5.4",
|
|
12
12
|
"body-scroll-lock": "^3.1.5",
|
|
13
13
|
"classnames": "^2.3.2",
|
|
@@ -105,5 +105,5 @@
|
|
|
105
105
|
"build:storybook": "storybook build"
|
|
106
106
|
},
|
|
107
107
|
"sideEffects": false,
|
|
108
|
-
"version": "3.18.2-alpha.
|
|
108
|
+
"version": "3.18.2-alpha.3"
|
|
109
109
|
}
|
|
@@ -175,6 +175,7 @@ export const ButtonRoot = forwardRef<ButtonRootProps, HTMLButtonElement | HTMLAn
|
|
|
175
175
|
<button
|
|
176
176
|
{...forwardedProps}
|
|
177
177
|
{...disabledStateProps}
|
|
178
|
+
aria-disabled={isAnyDisabled}
|
|
178
179
|
aria-label={ariaLabel}
|
|
179
180
|
ref={ref as RefObject<HTMLButtonElement>}
|
|
180
181
|
className={buttonClassName}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
+
import { DisabledStateProvider } from '@lumx/react/utils';
|
|
3
4
|
import { commonTestsSuiteRTL, SetupRenderOptions } from '@lumx/react/testing/utils';
|
|
4
5
|
import { queryByClassName } from '@lumx/react/testing/utils/queries';
|
|
5
|
-
import { render } from '@testing-library/react';
|
|
6
|
+
import { fireEvent, render } from '@testing-library/react';
|
|
6
7
|
import { Thumbnail, ThumbnailProps } from './Thumbnail';
|
|
7
8
|
|
|
8
9
|
const CLASSNAME = Thumbnail.className as string;
|
|
9
10
|
|
|
10
11
|
const setup = (props: Partial<ThumbnailProps> = {}, { wrapper }: SetupRenderOptions = {}) => {
|
|
11
|
-
render(<Thumbnail {...(props as any)} />, { wrapper });
|
|
12
|
+
const { container } = render(<Thumbnail {...(props as any)} />, { wrapper });
|
|
12
13
|
const thumbnail = queryByClassName(document.body, CLASSNAME);
|
|
13
|
-
return { props, thumbnail };
|
|
14
|
+
return { props, thumbnail, container };
|
|
14
15
|
};
|
|
15
16
|
|
|
16
17
|
describe(`<${Thumbnail.displayName}>`, () => {
|
|
@@ -26,4 +27,40 @@ describe(`<${Thumbnail.displayName}>`, () => {
|
|
|
26
27
|
defaultTheme: 'light',
|
|
27
28
|
},
|
|
28
29
|
});
|
|
30
|
+
|
|
31
|
+
describe('disabled state', () => {
|
|
32
|
+
it('should not be clickable when disabled from context', () => {
|
|
33
|
+
const onClick = jest.fn();
|
|
34
|
+
const { thumbnail, container } = setup(
|
|
35
|
+
{ onClick, 'aria-label': 'thumbnail' },
|
|
36
|
+
{
|
|
37
|
+
wrapper: ({ children }) => (
|
|
38
|
+
<DisabledStateProvider state="disabled">{children}</DisabledStateProvider>
|
|
39
|
+
),
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
// Should render a div instead of a button.
|
|
44
|
+
expect(container.querySelector('button')).toBe(null);
|
|
45
|
+
expect(thumbnail?.tagName).toBe('DIV');
|
|
46
|
+
|
|
47
|
+
fireEvent.click(thumbnail as HTMLElement);
|
|
48
|
+
expect(onClick).not.toHaveBeenCalled();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should have no href when disabled from context', () => {
|
|
52
|
+
const { container, thumbnail } = setup(
|
|
53
|
+
{ linkAs: 'a', linkProps: { href: '#' }, 'aria-label': 'thumbnail' },
|
|
54
|
+
{
|
|
55
|
+
wrapper: ({ children }) => (
|
|
56
|
+
<DisabledStateProvider state="disabled">{children}</DisabledStateProvider>
|
|
57
|
+
),
|
|
58
|
+
},
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
// Should render a div instead of a link.
|
|
62
|
+
expect(container.querySelector('a')).toBe(null);
|
|
63
|
+
expect(thumbnail?.tagName).toBe('DIV');
|
|
64
|
+
});
|
|
65
|
+
});
|
|
29
66
|
});
|
|
@@ -21,6 +21,7 @@ import { useFocusPointStyle } from '@lumx/react/components/thumbnail/useFocusPoi
|
|
|
21
21
|
import { useTheme } from '@lumx/react/utils/theme/ThemeContext';
|
|
22
22
|
import { forwardRef } from '@lumx/react/utils/react/forwardRef';
|
|
23
23
|
|
|
24
|
+
import { useDisableStateProps } from '@lumx/react/utils/disabled';
|
|
24
25
|
import { FocusPoint, ThumbnailSize, ThumbnailVariant } from './types';
|
|
25
26
|
|
|
26
27
|
type ImgHTMLProps = ImgHTMLAttributes<HTMLImageElement>;
|
|
@@ -99,6 +100,7 @@ const DEFAULT_PROPS: Partial<ThumbnailProps> = {
|
|
|
99
100
|
* @return React element.
|
|
100
101
|
*/
|
|
101
102
|
export const Thumbnail = forwardRef<ThumbnailProps>((props, ref) => {
|
|
103
|
+
const { isAnyDisabled, otherProps } = useDisableStateProps(props);
|
|
102
104
|
const defaultTheme = useTheme() || Theme.light;
|
|
103
105
|
const {
|
|
104
106
|
align,
|
|
@@ -125,7 +127,7 @@ export const Thumbnail = forwardRef<ThumbnailProps>((props, ref) => {
|
|
|
125
127
|
linkProps,
|
|
126
128
|
linkAs,
|
|
127
129
|
...forwardedProps
|
|
128
|
-
} =
|
|
130
|
+
} = otherProps;
|
|
129
131
|
const [imgElement, setImgElement] = useState<HTMLImageElement>();
|
|
130
132
|
|
|
131
133
|
// Image loading state.
|
|
@@ -150,14 +152,14 @@ export const Thumbnail = forwardRef<ThumbnailProps>((props, ref) => {
|
|
|
150
152
|
|
|
151
153
|
const isLink = Boolean(linkProps?.href || linkAs);
|
|
152
154
|
const isButton = !!forwardedProps.onClick;
|
|
153
|
-
const isClickable = isButton || isLink;
|
|
155
|
+
const isClickable = !isAnyDisabled && (isButton || isLink);
|
|
154
156
|
|
|
155
157
|
let Wrapper: any = 'div';
|
|
156
158
|
const wrapperProps = { ...forwardedProps };
|
|
157
|
-
if (isLink) {
|
|
159
|
+
if (!isAnyDisabled && isLink) {
|
|
158
160
|
Wrapper = linkAs || 'a';
|
|
159
161
|
Object.assign(wrapperProps, linkProps);
|
|
160
|
-
} else if (isButton) {
|
|
162
|
+
} else if (!isAnyDisabled && isButton) {
|
|
161
163
|
Wrapper = 'button';
|
|
162
164
|
wrapperProps.type = forwardedProps.type || 'button';
|
|
163
165
|
wrapperProps['aria-label'] = forwardedProps['aria-label'] || alt;
|
|
@@ -12,11 +12,13 @@ import {
|
|
|
12
12
|
RadioButton,
|
|
13
13
|
Switch,
|
|
14
14
|
TextField,
|
|
15
|
+
Thumbnail,
|
|
15
16
|
} from '@lumx/react';
|
|
16
17
|
import { DisabledStateProvider } from '@lumx/react/utils';
|
|
17
18
|
import { getSelectArgType } from '@lumx/react/stories/controls/selectArgType';
|
|
18
19
|
import { disableArgTypes } from '@lumx/react/stories/utils/disableArgTypes';
|
|
19
20
|
import { mdiFoodApple } from '@lumx/icons';
|
|
21
|
+
import { LANDSCAPE_IMAGES } from '@lumx/react/stories/controls/image';
|
|
20
22
|
|
|
21
23
|
export default {
|
|
22
24
|
title: 'LumX components/DisabledStateProvider',
|
|
@@ -71,6 +73,7 @@ export const AllComponents = {
|
|
|
71
73
|
<Checkbox label="Checkbox" />
|
|
72
74
|
<Chip onClick={() => {}}>Chip</Chip>
|
|
73
75
|
<DatePickerField
|
|
76
|
+
label="Date picker field"
|
|
74
77
|
nextButtonProps={{ label: 'Next' }}
|
|
75
78
|
previousButtonProps={{ label: 'Previous' }}
|
|
76
79
|
value={new Date()}
|
|
@@ -82,7 +85,8 @@ export const AllComponents = {
|
|
|
82
85
|
</List>
|
|
83
86
|
<RadioButton label="Radio button" />
|
|
84
87
|
<Switch>Switch</Switch>
|
|
85
|
-
<TextField onChange={() => {}} value="" />
|
|
88
|
+
<TextField label="texfield" onChange={() => {}} value="" />
|
|
89
|
+
<Thumbnail alt="Thumbnail" image={LANDSCAPE_IMAGES.landscape1s200} onClick={() => {}} />
|
|
86
90
|
</DisabledStateProvider>
|
|
87
91
|
),
|
|
88
92
|
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { fireEvent, render } from '@testing-library/react';
|
|
4
|
+
import { DisabledStateProvider } from './DisabledStateContext';
|
|
5
|
+
import { useDisableStateProps } from './useDisableStateProps';
|
|
6
|
+
|
|
7
|
+
describe(useDisableStateProps.name, () => {
|
|
8
|
+
const setup = (props: any, wrapper?: React.ComponentType) => {
|
|
9
|
+
const testId = 'test-container';
|
|
10
|
+
const Component = () => {
|
|
11
|
+
const { disabledStateProps, otherProps } = useDisableStateProps(props);
|
|
12
|
+
return <div data-testid={testId} {...otherProps} {...disabledStateProps} />;
|
|
13
|
+
};
|
|
14
|
+
const renderResult = render(wrapper ? React.createElement(wrapper, undefined, <Component />) : <Component />);
|
|
15
|
+
return { ...renderResult, element: renderResult.getByTestId(testId) };
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
it('should not be disabled by default', () => {
|
|
19
|
+
const { element } = setup({});
|
|
20
|
+
expect(element).not.toHaveAttribute('disabled');
|
|
21
|
+
expect(element).toHaveAttribute('aria-disabled', 'false');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should be disabled with `disabled` prop', () => {
|
|
25
|
+
const { element } = setup({ disabled: true });
|
|
26
|
+
expect(element).toHaveAttribute('disabled');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should be disabled with `isDisabled` prop', () => {
|
|
30
|
+
const { element } = setup({ isDisabled: true });
|
|
31
|
+
expect(element).toHaveAttribute('disabled');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should be disabled with `aria-disabled` prop', () => {
|
|
35
|
+
const { element } = setup({ 'aria-disabled': true });
|
|
36
|
+
expect(element).toHaveAttribute('aria-disabled', 'true');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should be disabled with `aria-disabled` string prop', () => {
|
|
40
|
+
const { element } = setup({ 'aria-disabled': 'true' });
|
|
41
|
+
expect(element).toHaveAttribute('aria-disabled', 'true');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should be disabled with context', () => {
|
|
45
|
+
const wrapper = ({ children }: any) => (
|
|
46
|
+
<DisabledStateProvider state="disabled">{children}</DisabledStateProvider>
|
|
47
|
+
);
|
|
48
|
+
const { element } = setup({}, wrapper);
|
|
49
|
+
expect(element).toHaveAttribute('disabled');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should prioritize context', () => {
|
|
53
|
+
const wrapper = ({ children }: any) => (
|
|
54
|
+
<DisabledStateProvider state="disabled">{children}</DisabledStateProvider>
|
|
55
|
+
);
|
|
56
|
+
const { element } = setup({ disabled: false }, wrapper);
|
|
57
|
+
expect(element).toHaveAttribute('disabled');
|
|
58
|
+
expect(element).toHaveAttribute('aria-disabled', 'false');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should forward onClick when not disabled', () => {
|
|
62
|
+
const onClick = jest.fn();
|
|
63
|
+
const { element } = setup({ onClick });
|
|
64
|
+
fireEvent.click(element);
|
|
65
|
+
expect(onClick).toHaveBeenCalled();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should not forward onClick when disabled', () => {
|
|
69
|
+
const onClick = jest.fn();
|
|
70
|
+
const { element } = setup({ disabled: true, onClick });
|
|
71
|
+
fireEvent.click(element);
|
|
72
|
+
expect(onClick).not.toHaveBeenCalled();
|
|
73
|
+
});
|
|
74
|
+
});
|