@lumx/react 2.1.9-alpha-thumbnail3 → 2.1.9-prefer-css-color-variables

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/esm/_internal/Avatar2.js +1 -5
  2. package/esm/_internal/Avatar2.js.map +1 -1
  3. package/esm/_internal/DragHandle.js +1 -1
  4. package/esm/_internal/DragHandle.js.map +1 -1
  5. package/esm/_internal/Flag2.js +1 -3
  6. package/esm/_internal/Flag2.js.map +1 -1
  7. package/esm/_internal/Icon2.js +9 -1
  8. package/esm/_internal/Icon2.js.map +1 -1
  9. package/esm/_internal/ImageBlock.js +1 -0
  10. package/esm/_internal/ImageBlock.js.map +1 -1
  11. package/esm/_internal/List2.js.map +1 -1
  12. package/esm/_internal/Message2.js +2 -2
  13. package/esm/_internal/Message2.js.map +1 -1
  14. package/esm/_internal/Slider2.js +2 -21
  15. package/esm/_internal/Slider2.js.map +1 -1
  16. package/esm/_internal/Thumbnail2.js +787 -79
  17. package/esm/_internal/Thumbnail2.js.map +1 -1
  18. package/esm/_internal/UserBlock.js +14 -45
  19. package/esm/_internal/UserBlock.js.map +1 -1
  20. package/esm/_internal/avatar.js +3 -0
  21. package/esm/_internal/avatar.js.map +1 -1
  22. package/esm/_internal/clamp.js +22 -0
  23. package/esm/_internal/clamp.js.map +1 -0
  24. package/esm/_internal/comment-block.js +3 -0
  25. package/esm/_internal/comment-block.js.map +1 -1
  26. package/esm/_internal/image-block.js +3 -0
  27. package/esm/_internal/image-block.js.map +1 -1
  28. package/esm/_internal/link-preview.js +3 -0
  29. package/esm/_internal/link-preview.js.map +1 -1
  30. package/esm/_internal/mdi.js +2 -2
  31. package/esm/_internal/mdi.js.map +1 -1
  32. package/esm/_internal/mosaic.js +3 -0
  33. package/esm/_internal/mosaic.js.map +1 -1
  34. package/esm/_internal/post-block.js +3 -0
  35. package/esm/_internal/post-block.js.map +1 -1
  36. package/esm/_internal/slider.js +2 -1
  37. package/esm/_internal/slider.js.map +1 -1
  38. package/esm/_internal/thumbnail.js +3 -0
  39. package/esm/_internal/thumbnail.js.map +1 -1
  40. package/esm/_internal/user-block.js +2 -1
  41. package/esm/_internal/user-block.js.map +1 -1
  42. package/esm/index.js +3 -2
  43. package/esm/index.js.map +1 -1
  44. package/package.json +4 -4
  45. package/src/components/avatar/Avatar.tsx +0 -8
  46. package/src/components/drag-handle/DragHandle.tsx +5 -1
  47. package/src/components/flag/Flag.test.tsx +1 -2
  48. package/src/components/flag/Flag.tsx +2 -10
  49. package/src/components/flag/__snapshots__/Flag.test.tsx.snap +0 -15
  50. package/src/components/icon/Icon.tsx +10 -1
  51. package/src/components/image-block/ImageBlock.tsx +1 -0
  52. package/src/components/message/Message.tsx +2 -2
  53. package/src/components/thumbnail/Thumbnail.stories.tsx +42 -403
  54. package/src/components/thumbnail/Thumbnail.test.tsx +2 -20
  55. package/src/components/thumbnail/Thumbnail.tsx +45 -71
  56. package/src/components/thumbnail/__snapshots__/Thumbnail.test.tsx.snap +6 -53
  57. package/src/components/thumbnail/useFocusPoint.ts +10 -18
  58. package/src/components/thumbnail/useImageLoad.ts +22 -23
  59. package/src/components/user-block/UserBlock.stories.tsx +4 -30
  60. package/src/components/user-block/UserBlock.tsx +16 -41
  61. package/src/components/user-block/__snapshots__/UserBlock.test.tsx.snap +145 -244
  62. package/src/hooks/useOnResize.ts +0 -6
  63. package/src/stories/generated/List/Demos.stories.tsx +2 -0
  64. package/src/stories/knobs/image.ts +3 -35
  65. package/types.d.ts +0 -14
@@ -7,6 +7,7 @@ import React, {
7
7
  ReactNode,
8
8
  Ref,
9
9
  useRef,
10
+ useState,
10
11
  } from 'react';
11
12
  import classNames from 'classnames';
12
13
 
@@ -14,9 +15,12 @@ import { AspectRatio, HorizontalAlignment, Icon, Size, Theme } from '@lumx/react
14
15
 
15
16
  import { Comp, GenericProps, getRootClassName, handleBasicClasses } from '@lumx/react/utils';
16
17
 
17
- import { mdiImageBroken } from '@lumx/icons';
18
+ import { mdiImageBrokenVariant } from '@lumx/icons';
19
+ import { isInternetExplorer } from '@lumx/react/utils/isInternetExplorer';
18
20
  import { mergeRefs } from '@lumx/react/utils/mergeRefs';
21
+ import { useFocusPoint } from '@lumx/react/components/thumbnail/useFocusPoint';
19
22
  import { useImageLoad } from '@lumx/react/components/thumbnail/useImageLoad';
23
+ import { useClickable } from '@lumx/react/components/thumbnail/useClickable';
20
24
  import { FocusPoint, ThumbnailSize, ThumbnailVariant } from './types';
21
25
 
22
26
  type ImgHTMLProps = ImgHTMLAttributes<HTMLImageElement>;
@@ -47,8 +51,6 @@ export interface ThumbnailProps extends GenericProps {
47
51
  imgProps?: ImgHTMLProps;
48
52
  /** Reference to the native <img> element. */
49
53
  imgRef?: Ref<HTMLImageElement>;
50
- /** Set to true to force the display of the loading skeleton. */
51
- isLoading?: boolean;
52
54
  /** Size variant of the component. */
53
55
  size?: ThumbnailSize;
54
56
  /** Image loading mode. */
@@ -61,10 +63,6 @@ export interface ThumbnailProps extends GenericProps {
61
63
  theme?: Theme;
62
64
  /** Variant of the component. */
63
65
  variant?: ThumbnailVariant;
64
- /** Props to pass to the link wrapping the thumbnail. */
65
- linkProps?: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>;
66
- /** Custom react component for the link (can be used to inject react router Link). */
67
- linkAs?: 'a' | any;
68
66
  }
69
67
 
70
68
  /**
@@ -81,18 +79,11 @@ const CLASSNAME = getRootClassName(COMPONENT_NAME);
81
79
  * Component default props.
82
80
  */
83
81
  const DEFAULT_PROPS: Partial<ThumbnailProps> = {
84
- fallback: mdiImageBroken,
82
+ fallback: mdiImageBrokenVariant,
85
83
  loading: 'lazy',
86
84
  theme: Theme.light,
87
85
  };
88
86
 
89
- function getObjectPosition(aspectRatio: AspectRatio, focusPoint?: FocusPoint) {
90
- if (aspectRatio === AspectRatio.original || (!focusPoint?.y && !focusPoint?.x)) return undefined;
91
- const x = Math.round(Math.abs(((focusPoint?.x || 0) + 1) / 2) * 100);
92
- const y = Math.round(Math.abs(((focusPoint?.y || 0) - 1) / 2) * 100);
93
- return `${x}% ${y}%`;
94
- }
95
-
96
87
  /**
97
88
  * Thumbnail component.
98
89
  *
@@ -104,7 +95,7 @@ export const Thumbnail: Comp<ThumbnailProps> = forwardRef((props, ref) => {
104
95
  const {
105
96
  align,
106
97
  alt,
107
- aspectRatio = AspectRatio.original,
98
+ aspectRatio,
108
99
  badge,
109
100
  className,
110
101
  crossOrigin,
@@ -114,88 +105,71 @@ export const Thumbnail: Comp<ThumbnailProps> = forwardRef((props, ref) => {
114
105
  image,
115
106
  imgProps,
116
107
  imgRef: propImgRef,
117
- isLoading: isLoadingProp,
118
108
  loading,
119
109
  size,
120
110
  theme,
121
111
  variant,
122
- linkProps,
123
- linkAs,
124
- showSkeletonLoading = true,
125
112
  ...forwardedProps
126
113
  } = props;
127
114
  const imgRef = useRef<HTMLImageElement>(null);
128
115
 
129
116
  // Image loading state.
130
- const loadingState = useImageLoad(image, imgRef);
131
- const isLoading = isLoadingProp || loadingState === 'isLoading';
117
+ const loadingState = useImageLoad(imgRef);
132
118
  const hasError = loadingState === 'hasError';
119
+ const isLoading = loadingState === 'isLoading';
133
120
 
134
- const isLink = Boolean(linkProps?.href || linkAs);
135
- const isButton = !!forwardedProps.onClick;
136
- const isClickable = isButton || isLink;
121
+ const [wrapper, setWrapper] = useState<HTMLElement>();
122
+ const wrapperProps: any = {
123
+ ...forwardedProps,
124
+ ref: mergeRefs(setWrapper, ref),
125
+ className: classNames(
126
+ className,
127
+ handleBasicClasses({ align, aspectRatio, prefix: CLASSNAME, size, theme, variant, hasBadge: !!badge }),
128
+ isLoading && wrapper?.getBoundingClientRect()?.height && 'lumx-color-background-dark-L6',
129
+ fillHeight && `${CLASSNAME}--fill-height`,
130
+ ),
131
+ // Handle clickable Thumbnail a11y.
132
+ ...useClickable(props),
133
+ };
137
134
 
138
- let Wrapper: any = 'div';
139
- const wrapperProps = { ...forwardedProps };
140
- if (isLink) {
141
- Wrapper = linkAs || 'a';
142
- Object.assign(wrapperProps, linkProps);
143
- } else if (isButton) {
144
- Wrapper = 'button';
145
- }
135
+ // Update img style according to focus point and aspect ratio.
136
+ const style = useFocusPoint({ image, focusPoint, aspectRatio, imgRef, loadingState, wrapper });
146
137
 
147
138
  return (
148
- <Wrapper
149
- {...wrapperProps}
150
- ref={ref}
151
- className={classNames(
152
- linkProps?.className,
153
- className,
154
- handleBasicClasses({
155
- align,
156
- aspectRatio,
157
- prefix: CLASSNAME,
158
- size,
159
- theme,
160
- variant,
161
- isClickable,
162
- hasError,
163
- isLoading: showSkeletonLoading && isLoading,
164
- hasBadge: !!badge,
165
- }),
166
- fillHeight && `${CLASSNAME}--fill-height`,
167
- )}
168
- >
169
- <div className={`${CLASSNAME}__background`}>
139
+ <div {...wrapperProps}>
140
+ <div
141
+ className={`${CLASSNAME}__background`}
142
+ style={{
143
+ ...style?.wrapper,
144
+ // Remove from layout if image not loaded correctly (use fallback)
145
+ display: hasError ? 'none' : undefined,
146
+ // Hide while loading.
147
+ visibility: isLoading ? 'hidden' : undefined,
148
+ }}
149
+ >
170
150
  <img
171
151
  {...imgProps}
172
152
  style={{
173
153
  ...imgProps?.style,
174
- // Hide on error.
175
- visibility: hasError ? 'hidden' : undefined,
176
- // Focus point.
177
- objectPosition: getObjectPosition(aspectRatio, focusPoint),
154
+ ...style?.image,
178
155
  }}
179
156
  ref={mergeRefs(imgRef, propImgRef)}
180
- className={classNames(`${CLASSNAME}__image`, isLoading && `${CLASSNAME}__image--is-loading`)}
181
- crossOrigin={crossOrigin}
157
+ className={style?.image ? `${CLASSNAME}__focused-image` : `${CLASSNAME}__image`}
158
+ crossOrigin={crossOrigin && !isInternetExplorer() ? crossOrigin : undefined}
182
159
  src={image}
183
160
  alt={alt}
184
161
  loading={loading}
185
162
  />
186
- {!isLoading && hasError && (
187
- <div className={`${CLASSNAME}__fallback`}>
188
- {typeof fallback === 'string' ? (
189
- <Icon icon={fallback} size={Size.xxs} theme={theme} />
190
- ) : (
191
- fallback
192
- )}
193
- </div>
194
- )}
195
163
  </div>
164
+ {hasError &&
165
+ (typeof fallback === 'string' ? (
166
+ <Icon className={`${CLASSNAME}__fallback`} icon={fallback} size={size || Size.m} theme={theme} />
167
+ ) : (
168
+ <div className={`${CLASSNAME}__fallback`}>{fallback}</div>
169
+ ))}
196
170
  {badge &&
197
171
  React.cloneElement(badge, { className: classNames(`${CLASSNAME}__badge`, badge.props.className) })}
198
- </Wrapper>
172
+ </div>
199
173
  );
200
174
  });
201
175
  Thumbnail.displayName = COMPONENT_NAME;
@@ -1,9 +1,12 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`<Thumbnail> Snapshots and structure should render story 'Clickable' 1`] = `
4
- <button
5
- className="lumx-thumbnail lumx-thumbnail--size-xxl lumx-thumbnail--theme-light lumx-thumbnail--is-clickable"
4
+ <div
5
+ className="lumx-thumbnail lumx-thumbnail--size-xxl lumx-thumbnail--theme-light"
6
6
  onClick={[Function]}
7
+ onKeyPress={[Function]}
8
+ role="button"
9
+ tabIndex={0}
7
10
  >
8
11
  <div
9
12
  className="lumx-thumbnail__background"
@@ -22,57 +25,7 @@ exports[`<Thumbnail> Snapshots and structure should render story 'Clickable' 1`]
22
25
  style={Object {}}
23
26
  />
24
27
  </div>
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="/demo-assets/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="/demo-assets/landscape1.jpg"
72
- style={Object {}}
73
- />
74
- </div>
75
- </a>
28
+ </div>
76
29
  `;
77
30
 
78
31
  exports[`<Thumbnail> Snapshots and structure should render story 'CustomFallback' 1`] = `
@@ -32,19 +32,15 @@ type Sizes = {
32
32
 
33
33
  function calculateSizes(
34
34
  imageElement?: HTMLImageElement | null | undefined,
35
- imageWidthProp?: number,
36
- imageHeightProp?: number,
37
35
  parentElement?: HTMLElement | null,
38
36
  aspectRatio?: AspectRatio,
39
37
  ): Sizes | undefined {
40
- const imgWidth = imageElement?.naturalWidth || imageWidthProp;
41
- const imgHeight = imageElement?.naturalHeight || imageHeightProp;
42
- if (!imgHeight || !imgWidth || !parentElement || !aspectRatio || aspectRatio === AspectRatio.original) {
43
- return undefined;
44
- }
45
- const rect = parentElement?.getBoundingClientRect();
46
- const containerWidth = Math.ceil(rect?.width || 0);
47
- const containerHeight = Math.ceil(rect?.height || 0);
38
+ if (!imageElement || !parentElement || !aspectRatio || aspectRatio === AspectRatio.original) return undefined;
39
+ const { naturalWidth: imgWidth, naturalHeight: imgHeight } = imageElement || { naturalWidth: 0, naturalHeight: 0 };
40
+ const { width: containerWidth, height: containerHeight } = parentElement?.getBoundingClientRect() || {
41
+ width: 0,
42
+ height: 0,
43
+ };
48
44
  return { imgWidth, imgHeight, containerWidth, containerHeight, aspectRatio };
49
45
  }
50
46
 
@@ -94,7 +90,6 @@ function calculateImageStyle(sizes: Sizes, point: Required<FocusPoint>): Styles
94
90
  // Minimize image while still filling space
95
91
  if (sizes.imgWidth > sizes.containerWidth && sizes.imgHeight > sizes.containerHeight) {
96
92
  image[widthRatio > heightRatio ? 'maxHeight' : 'maxWidth'] = '100%';
97
- image[widthRatio > heightRatio ? 'maxWidth' : 'maxHeight'] = 'none';
98
93
  }
99
94
 
100
95
  if (widthRatio > heightRatio) {
@@ -114,15 +109,13 @@ function calculateImageStyle(sizes: Sizes, point: Required<FocusPoint>): Styles
114
109
  */
115
110
  export const useFocusPoint = (options: {
116
111
  image: string;
117
- imageWidthProp?: number;
118
- imageHeightProp?: number;
119
112
  focusPoint?: FocusPoint;
120
113
  aspectRatio?: AspectRatio;
121
114
  imgRef: RefObject<HTMLImageElement>;
122
115
  loadingState: LoadingState;
123
116
  wrapper?: HTMLElement;
124
117
  }): Styles | undefined => {
125
- const { image, imageWidthProp, imageHeightProp, aspectRatio, focusPoint, imgRef, loadingState, wrapper } = options;
118
+ const { image, aspectRatio, focusPoint, imgRef, loadingState, wrapper } = options;
126
119
 
127
120
  const point = parseFocusPoint(focusPoint);
128
121
 
@@ -135,13 +128,12 @@ export const useFocusPoint = (options: {
135
128
  const update = useMemo(
136
129
  () => {
137
130
  const updateFunction = () => {
138
- const sizes = calculateSizes(imgRef?.current, imageWidthProp, imageHeightProp, wrapper, aspectRatio);
131
+ const sizes = calculateSizes(imgRef?.current, wrapper, aspectRatio);
139
132
  if (!sizes || (isEqual(sizes, previousSizes.current) && isEqual(point, previousPoint.current))) {
140
133
  // Nothing changed.
141
134
  return;
142
135
  }
143
- const newStyle = calculateImageStyle(sizes, point);
144
- setStyle(newStyle);
136
+ setStyle(calculateImageStyle(sizes, point));
145
137
  previousPoint.current = point;
146
138
  previousSizes.current = sizes;
147
139
  };
@@ -149,7 +141,7 @@ export const useFocusPoint = (options: {
149
141
  return updateFunction;
150
142
  },
151
143
  // eslint-disable-next-line react-hooks/exhaustive-deps
152
- [...Object.values(point), wrapper, aspectRatio],
144
+ [...Object.values(point), imgRef, wrapper, aspectRatio],
153
145
  );
154
146
 
155
147
  // Update on image loaded.
@@ -1,40 +1,39 @@
1
- import { RefObject, useEffect, useState } from 'react';
1
+ import { RefObject, useCallback, useEffect, useState } from 'react';
2
2
 
3
3
  export type LoadingState = 'isLoading' | 'isLoaded' | 'hasError';
4
4
 
5
- function getState(img: HTMLImageElement | null | undefined, event?: Event) {
6
- // Error event occurred or image loaded empty.
7
- if (event?.type === 'error' || (img?.complete && (img?.naturalWidth === 0 || img?.naturalHeight === 0))) {
8
- return 'hasError';
9
- }
10
- // Image is undefined or incomplete.
11
- if (!img || !img.complete) {
12
- return 'isLoading';
13
- }
14
- // Else loaded.
15
- return 'isLoaded';
16
- }
5
+ export function useImageLoad(imgRef?: RefObject<HTMLImageElement>): LoadingState {
6
+ const [state, setState] = useState<LoadingState>('isLoading');
17
7
 
18
- export function useImageLoad(imageURL: string, imgRef?: RefObject<HTMLImageElement>): LoadingState {
19
- const [state, setState] = useState<LoadingState>(getState(imgRef?.current));
8
+ const update = useCallback(
9
+ (event?: any) => {
10
+ const img = imgRef?.current;
11
+ if (!img || !img.complete) {
12
+ setState('isLoading');
13
+ return;
14
+ }
20
15
 
21
- // Update state when changing image URL or DOM reference.
22
- useEffect(() => {
23
- setState(getState(imgRef?.current));
24
- }, [imageURL, imgRef]);
16
+ if (event?.type === 'error' || (img.complete && img?.naturalWidth === 0)) {
17
+ setState('hasError');
18
+ return;
19
+ }
20
+
21
+ setState('isLoaded');
22
+ },
23
+ [imgRef],
24
+ );
25
25
 
26
- // Listen to `load` and `error` event on image
27
26
  useEffect(() => {
28
27
  const img = imgRef?.current;
29
28
  if (!img) return undefined;
30
- const update = (event?: Event) => setState(getState(img, event));
29
+
30
+ update();
31
31
  img.addEventListener('load', update);
32
32
  img.addEventListener('error', update);
33
33
  return () => {
34
34
  img.removeEventListener('load', update);
35
35
  img.removeEventListener('error', update);
36
36
  };
37
- }, [imgRef, imgRef?.current?.src]);
38
-
37
+ }, [update, imgRef, imgRef?.current?.src]);
39
38
  return state;
40
39
  }
@@ -6,12 +6,11 @@ import { UserBlock } from './UserBlock';
6
6
 
7
7
  export default { title: 'LumX components/user-block/UserBlock' };
8
8
 
9
- export const Sizes = ({ theme }: any) => {
9
+ export const Sizes = () => {
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}
15
14
  name="Emmitt O. Lum"
16
15
  fields={['Creative developer', 'Denpasar']}
17
16
  avatarProps={{ image: avatarImageKnob(), alt: 'Avatar' }}
@@ -24,34 +23,11 @@ export const Sizes = ({ theme }: any) => {
24
23
  ));
25
24
  };
26
25
 
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={{
35
- href: 'https://www.lumapps.com',
36
- target: '_blank',
37
- }}
38
- fields={['Creative developer', 'Denpasar']}
39
- avatarProps={{ image: avatarImageKnob(), alt: 'Avatar' }}
40
- size={size}
41
- onMouseEnter={logAction('Mouse entered')}
42
- onMouseLeave={logAction('Mouse left')}
43
- onClick={logAction('UserBlock clicked')}
44
- />
45
- </div>
46
- ));
47
- };
48
-
49
- export const WithBadge = ({ theme }: any) => {
26
+ export const WithBadge = () => {
50
27
  const logAction = (action: string) => () => console.log(action);
51
28
  return (
52
29
  <div className="demo-grid">
53
30
  <UserBlock
54
- theme={theme}
55
31
  name="Emmitt O. Lum"
56
32
  fields={['Creative developer', 'Denpasar']}
57
33
  avatarProps={{
@@ -66,19 +42,19 @@ export const WithBadge = ({ theme }: any) => {
66
42
  size={Size.m}
67
43
  onMouseEnter={logAction('Mouse entered')}
68
44
  onMouseLeave={logAction('Mouse left')}
45
+ onClick={logAction('UserBlock clicked')}
69
46
  />
70
47
  </div>
71
48
  );
72
49
  };
73
50
 
74
- export const InList = ({ theme }: any) => {
51
+ export const InList = () => {
75
52
  const logAction = (action: string) => () => console.log(action);
76
53
  return (
77
54
  <div className="demo-grid">
78
55
  <List itemPadding={Size.big}>
79
56
  <ListItem className="lumx-color-background-dark-L6" size={Size.big}>
80
57
  <UserBlock
81
- theme={theme}
82
58
  name="Emmitt O. Lum"
83
59
  fields={['Creative developer', 'Denpasar']}
84
60
  avatarProps={{
@@ -98,7 +74,6 @@ export const InList = ({ theme }: any) => {
98
74
  </ListItem>
99
75
  <ListItem className="lumx-color-background-dark-L6" size={Size.big}>
100
76
  <UserBlock
101
- theme={theme}
102
77
  name="Emmitt O. Lum"
103
78
  fields={['Creative developer', 'Denpasar']}
104
79
  avatarProps={{
@@ -118,7 +93,6 @@ export const InList = ({ theme }: any) => {
118
93
  </ListItem>
119
94
  <ListItem className="lumx-color-background-dark-L6" size={Size.big}>
120
95
  <UserBlock
121
- theme={theme}
122
96
  name="Emmitt O. Lum"
123
97
  fields={['Creative developer', 'Denpasar']}
124
98
  avatarProps={{
@@ -5,8 +5,6 @@ import classNames from 'classnames';
5
5
  import { Avatar, Orientation, Size, Theme } from '@lumx/react';
6
6
 
7
7
  import { Comp, GenericProps, getRootClassName, handleBasicClasses } from '@lumx/react/utils';
8
- import { isEmpty } from 'lodash';
9
- import { renderLink } from '@lumx/react/utils/renderLink';
10
8
  import { AvatarProps } from '../avatar/Avatar';
11
9
 
12
10
  /**
@@ -20,10 +18,6 @@ export type UserBlockSize = Extract<Size, 's' | 'm' | 'l'>;
20
18
  export interface UserBlockProps extends GenericProps {
21
19
  /** Props to pass to the avatar. */
22
20
  avatarProps?: AvatarProps;
23
- /** Props to pass to the link wrapping the avatar thumbnail. */
24
- linkProps?: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>;
25
- /** Custom react component for the link (can be used to inject react router Link). */
26
- linkAs?: 'a' | any;
27
21
  /** Simple action toolbar content. */
28
22
  simpleAction?: ReactNode;
29
23
  /** Multiple action toolbar content. */
@@ -86,8 +80,6 @@ export const UserBlock: Comp<UserBlockProps, HTMLDivElement> = forwardRef((props
86
80
  simpleAction,
87
81
  size,
88
82
  theme,
89
- linkProps,
90
- linkAs,
91
83
  ...forwardedProps
92
84
  } = props;
93
85
  let componentSize = size;
@@ -99,29 +91,12 @@ export const UserBlock: Comp<UserBlockProps, HTMLDivElement> = forwardRef((props
99
91
 
100
92
  const shouldDisplayActions: boolean = orientation === Orientation.vertical;
101
93
 
102
- const isLink = Boolean(linkProps?.href || linkAs);
103
- const isClickable = !!onClick || isLink;
104
-
105
- const nameBlock: ReactNode = React.useMemo(() => {
106
- if (isEmpty(name)) {
107
- return null;
108
- }
109
- const nameClassName = classNames(
110
- handleBasicClasses({ prefix: `${CLASSNAME}__name`, isClickable }),
111
- isLink && linkProps?.className,
112
- );
113
- if (isLink) {
114
- return renderLink({ ...linkProps, linkAs, className: nameClassName }, name);
115
- }
116
- if (onClick) {
117
- return (
118
- <button onClick={onClick} type="button" className={nameClassName}>
119
- {name}
120
- </button>
121
- );
122
- }
123
- return <span className={nameClassName}>{name}</span>;
124
- }, [isClickable, isLink, linkAs, linkProps, name, onClick]);
94
+ const nameBlock: ReactNode = name && (
95
+ // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-noninteractive-tabindex,jsx-a11y/no-static-element-interactions
96
+ <span className={`${CLASSNAME}__name`} onClick={onClick} tabIndex={onClick ? 0 : -1}>
97
+ {name}
98
+ </span>
99
+ );
125
100
 
126
101
  const fieldsBlock: ReactNode = fields && componentSize !== Size.s && (
127
102
  <div className={`${CLASSNAME}__fields`}>
@@ -139,21 +114,21 @@ export const UserBlock: Comp<UserBlockProps, HTMLDivElement> = forwardRef((props
139
114
  {...forwardedProps}
140
115
  className={classNames(
141
116
  className,
142
- handleBasicClasses({ prefix: CLASSNAME, orientation, size: componentSize, theme, isClickable }),
117
+ handleBasicClasses({ prefix: CLASSNAME, orientation, size: componentSize, theme }),
143
118
  )}
144
119
  onMouseLeave={onMouseLeave}
145
120
  onMouseEnter={onMouseEnter}
146
121
  >
147
122
  {avatarProps && (
148
- <Avatar
149
- linkAs={linkAs}
150
- linkProps={linkProps}
151
- {...avatarProps}
152
- className={classNames(`${CLASSNAME}__avatar`, avatarProps.className)}
153
- size={componentSize}
154
- onClick={onClick}
155
- theme={theme}
156
- />
123
+ <div className={`${CLASSNAME}__avatar`}>
124
+ <Avatar
125
+ {...avatarProps}
126
+ size={componentSize}
127
+ onClick={onClick}
128
+ tabIndex={onClick ? 0 : -1}
129
+ theme={theme}
130
+ />
131
+ </div>
157
132
  )}
158
133
  {(fields || name) && (
159
134
  <div className={`${CLASSNAME}__wrapper`}>