@lumx/react 2.1.9-alpha-thumbnail4 → 2.1.9-prefer-css-color-variables2

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 (42) hide show
  1. package/esm/_internal/ImageBlock.js +1 -0
  2. package/esm/_internal/ImageBlock.js.map +1 -1
  3. package/esm/_internal/List2.js.map +1 -1
  4. package/esm/_internal/Slider2.js +2 -21
  5. package/esm/_internal/Slider2.js.map +1 -1
  6. package/esm/_internal/Thumbnail2.js +787 -79
  7. package/esm/_internal/Thumbnail2.js.map +1 -1
  8. package/esm/_internal/avatar.js +3 -0
  9. package/esm/_internal/avatar.js.map +1 -1
  10. package/esm/_internal/clamp.js +22 -0
  11. package/esm/_internal/clamp.js.map +1 -0
  12. package/esm/_internal/comment-block.js +3 -0
  13. package/esm/_internal/comment-block.js.map +1 -1
  14. package/esm/_internal/image-block.js +3 -0
  15. package/esm/_internal/image-block.js.map +1 -1
  16. package/esm/_internal/link-preview.js +3 -0
  17. package/esm/_internal/link-preview.js.map +1 -1
  18. package/esm/_internal/mdi.js +2 -2
  19. package/esm/_internal/mdi.js.map +1 -1
  20. package/esm/_internal/mosaic.js +3 -0
  21. package/esm/_internal/mosaic.js.map +1 -1
  22. package/esm/_internal/post-block.js +3 -0
  23. package/esm/_internal/post-block.js.map +1 -1
  24. package/esm/_internal/slider.js +2 -1
  25. package/esm/_internal/slider.js.map +1 -1
  26. package/esm/_internal/thumbnail.js +3 -0
  27. package/esm/_internal/thumbnail.js.map +1 -1
  28. package/esm/_internal/user-block.js +3 -0
  29. package/esm/_internal/user-block.js.map +1 -1
  30. package/esm/index.js +3 -1
  31. package/esm/index.js.map +1 -1
  32. package/package.json +4 -4
  33. package/src/components/image-block/ImageBlock.tsx +1 -0
  34. package/src/components/thumbnail/Thumbnail.stories.tsx +42 -403
  35. package/src/components/thumbnail/Thumbnail.test.tsx +2 -20
  36. package/src/components/thumbnail/Thumbnail.tsx +45 -71
  37. package/src/components/thumbnail/useFocusPoint.ts +10 -18
  38. package/src/components/thumbnail/useImageLoad.ts +22 -23
  39. package/src/hooks/useOnResize.ts +0 -6
  40. package/src/stories/generated/List/Demos.stories.tsx +2 -0
  41. package/src/stories/knobs/image.ts +3 -35
  42. package/types.d.ts +0 -6
@@ -5,16 +5,7 @@ import 'jest-enzyme';
5
5
  import { commonTestsSuite, itShouldRenderStories } from '@lumx/react/testing/utils';
6
6
 
7
7
  import { Thumbnail, ThumbnailProps } from './Thumbnail';
8
- import {
9
- Clickable,
10
- ClickableCustomLink,
11
- ClickableLink,
12
- ErrorCustomFallback,
13
- Default,
14
- ErrorFallback,
15
- ErrorCustomIconFallback,
16
- WithBadge,
17
- } from './Thumbnail.stories';
8
+ import { Clickable, CustomFallback, Default, DefaultFallback, IconFallback, WithBadge } from './Thumbnail.stories';
18
9
 
19
10
  const CLASSNAME = Thumbnail.className as string;
20
11
 
@@ -31,16 +22,7 @@ describe(`<${Thumbnail.displayName}>`, () => {
31
22
  // 1. Test render via snapshot.
32
23
  describe('Snapshots and structure', () => {
33
24
  itShouldRenderStories(
34
- {
35
- Default,
36
- Clickable,
37
- ClickableLink,
38
- ClickableCustomLink,
39
- ErrorFallback,
40
- ErrorCustomFallback,
41
- ErrorCustomIconFallback,
42
- WithBadge,
43
- },
25
+ { Default, Clickable, DefaultFallback, CustomFallback, IconFallback, WithBadge },
44
26
  Thumbnail,
45
27
  );
46
28
  });
@@ -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;
@@ -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
  }
@@ -23,12 +23,6 @@ export function useOnResize(element: HTMLElement | Falsy, update: RefObject<Call
23
23
  return;
24
24
  }
25
25
 
26
- // Do not update on first resize.
27
- if (previousSize.current && previousSize.current.height <= 1) {
28
- return;
29
- }
30
-
31
- // Do not update if size hasn't really changed.
32
26
  const { width, height } = entry.contentRect;
33
27
  if (previousSize.current?.width === width && previousSize.current?.height === height) {
34
28
  return;
@@ -4,6 +4,8 @@
4
4
  export default { title: 'LumX components/list/List Demos' };
5
5
 
6
6
  export { App as Big } from './big';
7
+ export { App as Clickable } from './clickable';
7
8
  export { App as Huge } from './huge';
9
+ export { App as Paddings } from './paddings';
8
10
  export { App as Regular } from './regular';
9
11
  export { App as Tiny } from './tiny';
@@ -6,19 +6,18 @@ const avatar3 = '/demo-assets/avatar3.jpg';
6
6
  const avatar4 = '/demo-assets/avatar4.jpg';
7
7
  const landscape1 = '/demo-assets/landscape1.jpg';
8
8
  const landscape2 = '/demo-assets/landscape2.jpg';
9
- const landscape1s200 = '/demo-assets/landscape1-s200.jpg';
10
9
  const landscape3 = '/demo-assets/landscape3.jpg';
11
10
  const portrait1 = '/demo-assets/portrait1.jpg';
12
- const portrait1s200 = '/demo-assets/portrait1-s200.jpg';
13
11
  const portrait2 = '/demo-assets/portrait2.jpg';
14
12
  const portrait3 = '/demo-assets/portrait3.jpg';
15
13
  const square1 = '/demo-assets/square1.jpg';
16
14
  const square2 = '/demo-assets/square2.jpg';
17
15
 
18
16
  export const AVATAR_IMAGES = { avatar1, avatar2, avatar3, avatar4 };
17
+
19
18
  export const SQUARE_IMAGES = { square1, square2 };
20
- export const LANDSCAPE_IMAGES = { landscape1, landscape1s200, landscape2, landscape3 };
21
- export const PORTRAIT_IMAGES = { portrait1, portrait1s200, portrait2, portrait3 };
19
+ export const LANDSCAPE_IMAGES = { landscape1, landscape2, landscape3 };
20
+ export const PORTRAIT_IMAGES = { portrait1, portrait2, portrait3 };
22
21
 
23
22
  export const IMAGES = { ...LANDSCAPE_IMAGES, ...PORTRAIT_IMAGES, ...SQUARE_IMAGES, ...AVATAR_IMAGES };
24
23
 
@@ -36,34 +35,3 @@ export const squareImageKnob = (name = 'Image', value = Object.values(SQUARE_IMA
36
35
 
37
36
  export const imageKnob = (name = 'Image', value = Object.values(IMAGES)[0], groupId?: string) =>
38
37
  select(name, IMAGES, value, groupId);
39
-
40
- type Size = { width: number; height: number };
41
-
42
- export const AVATAR_IMAGE_SIZES: Record<keyof typeof AVATAR_IMAGES, Size> = {
43
- avatar1: { width: 128, height: 128 },
44
- avatar2: { width: 150, height: 150 },
45
- avatar3: { width: 128, height: 128 },
46
- avatar4: { width: 128, height: 128 },
47
- };
48
- export const SQUARE_IMAGE_SIZES: Record<keyof typeof SQUARE_IMAGES, Size> = {
49
- square1: { width: 72, height: 72 },
50
- square2: { width: 300, height: 300 },
51
- };
52
- export const LANDSCAPE_IMAGE_SIZES: Record<keyof typeof LANDSCAPE_IMAGES, Size> = {
53
- landscape1: { width: 800, height: 546 },
54
- landscape1s200: { width: 200, height: 150 },
55
- landscape2: { width: 800, height: 600 },
56
- landscape3: { width: 640, height: 480 },
57
- };
58
- export const PORTRAIT_IMAGE_SIZES: Record<keyof typeof PORTRAIT_IMAGES, Size> = {
59
- portrait1: { width: 275, height: 500 },
60
- portrait1s200: { width: 200, height: 364 },
61
- portrait2: { width: 350, height: 500 },
62
- portrait3: { width: 300, height: 500 },
63
- };
64
- export const IMAGE_SIZES: Record<keyof typeof IMAGES, Size> = {
65
- ...LANDSCAPE_IMAGE_SIZES,
66
- ...PORTRAIT_IMAGE_SIZES,
67
- ...SQUARE_IMAGE_SIZES,
68
- ...AVATAR_IMAGE_SIZES,
69
- };
package/types.d.ts CHANGED
@@ -1233,8 +1233,6 @@ export interface ThumbnailProps extends GenericProps {
1233
1233
  imgProps?: ImgHTMLProps;
1234
1234
  /** Reference to the native <img> element. */
1235
1235
  imgRef?: Ref<HTMLImageElement>;
1236
- /** Set to true to force the display of the loading skeleton. */
1237
- isLoading?: boolean;
1238
1236
  /** Size variant of the component. */
1239
1237
  size?: ThumbnailSize;
1240
1238
  /** Image loading mode. */
@@ -1247,10 +1245,6 @@ export interface ThumbnailProps extends GenericProps {
1247
1245
  theme?: Theme;
1248
1246
  /** Variant of the component. */
1249
1247
  variant?: ThumbnailVariant;
1250
- /** Props to pass to the link wrapping the thumbnail. */
1251
- linkProps?: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>;
1252
- /** Custom react component for the link (can be used to inject react router Link). */
1253
- linkAs?: "a" | any;
1254
1248
  }
1255
1249
  /**
1256
1250
  * Thumbnail component.