@lumx/react 2.1.2 → 2.1.6-alpha.0
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/esm/_internal/Avatar2.js +5 -1
- package/esm/_internal/Avatar2.js.map +1 -1
- package/esm/_internal/ClickAwayProvider.js +1 -1
- package/esm/_internal/Dialog2.js +13 -8
- package/esm/_internal/Dialog2.js.map +1 -1
- package/esm/_internal/DragHandle.js +1 -1
- package/esm/_internal/DragHandle.js.map +1 -1
- package/esm/_internal/Flag2.js +1 -3
- package/esm/_internal/Flag2.js.map +1 -1
- package/esm/_internal/List2.js +16 -9
- package/esm/_internal/List2.js.map +1 -1
- package/esm/_internal/Message2.js +2 -2
- package/esm/_internal/Message2.js.map +1 -1
- package/esm/_internal/SlideshowControls.js +3 -3
- package/esm/_internal/SlideshowControls.js.map +1 -1
- package/esm/_internal/Thumbnail2.js +29 -34
- package/esm/_internal/Thumbnail2.js.map +1 -1
- package/esm/_internal/Tooltip2.js +1 -1
- package/esm/_internal/UserBlock.js +44 -14
- package/esm/_internal/UserBlock.js.map +1 -1
- package/esm/_internal/getRootClassName.js +17 -1
- package/esm/_internal/getRootClassName.js.map +1 -1
- package/esm/_internal/user-block.js +1 -0
- package/esm/_internal/user-block.js.map +1 -1
- package/package.json +16 -17
- package/src/components/avatar/Avatar.tsx +8 -0
- package/src/components/dialog/Dialog.stories.tsx +44 -2
- package/src/components/dialog/Dialog.tsx +15 -11
- package/src/components/dialog/__snapshots__/Dialog.test.tsx.snap +76 -0
- package/src/components/drag-handle/DragHandle.tsx +5 -1
- package/src/components/flag/Flag.test.tsx +1 -2
- package/src/components/flag/Flag.tsx +2 -10
- package/src/components/flag/__snapshots__/Flag.test.tsx.snap +0 -15
- package/src/components/list/List.stories.tsx +7 -1
- package/src/components/list/ListItem.stories.tsx +28 -3
- package/src/components/list/ListItem.tsx +25 -7
- package/src/components/list/__snapshots__/List.test.tsx.snap +23 -3
- package/src/components/list/__snapshots__/ListItem.test.tsx.snap +84 -11
- package/src/components/list/useInteractiveList.tsx +1 -1
- package/src/components/message/Message.tsx +2 -2
- package/src/components/slideshow/useKeyNavigate.ts +2 -2
- package/src/components/thumbnail/Thumbnail.stories.tsx +21 -0
- package/src/components/thumbnail/Thumbnail.test.tsx +20 -2
- package/src/components/thumbnail/Thumbnail.tsx +40 -15
- package/src/components/thumbnail/__snapshots__/Thumbnail.test.tsx.snap +53 -6
- package/src/components/user-block/UserBlock.stories.tsx +27 -4
- package/src/components/user-block/UserBlock.tsx +40 -16
- package/src/components/user-block/__snapshots__/UserBlock.test.tsx.snap +244 -145
- package/src/utils/MaterialThemeSwitcher/MaterialThemeSwitcher.tsx +54 -0
- package/src/utils/MaterialThemeSwitcher/index.ts +1 -0
- package/types.d.ts +14 -0
|
@@ -2,12 +2,37 @@ import React from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { Size } from '@lumx/react';
|
|
4
4
|
import { select, text } from '@storybook/addon-knobs';
|
|
5
|
+
import { action } from '@storybook/addon-actions';
|
|
5
6
|
|
|
6
7
|
import { ListItem } from './ListItem';
|
|
7
8
|
|
|
8
9
|
export default { title: 'LumX components/list/ListItem' };
|
|
9
10
|
|
|
10
|
-
export const
|
|
11
|
+
export const NonClickable = ({ theme }: any) => <ListItem theme={theme}>{text('text', 'Text')}</ListItem>;
|
|
12
|
+
|
|
13
|
+
export const Link = ({ theme }: any) => (
|
|
14
|
+
<ListItem theme={theme} linkProps={{ href: '#' }}>
|
|
15
|
+
{text('text', 'Text')}
|
|
16
|
+
</ListItem>
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
export const Button = ({ theme }: any) => (
|
|
20
|
+
<ListItem theme={theme} onItemSelected={action('onItemSelected')}>
|
|
21
|
+
{text('text', 'Text')}
|
|
22
|
+
</ListItem>
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
export const LinkDisabled = ({ theme }: any) => (
|
|
26
|
+
<ListItem theme={theme} linkProps={{ href: '#' }} isDisabled>
|
|
27
|
+
{text('text', 'Text')}
|
|
28
|
+
</ListItem>
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
export const ButtonDisabled = ({ theme }: any) => (
|
|
32
|
+
<ListItem theme={theme} onItemSelected={action('onItemSelected')} isDisabled>
|
|
33
|
+
{text('text', 'Text')}
|
|
34
|
+
</ListItem>
|
|
35
|
+
);
|
|
11
36
|
|
|
12
37
|
export const Selected = ({ theme }: any) => (
|
|
13
38
|
<ListItem theme={theme} linkProps={{ href: '#' }} isSelected>
|
|
@@ -28,10 +53,10 @@ export const Sizes = ({ theme }: any) => (
|
|
|
28
53
|
);
|
|
29
54
|
|
|
30
55
|
const CustomLink: React.FC = ({ children, ...props }) =>
|
|
31
|
-
React.createElement('a', { ...props, style: { color: 'red' } }, children);
|
|
56
|
+
React.createElement('a', { ...props, style: { color: 'red' }, href: 'http://google.com' }, children);
|
|
32
57
|
|
|
33
58
|
export const WithCustomLink = ({ theme }: any) => (
|
|
34
|
-
<ListItem theme={theme} linkAs={CustomLink}
|
|
59
|
+
<ListItem theme={theme} linkAs={CustomLink}>
|
|
35
60
|
My custom link
|
|
36
61
|
</ListItem>
|
|
37
62
|
);
|
|
@@ -4,7 +4,14 @@ import classNames from 'classnames';
|
|
|
4
4
|
import isEmpty from 'lodash/isEmpty';
|
|
5
5
|
|
|
6
6
|
import { ListProps, Size } from '@lumx/react';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
Comp,
|
|
9
|
+
GenericProps,
|
|
10
|
+
getRootClassName,
|
|
11
|
+
handleBasicClasses,
|
|
12
|
+
onEnterPressed,
|
|
13
|
+
onButtonPressed,
|
|
14
|
+
} from '@lumx/react/utils';
|
|
8
15
|
import { renderLink } from '@lumx/react/utils/renderLink';
|
|
9
16
|
|
|
10
17
|
export type ListItemSize = Extract<Size, 'tiny' | 'regular' | 'big' | 'huge'>;
|
|
@@ -23,6 +30,8 @@ export interface ListItemProps extends GenericProps {
|
|
|
23
30
|
isHighlighted?: boolean;
|
|
24
31
|
/** Whether the component is selected or not. */
|
|
25
32
|
isSelected?: boolean;
|
|
33
|
+
/** Whether link/button is disabled or not. */
|
|
34
|
+
isDisabled?: boolean;
|
|
26
35
|
/** Reference to the <li> element. */
|
|
27
36
|
listItemRef?: Ref<HTMLLIElement>;
|
|
28
37
|
/** Custom react component for the link (can be used to inject react router Link). */
|
|
@@ -33,6 +42,7 @@ export interface ListItemProps extends GenericProps {
|
|
|
33
42
|
linkRef?: Ref<HTMLAnchorElement>;
|
|
34
43
|
/** Size variant. */
|
|
35
44
|
size?: ListItemSize;
|
|
45
|
+
|
|
36
46
|
/** On selected callback. */
|
|
37
47
|
onItemSelected?(evt: SyntheticEvent): void;
|
|
38
48
|
}
|
|
@@ -77,6 +87,7 @@ export const ListItem: Comp<ListItemProps, HTMLLIElement> = forwardRef((props, r
|
|
|
77
87
|
className,
|
|
78
88
|
isHighlighted,
|
|
79
89
|
isSelected,
|
|
90
|
+
isDisabled,
|
|
80
91
|
linkAs,
|
|
81
92
|
linkProps = {},
|
|
82
93
|
linkRef,
|
|
@@ -84,9 +95,13 @@ export const ListItem: Comp<ListItemProps, HTMLLIElement> = forwardRef((props, r
|
|
|
84
95
|
size,
|
|
85
96
|
...forwardedProps
|
|
86
97
|
} = props;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
98
|
+
|
|
99
|
+
const role = linkAs || linkProps.href ? 'link' : 'button';
|
|
100
|
+
const onKeyDown = useMemo(() => {
|
|
101
|
+
if (onItemSelected && role === 'link') return onEnterPressed(onItemSelected as any);
|
|
102
|
+
if (onItemSelected && role === 'button') return onButtonPressed(onItemSelected as any);
|
|
103
|
+
return undefined;
|
|
104
|
+
}, [role, onItemSelected]);
|
|
90
105
|
|
|
91
106
|
const content = (
|
|
92
107
|
<>
|
|
@@ -113,17 +128,20 @@ export const ListItem: Comp<ListItemProps, HTMLLIElement> = forwardRef((props, r
|
|
|
113
128
|
renderLink(
|
|
114
129
|
{
|
|
115
130
|
linkAs,
|
|
116
|
-
tabIndex: 0,
|
|
117
|
-
role
|
|
131
|
+
tabIndex: !isDisabled && role === 'button' ? 0 : undefined,
|
|
132
|
+
role,
|
|
133
|
+
'aria-disabled': isDisabled,
|
|
118
134
|
...linkProps,
|
|
135
|
+
href: isDisabled ? undefined : linkProps.href,
|
|
119
136
|
className: classNames(
|
|
120
137
|
handleBasicClasses({
|
|
121
138
|
prefix: `${CLASSNAME}__link`,
|
|
122
139
|
isHighlighted,
|
|
123
140
|
isSelected,
|
|
141
|
+
isDisabled,
|
|
124
142
|
}),
|
|
125
143
|
),
|
|
126
|
-
onClick: onItemSelected,
|
|
144
|
+
onClick: isDisabled ? undefined : onItemSelected,
|
|
127
145
|
onKeyDown,
|
|
128
146
|
ref: linkRef,
|
|
129
147
|
},
|
|
@@ -129,12 +129,32 @@ exports[`<List> Snapshots and structure should render story 'KeyboardNavigation'
|
|
|
129
129
|
>
|
|
130
130
|
Header
|
|
131
131
|
</ListSubheader>
|
|
132
|
-
<
|
|
132
|
+
<ListItem
|
|
133
|
+
isDisabled={true}
|
|
133
134
|
key=".4"
|
|
135
|
+
linkProps={
|
|
136
|
+
Object {
|
|
137
|
+
"href": "#",
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
size="regular"
|
|
141
|
+
>
|
|
142
|
+
Disabled link item
|
|
143
|
+
</ListItem>
|
|
144
|
+
<ListItem
|
|
145
|
+
isDisabled={true}
|
|
146
|
+
key=".5"
|
|
147
|
+
onItemSelected={[Function]}
|
|
148
|
+
size="regular"
|
|
149
|
+
>
|
|
150
|
+
Disabled button item
|
|
151
|
+
</ListItem>
|
|
152
|
+
<CustomListItem
|
|
153
|
+
key=".6"
|
|
134
154
|
/>
|
|
135
155
|
<ListItem
|
|
136
156
|
isHighlighted={false}
|
|
137
|
-
key=".
|
|
157
|
+
key=".7:$1"
|
|
138
158
|
linkProps={
|
|
139
159
|
Object {
|
|
140
160
|
"href": "#",
|
|
@@ -147,7 +167,7 @@ exports[`<List> Snapshots and structure should render story 'KeyboardNavigation'
|
|
|
147
167
|
onMouseUp={[Function]}
|
|
148
168
|
size="regular"
|
|
149
169
|
>
|
|
150
|
-
Link item
|
|
170
|
+
Link item 4
|
|
151
171
|
</ListItem>
|
|
152
172
|
</ul>
|
|
153
173
|
`;
|
|
@@ -1,18 +1,41 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
|
-
exports[`<ListItem> Snapshots and structure should render story '
|
|
3
|
+
exports[`<ListItem> Snapshots and structure should render story 'Button' 1`] = `
|
|
4
4
|
<li
|
|
5
5
|
className="lumx-list-item lumx-list-item--size-regular"
|
|
6
6
|
>
|
|
7
|
-
<
|
|
8
|
-
className="lumx-list-
|
|
7
|
+
<a
|
|
8
|
+
className="lumx-list-item__link"
|
|
9
|
+
onClick={[Function]}
|
|
10
|
+
onKeyDown={[Function]}
|
|
11
|
+
role="button"
|
|
12
|
+
tabIndex={0}
|
|
9
13
|
>
|
|
10
14
|
<div
|
|
11
15
|
className="lumx-list-item__content"
|
|
12
16
|
>
|
|
13
17
|
Text
|
|
14
18
|
</div>
|
|
15
|
-
</
|
|
19
|
+
</a>
|
|
20
|
+
</li>
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
exports[`<ListItem> Snapshots and structure should render story 'ButtonDisabled' 1`] = `
|
|
24
|
+
<li
|
|
25
|
+
className="lumx-list-item lumx-list-item--size-regular"
|
|
26
|
+
>
|
|
27
|
+
<a
|
|
28
|
+
aria-disabled={true}
|
|
29
|
+
className="lumx-list-item__link lumx-list-item__link--is-disabled"
|
|
30
|
+
onKeyDown={[Function]}
|
|
31
|
+
role="button"
|
|
32
|
+
>
|
|
33
|
+
<div
|
|
34
|
+
className="lumx-list-item__content"
|
|
35
|
+
>
|
|
36
|
+
Text
|
|
37
|
+
</div>
|
|
38
|
+
</a>
|
|
16
39
|
</li>
|
|
17
40
|
`;
|
|
18
41
|
|
|
@@ -23,7 +46,7 @@ exports[`<ListItem> Snapshots and structure should render story 'Highlighted' 1`
|
|
|
23
46
|
<a
|
|
24
47
|
className="lumx-list-item__link lumx-list-item__link--is-highlighted"
|
|
25
48
|
href="#"
|
|
26
|
-
|
|
49
|
+
role="link"
|
|
27
50
|
>
|
|
28
51
|
<div
|
|
29
52
|
className="lumx-list-item__content"
|
|
@@ -34,6 +57,58 @@ exports[`<ListItem> Snapshots and structure should render story 'Highlighted' 1`
|
|
|
34
57
|
</li>
|
|
35
58
|
`;
|
|
36
59
|
|
|
60
|
+
exports[`<ListItem> Snapshots and structure should render story 'Link' 1`] = `
|
|
61
|
+
<li
|
|
62
|
+
className="lumx-list-item lumx-list-item--size-regular"
|
|
63
|
+
>
|
|
64
|
+
<a
|
|
65
|
+
className="lumx-list-item__link"
|
|
66
|
+
href="#"
|
|
67
|
+
role="link"
|
|
68
|
+
>
|
|
69
|
+
<div
|
|
70
|
+
className="lumx-list-item__content"
|
|
71
|
+
>
|
|
72
|
+
Text
|
|
73
|
+
</div>
|
|
74
|
+
</a>
|
|
75
|
+
</li>
|
|
76
|
+
`;
|
|
77
|
+
|
|
78
|
+
exports[`<ListItem> Snapshots and structure should render story 'LinkDisabled' 1`] = `
|
|
79
|
+
<li
|
|
80
|
+
className="lumx-list-item lumx-list-item--size-regular"
|
|
81
|
+
>
|
|
82
|
+
<a
|
|
83
|
+
aria-disabled={true}
|
|
84
|
+
className="lumx-list-item__link lumx-list-item__link--is-disabled"
|
|
85
|
+
role="link"
|
|
86
|
+
>
|
|
87
|
+
<div
|
|
88
|
+
className="lumx-list-item__content"
|
|
89
|
+
>
|
|
90
|
+
Text
|
|
91
|
+
</div>
|
|
92
|
+
</a>
|
|
93
|
+
</li>
|
|
94
|
+
`;
|
|
95
|
+
|
|
96
|
+
exports[`<ListItem> Snapshots and structure should render story 'NonClickable' 1`] = `
|
|
97
|
+
<li
|
|
98
|
+
className="lumx-list-item lumx-list-item--size-regular"
|
|
99
|
+
>
|
|
100
|
+
<div
|
|
101
|
+
className="lumx-list-item__wrapper"
|
|
102
|
+
>
|
|
103
|
+
<div
|
|
104
|
+
className="lumx-list-item__content"
|
|
105
|
+
>
|
|
106
|
+
Text
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
</li>
|
|
110
|
+
`;
|
|
111
|
+
|
|
37
112
|
exports[`<ListItem> Snapshots and structure should render story 'Selected' 1`] = `
|
|
38
113
|
<li
|
|
39
114
|
className="lumx-list-item lumx-list-item--size-regular"
|
|
@@ -41,7 +116,7 @@ exports[`<ListItem> Snapshots and structure should render story 'Selected' 1`] =
|
|
|
41
116
|
<a
|
|
42
117
|
className="lumx-list-item__link lumx-list-item__link--is-selected"
|
|
43
118
|
href="#"
|
|
44
|
-
|
|
119
|
+
role="link"
|
|
45
120
|
>
|
|
46
121
|
<div
|
|
47
122
|
className="lumx-list-item__content"
|
|
@@ -72,16 +147,14 @@ exports[`<ListItem> Snapshots and structure should render story 'WithCustomLink'
|
|
|
72
147
|
<li
|
|
73
148
|
className="lumx-list-item lumx-list-item--size-regular"
|
|
74
149
|
>
|
|
75
|
-
<
|
|
76
|
-
className="lumx-list-
|
|
77
|
-
href="http://google.com"
|
|
78
|
-
tabIndex={0}
|
|
150
|
+
<div
|
|
151
|
+
className="lumx-list-item__wrapper"
|
|
79
152
|
>
|
|
80
153
|
<div
|
|
81
154
|
className="lumx-list-item__content"
|
|
82
155
|
>
|
|
83
156
|
My custom link
|
|
84
157
|
</div>
|
|
85
|
-
</
|
|
158
|
+
</div>
|
|
86
159
|
</li>
|
|
87
160
|
`;
|
|
@@ -75,7 +75,7 @@ function onKeyboardFocus(props: any, handler: (evt: FocusEvent) => void) {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
const isNavigableItem = (node: ReactNode): node is ReactElement => {
|
|
78
|
-
return isComponent('ListItem')(node) && isClickable(node.props);
|
|
78
|
+
return isComponent('ListItem')(node) && isClickable(node.props) && !node.props.isDisabled;
|
|
79
79
|
};
|
|
80
80
|
|
|
81
81
|
/**
|
|
@@ -62,8 +62,8 @@ export const Message: Comp<MessageProps, HTMLDivElement> = forwardRef((props, re
|
|
|
62
62
|
)}
|
|
63
63
|
{...forwardedProps}
|
|
64
64
|
>
|
|
65
|
-
{(customIcon || icon) && <Icon className=
|
|
66
|
-
<div className=
|
|
65
|
+
{(customIcon || icon) && <Icon className={`${CLASSNAME}__icon`} icon={customIcon || icon} size={Size.xs} />}
|
|
66
|
+
<div className={`${CLASSNAME}__text`}>{children}</div>
|
|
67
67
|
</div>
|
|
68
68
|
);
|
|
69
69
|
});
|
|
@@ -9,9 +9,9 @@ export function useKeyNavigate(element?: HTMLElement | null, onNext?: () => void
|
|
|
9
9
|
const onKeyNavigate = (evt: KeyboardEvent) => {
|
|
10
10
|
let callback;
|
|
11
11
|
if (evt?.key === 'ArrowRight') {
|
|
12
|
-
callback = onPrevious;
|
|
13
|
-
} else if (evt?.key === 'ArrowLeft') {
|
|
14
12
|
callback = onNext;
|
|
13
|
+
} else if (evt?.key === 'ArrowLeft') {
|
|
14
|
+
callback = onPrevious;
|
|
15
15
|
}
|
|
16
16
|
if (!callback) return;
|
|
17
17
|
|
|
@@ -18,6 +18,7 @@ import { boolean, select, text } from '@storybook/addon-knobs';
|
|
|
18
18
|
import { enumKnob } from '@lumx/react/stories/knobs/enumKnob';
|
|
19
19
|
import { focusKnob } from '@lumx/react/stories/knobs/focusKnob';
|
|
20
20
|
import { sizeKnob } from '@lumx/react/stories/knobs/sizeKnob';
|
|
21
|
+
import classNames from 'classnames';
|
|
21
22
|
|
|
22
23
|
export default { title: 'LumX components/thumbnail/Thumbnail' };
|
|
23
24
|
|
|
@@ -25,6 +26,26 @@ export const Default = () => <Thumbnail alt="Image alt text" image={imageKnob()}
|
|
|
25
26
|
|
|
26
27
|
export const Clickable = () => <Thumbnail alt="Click me" image={imageKnob()} size={Size.xxl} onClick={console.log} />;
|
|
27
28
|
|
|
29
|
+
export const ClickableLink = () => (
|
|
30
|
+
<Thumbnail alt="Click me" image={imageKnob()} size={Size.xxl} linkProps={{ href: 'https://google.fr' }} />
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const CustomLinkComponent = (props: any) => (
|
|
34
|
+
<a {...props} className={classNames('custom-link-component', props.className)}>
|
|
35
|
+
{props.children}
|
|
36
|
+
</a>
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
export const ClickableCustomLink = () => (
|
|
40
|
+
<Thumbnail
|
|
41
|
+
alt="Click me"
|
|
42
|
+
image={imageKnob()}
|
|
43
|
+
size={Size.xxl}
|
|
44
|
+
linkAs={CustomLinkComponent}
|
|
45
|
+
linkProps={{ href: 'https://google.fr', className: 'custom-class-name' }}
|
|
46
|
+
/>
|
|
47
|
+
);
|
|
48
|
+
|
|
28
49
|
export const DefaultFallback = () => <Thumbnail alt="foo" image="foo" />;
|
|
29
50
|
|
|
30
51
|
export const IconFallback = () => <Thumbnail alt="foo" image="foo" fallback={mdiAbTesting} />;
|
|
@@ -5,7 +5,16 @@ import 'jest-enzyme';
|
|
|
5
5
|
import { commonTestsSuite, itShouldRenderStories } from '@lumx/react/testing/utils';
|
|
6
6
|
|
|
7
7
|
import { Thumbnail, ThumbnailProps } from './Thumbnail';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
Clickable,
|
|
10
|
+
ClickableCustomLink,
|
|
11
|
+
ClickableLink,
|
|
12
|
+
CustomFallback,
|
|
13
|
+
Default,
|
|
14
|
+
DefaultFallback,
|
|
15
|
+
IconFallback,
|
|
16
|
+
WithBadge,
|
|
17
|
+
} from './Thumbnail.stories';
|
|
9
18
|
|
|
10
19
|
const CLASSNAME = Thumbnail.className as string;
|
|
11
20
|
|
|
@@ -22,7 +31,16 @@ describe(`<${Thumbnail.displayName}>`, () => {
|
|
|
22
31
|
// 1. Test render via snapshot.
|
|
23
32
|
describe('Snapshots and structure', () => {
|
|
24
33
|
itShouldRenderStories(
|
|
25
|
-
{
|
|
34
|
+
{
|
|
35
|
+
Default,
|
|
36
|
+
Clickable,
|
|
37
|
+
ClickableLink,
|
|
38
|
+
ClickableCustomLink,
|
|
39
|
+
DefaultFallback,
|
|
40
|
+
CustomFallback,
|
|
41
|
+
IconFallback,
|
|
42
|
+
WithBadge,
|
|
43
|
+
},
|
|
26
44
|
Thumbnail,
|
|
27
45
|
);
|
|
28
46
|
});
|
|
@@ -20,7 +20,6 @@ import { isInternetExplorer } from '@lumx/react/utils/isInternetExplorer';
|
|
|
20
20
|
import { mergeRefs } from '@lumx/react/utils/mergeRefs';
|
|
21
21
|
import { useFocusPoint } from '@lumx/react/components/thumbnail/useFocusPoint';
|
|
22
22
|
import { useImageLoad } from '@lumx/react/components/thumbnail/useImageLoad';
|
|
23
|
-
import { useClickable } from '@lumx/react/components/thumbnail/useClickable';
|
|
24
23
|
import { FocusPoint, ThumbnailSize, ThumbnailVariant } from './types';
|
|
25
24
|
|
|
26
25
|
type ImgHTMLProps = ImgHTMLAttributes<HTMLImageElement>;
|
|
@@ -63,6 +62,10 @@ export interface ThumbnailProps extends GenericProps {
|
|
|
63
62
|
theme?: Theme;
|
|
64
63
|
/** Variant of the component. */
|
|
65
64
|
variant?: ThumbnailVariant;
|
|
65
|
+
/** Props to pass to the link wrapping the thumbnail. */
|
|
66
|
+
linkProps?: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>;
|
|
67
|
+
/** Custom react component for the link (can be used to inject react router Link). */
|
|
68
|
+
linkAs?: 'a' | any;
|
|
66
69
|
}
|
|
67
70
|
|
|
68
71
|
/**
|
|
@@ -109,6 +112,8 @@ export const Thumbnail: Comp<ThumbnailProps> = forwardRef((props, ref) => {
|
|
|
109
112
|
size,
|
|
110
113
|
theme,
|
|
111
114
|
variant,
|
|
115
|
+
linkProps,
|
|
116
|
+
linkAs,
|
|
112
117
|
...forwardedProps
|
|
113
118
|
} = props;
|
|
114
119
|
const imgRef = useRef<HTMLImageElement>(null);
|
|
@@ -119,24 +124,44 @@ export const Thumbnail: Comp<ThumbnailProps> = forwardRef((props, ref) => {
|
|
|
119
124
|
const isLoading = loadingState === 'isLoading';
|
|
120
125
|
|
|
121
126
|
const [wrapper, setWrapper] = useState<HTMLElement>();
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
127
|
+
|
|
128
|
+
const isLink = Boolean(linkProps?.href || linkAs);
|
|
129
|
+
const isButton = !!forwardedProps.onClick;
|
|
130
|
+
const isClickable = isButton || isLink;
|
|
131
|
+
|
|
132
|
+
let Wrapper: any = 'div';
|
|
133
|
+
const wrapperProps = { ...forwardedProps };
|
|
134
|
+
if (isLink) {
|
|
135
|
+
Wrapper = linkAs || 'a';
|
|
136
|
+
Object.assign(wrapperProps, linkProps);
|
|
137
|
+
} else if (isButton) {
|
|
138
|
+
Wrapper = 'button';
|
|
139
|
+
}
|
|
134
140
|
|
|
135
141
|
// Update img style according to focus point and aspect ratio.
|
|
136
142
|
const style = useFocusPoint({ image, focusPoint, aspectRatio, imgRef, loadingState, wrapper });
|
|
137
143
|
|
|
138
144
|
return (
|
|
139
|
-
<
|
|
145
|
+
<Wrapper
|
|
146
|
+
{...wrapperProps}
|
|
147
|
+
ref={mergeRefs(setWrapper, ref) as any}
|
|
148
|
+
className={classNames(
|
|
149
|
+
linkProps?.className,
|
|
150
|
+
className,
|
|
151
|
+
handleBasicClasses({
|
|
152
|
+
align,
|
|
153
|
+
aspectRatio,
|
|
154
|
+
prefix: CLASSNAME,
|
|
155
|
+
size,
|
|
156
|
+
theme,
|
|
157
|
+
variant,
|
|
158
|
+
isClickable,
|
|
159
|
+
hasBadge: !!badge,
|
|
160
|
+
}),
|
|
161
|
+
isLoading && wrapper?.getBoundingClientRect()?.height && 'lumx-color-background-dark-L6',
|
|
162
|
+
fillHeight && `${CLASSNAME}--fill-height`,
|
|
163
|
+
)}
|
|
164
|
+
>
|
|
140
165
|
<div
|
|
141
166
|
className={`${CLASSNAME}__background`}
|
|
142
167
|
style={{
|
|
@@ -169,7 +194,7 @@ export const Thumbnail: Comp<ThumbnailProps> = forwardRef((props, ref) => {
|
|
|
169
194
|
))}
|
|
170
195
|
{badge &&
|
|
171
196
|
React.cloneElement(badge, { className: classNames(`${CLASSNAME}__badge`, badge.props.className) })}
|
|
172
|
-
</
|
|
197
|
+
</Wrapper>
|
|
173
198
|
);
|
|
174
199
|
});
|
|
175
200
|
Thumbnail.displayName = COMPONENT_NAME;
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
3
|
exports[`<Thumbnail> Snapshots and structure should render story 'Clickable' 1`] = `
|
|
4
|
-
<
|
|
5
|
-
className="lumx-thumbnail lumx-thumbnail--size-xxl lumx-thumbnail--theme-light"
|
|
4
|
+
<button
|
|
5
|
+
className="lumx-thumbnail lumx-thumbnail--size-xxl lumx-thumbnail--theme-light lumx-thumbnail--is-clickable"
|
|
6
6
|
onClick={[Function]}
|
|
7
|
-
onKeyPress={[Function]}
|
|
8
|
-
role="button"
|
|
9
|
-
tabIndex={0}
|
|
10
7
|
>
|
|
11
8
|
<div
|
|
12
9
|
className="lumx-thumbnail__background"
|
|
@@ -25,7 +22,57 @@ exports[`<Thumbnail> Snapshots and structure should render story 'Clickable' 1`]
|
|
|
25
22
|
style={Object {}}
|
|
26
23
|
/>
|
|
27
24
|
</div>
|
|
28
|
-
</
|
|
25
|
+
</button>
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
exports[`<Thumbnail> Snapshots and structure should render story 'ClickableCustomLink' 1`] = `
|
|
29
|
+
<CustomLinkComponent
|
|
30
|
+
className="custom-class-name lumx-thumbnail lumx-thumbnail--size-xxl lumx-thumbnail--theme-light lumx-thumbnail--is-clickable"
|
|
31
|
+
href="https://google.fr"
|
|
32
|
+
>
|
|
33
|
+
<div
|
|
34
|
+
className="lumx-thumbnail__background"
|
|
35
|
+
style={
|
|
36
|
+
Object {
|
|
37
|
+
"display": undefined,
|
|
38
|
+
"visibility": "hidden",
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
>
|
|
42
|
+
<img
|
|
43
|
+
alt="Click me"
|
|
44
|
+
className="lumx-thumbnail__image"
|
|
45
|
+
loading="lazy"
|
|
46
|
+
src="landscape1.jpg"
|
|
47
|
+
style={Object {}}
|
|
48
|
+
/>
|
|
49
|
+
</div>
|
|
50
|
+
</CustomLinkComponent>
|
|
51
|
+
`;
|
|
52
|
+
|
|
53
|
+
exports[`<Thumbnail> Snapshots and structure should render story 'ClickableLink' 1`] = `
|
|
54
|
+
<a
|
|
55
|
+
className="lumx-thumbnail lumx-thumbnail--size-xxl lumx-thumbnail--theme-light lumx-thumbnail--is-clickable"
|
|
56
|
+
href="https://google.fr"
|
|
57
|
+
>
|
|
58
|
+
<div
|
|
59
|
+
className="lumx-thumbnail__background"
|
|
60
|
+
style={
|
|
61
|
+
Object {
|
|
62
|
+
"display": undefined,
|
|
63
|
+
"visibility": "hidden",
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
>
|
|
67
|
+
<img
|
|
68
|
+
alt="Click me"
|
|
69
|
+
className="lumx-thumbnail__image"
|
|
70
|
+
loading="lazy"
|
|
71
|
+
src="landscape1.jpg"
|
|
72
|
+
style={Object {}}
|
|
73
|
+
/>
|
|
74
|
+
</div>
|
|
75
|
+
</a>
|
|
29
76
|
`;
|
|
30
77
|
|
|
31
78
|
exports[`<Thumbnail> Snapshots and structure should render story 'CustomFallback' 1`] = `
|
|
@@ -6,11 +6,12 @@ import { UserBlock } from './UserBlock';
|
|
|
6
6
|
|
|
7
7
|
export default { title: 'LumX components/user-block/UserBlock' };
|
|
8
8
|
|
|
9
|
-
export const Sizes = () => {
|
|
9
|
+
export const Sizes = ({ theme }: any) => {
|
|
10
10
|
const logAction = (action: string) => () => console.log(action);
|
|
11
11
|
return [Size.s, Size.m, Size.l].map((size: any) => (
|
|
12
12
|
<div className="demo-grid" key={size}>
|
|
13
13
|
<UserBlock
|
|
14
|
+
theme={theme}
|
|
14
15
|
name="Emmitt O. Lum"
|
|
15
16
|
fields={['Creative developer', 'Denpasar']}
|
|
16
17
|
avatarProps={{ image: avatarImageKnob(), alt: 'Avatar' }}
|
|
@@ -23,11 +24,31 @@ export const Sizes = () => {
|
|
|
23
24
|
));
|
|
24
25
|
};
|
|
25
26
|
|
|
26
|
-
export const
|
|
27
|
+
export const WithLinks = ({ theme }: any) => {
|
|
28
|
+
const logAction = (action: string) => () => console.log(action);
|
|
29
|
+
return [Size.s, Size.m, Size.l].map((size: any) => (
|
|
30
|
+
<div className="demo-grid" key={size}>
|
|
31
|
+
<UserBlock
|
|
32
|
+
theme={theme}
|
|
33
|
+
name="Emmitt O. Lum"
|
|
34
|
+
linkProps={{ href: 'https://www.lumapps.com', target: '_blank' }}
|
|
35
|
+
fields={['Creative developer', 'Denpasar']}
|
|
36
|
+
avatarProps={{ image: avatarImageKnob(), alt: 'Avatar' }}
|
|
37
|
+
size={size}
|
|
38
|
+
onMouseEnter={logAction('Mouse entered')}
|
|
39
|
+
onMouseLeave={logAction('Mouse left')}
|
|
40
|
+
onClick={logAction('UserBlock clicked')}
|
|
41
|
+
/>
|
|
42
|
+
</div>
|
|
43
|
+
));
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const WithBadge = ({ theme }: any) => {
|
|
27
47
|
const logAction = (action: string) => () => console.log(action);
|
|
28
48
|
return (
|
|
29
49
|
<div className="demo-grid">
|
|
30
50
|
<UserBlock
|
|
51
|
+
theme={theme}
|
|
31
52
|
name="Emmitt O. Lum"
|
|
32
53
|
fields={['Creative developer', 'Denpasar']}
|
|
33
54
|
avatarProps={{
|
|
@@ -42,19 +63,19 @@ export const WithBadge = () => {
|
|
|
42
63
|
size={Size.m}
|
|
43
64
|
onMouseEnter={logAction('Mouse entered')}
|
|
44
65
|
onMouseLeave={logAction('Mouse left')}
|
|
45
|
-
onClick={logAction('UserBlock clicked')}
|
|
46
66
|
/>
|
|
47
67
|
</div>
|
|
48
68
|
);
|
|
49
69
|
};
|
|
50
70
|
|
|
51
|
-
export const InList = () => {
|
|
71
|
+
export const InList = ({ theme }: any) => {
|
|
52
72
|
const logAction = (action: string) => () => console.log(action);
|
|
53
73
|
return (
|
|
54
74
|
<div className="demo-grid">
|
|
55
75
|
<List itemPadding={Size.big}>
|
|
56
76
|
<ListItem className="lumx-color-background-dark-L6" size={Size.big}>
|
|
57
77
|
<UserBlock
|
|
78
|
+
theme={theme}
|
|
58
79
|
name="Emmitt O. Lum"
|
|
59
80
|
fields={['Creative developer', 'Denpasar']}
|
|
60
81
|
avatarProps={{
|
|
@@ -74,6 +95,7 @@ export const InList = () => {
|
|
|
74
95
|
</ListItem>
|
|
75
96
|
<ListItem className="lumx-color-background-dark-L6" size={Size.big}>
|
|
76
97
|
<UserBlock
|
|
98
|
+
theme={theme}
|
|
77
99
|
name="Emmitt O. Lum"
|
|
78
100
|
fields={['Creative developer', 'Denpasar']}
|
|
79
101
|
avatarProps={{
|
|
@@ -93,6 +115,7 @@ export const InList = () => {
|
|
|
93
115
|
</ListItem>
|
|
94
116
|
<ListItem className="lumx-color-background-dark-L6" size={Size.big}>
|
|
95
117
|
<UserBlock
|
|
118
|
+
theme={theme}
|
|
96
119
|
name="Emmitt O. Lum"
|
|
97
120
|
fields={['Creative developer', 'Denpasar']}
|
|
98
121
|
avatarProps={{
|