@lumx/react 2.1.9-alpha-thumbnail3 → 2.1.9-alpha-thumbnail8
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 +1 -5
- package/esm/_internal/Avatar2.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/Icon2.js +9 -1
- package/esm/_internal/Icon2.js.map +1 -1
- 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/Thumbnail2.js +18 -8
- package/esm/_internal/Thumbnail2.js.map +1 -1
- package/esm/_internal/UserBlock.js +14 -45
- package/esm/_internal/UserBlock.js.map +1 -1
- package/esm/_internal/user-block.js +0 -2
- package/esm/_internal/user-block.js.map +1 -1
- package/esm/index.js +0 -1
- package/esm/index.js.map +1 -1
- package/package.json +4 -4
- package/src/components/avatar/Avatar.tsx +0 -8
- package/src/components/avatar/__snapshots__/Avatar.test.tsx.snap +30 -30
- 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/icon/Icon.tsx +10 -1
- package/src/components/image-block/__snapshots__/ImageBlock.test.tsx.snap +1 -1
- package/src/components/message/Message.tsx +2 -2
- package/src/components/mosaic/__snapshots__/Mosaic.test.tsx.snap +30 -30
- package/src/components/post-block/__snapshots__/PostBlock.test.tsx.snap +1 -1
- package/src/components/slideshow/__snapshots__/Slideshow.test.tsx.snap +10 -10
- package/src/components/table/__snapshots__/Table.test.tsx.snap +3 -3
- package/src/components/thumbnail/Thumbnail.stories.tsx +14 -38
- package/src/components/thumbnail/Thumbnail.test.tsx +0 -6
- package/src/components/thumbnail/Thumbnail.tsx +18 -6
- package/src/components/thumbnail/__snapshots__/Thumbnail.test.tsx.snap +39 -116
- package/src/components/user-block/UserBlock.stories.tsx +4 -30
- package/src/components/user-block/UserBlock.tsx +16 -41
- package/src/components/user-block/__snapshots__/UserBlock.test.tsx.snap +145 -244
- package/src/hooks/useOnResize.ts +0 -6
- package/src/stories/generated/List/Demos.stories.tsx +2 -0
- package/types.d.ts +0 -8
- package/src/components/thumbnail/useClickable.ts +0 -26
- package/src/components/thumbnail/useFocusPoint.ts +0 -162
|
@@ -31,27 +31,28 @@ export const Default = ({ theme }: any) => {
|
|
|
31
31
|
undefined,
|
|
32
32
|
);
|
|
33
33
|
const aspectRatio = enumKnob('Aspect ratio', [undefined, ...Object.values(AspectRatio)], undefined);
|
|
34
|
-
const crossOrigin = enumKnob('CORS', [undefined, 'anonymous', 'use-credentials'] as const, undefined);
|
|
35
34
|
const fillHeight = boolean('Fill Height', false);
|
|
36
35
|
const focusPoint = { x: focusKnob('Focus X'), y: focusKnob('Focus Y') };
|
|
37
36
|
const image = imageKnob('Image', IMAGES.landscape1);
|
|
38
37
|
const variant = select('Variant', ThumbnailVariant, ThumbnailVariant.squared);
|
|
39
38
|
const size = sizeKnob('Size', undefined);
|
|
40
39
|
const onClick = boolean('clickable?', false) ? action('onClick') : undefined;
|
|
40
|
+
const isLoading = boolean('Force loading', false);
|
|
41
|
+
const forceError = boolean('Force error', false);
|
|
41
42
|
|
|
42
43
|
return (
|
|
43
44
|
<Thumbnail
|
|
44
45
|
alt={alt}
|
|
45
46
|
align={align}
|
|
46
47
|
aspectRatio={aspectRatio}
|
|
47
|
-
crossOrigin={crossOrigin}
|
|
48
48
|
fillHeight={fillHeight}
|
|
49
49
|
focusPoint={focusPoint}
|
|
50
|
-
image={image}
|
|
50
|
+
image={forceError ? 'foo' : image}
|
|
51
51
|
size={size}
|
|
52
52
|
theme={theme}
|
|
53
53
|
variant={variant}
|
|
54
54
|
onClick={onClick}
|
|
55
|
+
isLoading={isLoading}
|
|
55
56
|
/>
|
|
56
57
|
);
|
|
57
58
|
};
|
|
@@ -207,6 +208,7 @@ export const Vertical = () => (
|
|
|
207
208
|
<>
|
|
208
209
|
<h1>Ratio: vertical</h1>
|
|
209
210
|
<h2>Default</h2>
|
|
211
|
+
<small>Unsupported use case (thumbnail size is undefined)</small>
|
|
210
212
|
<FlexBox orientation="horizontal" vAlign="center" gap="huge">
|
|
211
213
|
<Thumbnail alt="" aspectRatio="vertical" image={IMAGES.landscape1} />
|
|
212
214
|
<Thumbnail alt="" aspectRatio="vertical" image={IMAGES.portrait1} />
|
|
@@ -260,6 +262,7 @@ export const Wide = () => (
|
|
|
260
262
|
<>
|
|
261
263
|
<h1>Ratio: wide</h1>
|
|
262
264
|
<h2>Default</h2>
|
|
265
|
+
<small>Unsupported use case (thumbnail size is undefined)</small>
|
|
263
266
|
<FlexBox orientation="horizontal" vAlign="center" gap="huge">
|
|
264
267
|
<Thumbnail alt="" aspectRatio="wide" image={IMAGES.landscape1} />
|
|
265
268
|
<Thumbnail alt="" aspectRatio="wide" image={IMAGES.portrait1} />
|
|
@@ -313,6 +316,7 @@ export const Square = () => (
|
|
|
313
316
|
<>
|
|
314
317
|
<h1>Ratio: square</h1>
|
|
315
318
|
<h2>Default</h2>
|
|
319
|
+
<small>Unsupported use case (thumbnail size is undefined)</small>
|
|
316
320
|
<FlexBox orientation="horizontal" vAlign="center" gap="huge">
|
|
317
321
|
<Thumbnail alt="" aspectRatio="square" image={IMAGES.landscape1} />
|
|
318
322
|
<Thumbnail alt="" aspectRatio="square" image={IMAGES.portrait1} />
|
|
@@ -362,27 +366,6 @@ export const Square = () => (
|
|
|
362
366
|
</>
|
|
363
367
|
);
|
|
364
368
|
|
|
365
|
-
export const ParentSizeConstraint = () => {
|
|
366
|
-
const fillHeight = boolean('Fill Height', true);
|
|
367
|
-
return Object.values(AspectRatio).map((aspectRatio) => (
|
|
368
|
-
<FlexBox key={aspectRatio} orientation="horizontal" gap="huge">
|
|
369
|
-
<h1>ratio: {aspectRatio}</h1>
|
|
370
|
-
|
|
371
|
-
<div style={{ border: '1px solid red', width: 220, height: 400, resize: 'both', overflow: 'auto' }}>
|
|
372
|
-
<Thumbnail alt="Grid" image="/demo-assets/grid.jpg" aspectRatio={aspectRatio} fillHeight={fillHeight} />
|
|
373
|
-
</div>
|
|
374
|
-
|
|
375
|
-
<div style={{ border: '1px solid red', width: 300, height: 300, resize: 'both', overflow: 'auto' }}>
|
|
376
|
-
<Thumbnail alt="Grid" image="/demo-assets/grid.jpg" aspectRatio={aspectRatio} fillHeight={fillHeight} />
|
|
377
|
-
</div>
|
|
378
|
-
|
|
379
|
-
<div style={{ border: '1px solid red', width: 400, height: 200, resize: 'both', overflow: 'auto' }}>
|
|
380
|
-
<Thumbnail alt="Grid" image="/demo-assets/grid.jpg" aspectRatio={aspectRatio} fillHeight={fillHeight} />
|
|
381
|
-
</div>
|
|
382
|
-
</FlexBox>
|
|
383
|
-
));
|
|
384
|
-
};
|
|
385
|
-
|
|
386
369
|
export const IsLoading = ({ theme }: any) => (
|
|
387
370
|
<FlexBox
|
|
388
371
|
orientation="horizontal"
|
|
@@ -394,31 +377,23 @@ export const IsLoading = ({ theme }: any) => (
|
|
|
394
377
|
theme={theme}
|
|
395
378
|
alt="Image alt text"
|
|
396
379
|
image={IMAGES.landscape2}
|
|
397
|
-
isLoading={boolean('
|
|
380
|
+
isLoading={boolean('Force loading', true)}
|
|
398
381
|
fillHeight={boolean('Fill Height', false)}
|
|
399
382
|
size={sizeKnob('Size', undefined)}
|
|
400
383
|
/>
|
|
401
384
|
</FlexBox>
|
|
402
385
|
);
|
|
403
386
|
|
|
404
|
-
export const
|
|
405
|
-
|
|
406
|
-
export const ErrorCustomIconFallback = () => <Thumbnail alt="foo" image="foo" fallback={mdiAbTesting} />;
|
|
407
|
-
|
|
408
|
-
export const ErrorCustomFallback = () => (
|
|
409
|
-
<Thumbnail alt="foo" image="foo" fallback={<Thumbnail alt="missing image" image="/logo.svg" />} />
|
|
410
|
-
);
|
|
411
|
-
|
|
412
|
-
export const ErrorFallbackVariants = () => {
|
|
413
|
-
const isLoading = boolean('is loading', false);
|
|
387
|
+
export const ErrorFallbackVariants = ({ theme }: any) => {
|
|
388
|
+
const isLoading = boolean('Force loading', false);
|
|
414
389
|
const variant = select('Variant', ThumbnailVariant, undefined);
|
|
415
|
-
const base = { alt: 'foo', image: 'foo', isLoading, variant } as const;
|
|
390
|
+
const base = { alt: 'foo', image: 'foo', isLoading, variant, theme } as const;
|
|
416
391
|
const imageFallback = <img src="/logo.svg" alt="logo" />;
|
|
417
392
|
const imgProps = { width: 50, height: 50 };
|
|
393
|
+
|
|
418
394
|
return (
|
|
419
395
|
<>
|
|
420
396
|
<h2>Default</h2>
|
|
421
|
-
Default fallback | Custom icon fallback | Custom react node fallback
|
|
422
397
|
<FlexBox orientation="horizontal" gap="big">
|
|
423
398
|
<Thumbnail {...base} />
|
|
424
399
|
<Thumbnail {...base} fallback={mdiAbTesting} />
|
|
@@ -436,7 +411,7 @@ export const ErrorFallbackVariants = () => {
|
|
|
436
411
|
<FlexBox orientation="horizontal" gap="big">
|
|
437
412
|
<Thumbnail {...base} size="xl" />
|
|
438
413
|
<Thumbnail {...base} size="xl" fallback={mdiAbTesting} />
|
|
439
|
-
<Thumbnail {...base} size="xl" fallback={imageFallback}
|
|
414
|
+
<Thumbnail {...base} size="xl" fallback={imageFallback} />
|
|
440
415
|
</FlexBox>
|
|
441
416
|
<h2>With size & ratio</h2>
|
|
442
417
|
<FlexBox orientation="horizontal" gap="big">
|
|
@@ -447,6 +422,7 @@ export const ErrorFallbackVariants = () => {
|
|
|
447
422
|
<h2>
|
|
448
423
|
With original size <small>(50x50)</small> & ratio
|
|
449
424
|
</h2>
|
|
425
|
+
<small>Unsupported use case (thumbnail size is undefined)</small>
|
|
450
426
|
<FlexBox orientation="horizontal" gap="big">
|
|
451
427
|
<Thumbnail {...base} imgProps={imgProps} aspectRatio="wide" />
|
|
452
428
|
<Thumbnail {...base} imgProps={imgProps} aspectRatio="wide" fallback={mdiAbTesting} />
|
|
@@ -9,10 +9,7 @@ import {
|
|
|
9
9
|
Clickable,
|
|
10
10
|
ClickableCustomLink,
|
|
11
11
|
ClickableLink,
|
|
12
|
-
ErrorCustomFallback,
|
|
13
12
|
Default,
|
|
14
|
-
ErrorFallback,
|
|
15
|
-
ErrorCustomIconFallback,
|
|
16
13
|
WithBadge,
|
|
17
14
|
} from './Thumbnail.stories';
|
|
18
15
|
|
|
@@ -36,9 +33,6 @@ describe(`<${Thumbnail.displayName}>`, () => {
|
|
|
36
33
|
Clickable,
|
|
37
34
|
ClickableLink,
|
|
38
35
|
ClickableCustomLink,
|
|
39
|
-
ErrorFallback,
|
|
40
|
-
ErrorCustomFallback,
|
|
41
|
-
ErrorCustomIconFallback,
|
|
42
36
|
WithBadge,
|
|
43
37
|
},
|
|
44
38
|
Thumbnail,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, {
|
|
2
|
+
CSSProperties,
|
|
2
3
|
forwardRef,
|
|
3
4
|
ImgHTMLAttributes,
|
|
4
5
|
KeyboardEventHandler,
|
|
@@ -121,7 +122,6 @@ export const Thumbnail: Comp<ThumbnailProps> = forwardRef((props, ref) => {
|
|
|
121
122
|
variant,
|
|
122
123
|
linkProps,
|
|
123
124
|
linkAs,
|
|
124
|
-
showSkeletonLoading = true,
|
|
125
125
|
...forwardedProps
|
|
126
126
|
} = props;
|
|
127
127
|
const imgRef = useRef<HTMLImageElement>(null);
|
|
@@ -131,6 +131,17 @@ export const Thumbnail: Comp<ThumbnailProps> = forwardRef((props, ref) => {
|
|
|
131
131
|
const isLoading = isLoadingProp || loadingState === 'isLoading';
|
|
132
132
|
const hasError = loadingState === 'hasError';
|
|
133
133
|
|
|
134
|
+
const hasIconErrorFallback = hasError && typeof fallback === 'string';
|
|
135
|
+
const hasCustomErrorFallback = hasError && !hasIconErrorFallback;
|
|
136
|
+
const imageErrorStyle: CSSProperties = {};
|
|
137
|
+
if (hasIconErrorFallback) {
|
|
138
|
+
// Keep the image layout on icon fallback.
|
|
139
|
+
imageErrorStyle.visibility = 'hidden';
|
|
140
|
+
} else if (hasCustomErrorFallback) {
|
|
141
|
+
// Remove the image on custom fallback.
|
|
142
|
+
imageErrorStyle.display = 'none';
|
|
143
|
+
}
|
|
144
|
+
|
|
134
145
|
const isLink = Boolean(linkProps?.href || linkAs);
|
|
135
146
|
const isButton = !!forwardedProps.onClick;
|
|
136
147
|
const isClickable = isButton || isLink;
|
|
@@ -160,7 +171,9 @@ export const Thumbnail: Comp<ThumbnailProps> = forwardRef((props, ref) => {
|
|
|
160
171
|
variant,
|
|
161
172
|
isClickable,
|
|
162
173
|
hasError,
|
|
163
|
-
|
|
174
|
+
hasIconErrorFallback,
|
|
175
|
+
hasCustomErrorFallback,
|
|
176
|
+
isLoading,
|
|
164
177
|
hasBadge: !!badge,
|
|
165
178
|
}),
|
|
166
179
|
fillHeight && `${CLASSNAME}--fill-height`,
|
|
@@ -171,8 +184,7 @@ export const Thumbnail: Comp<ThumbnailProps> = forwardRef((props, ref) => {
|
|
|
171
184
|
{...imgProps}
|
|
172
185
|
style={{
|
|
173
186
|
...imgProps?.style,
|
|
174
|
-
|
|
175
|
-
visibility: hasError ? 'hidden' : undefined,
|
|
187
|
+
...imageErrorStyle,
|
|
176
188
|
// Focus point.
|
|
177
189
|
objectPosition: getObjectPosition(aspectRatio, focusPoint),
|
|
178
190
|
}}
|
|
@@ -185,8 +197,8 @@ export const Thumbnail: Comp<ThumbnailProps> = forwardRef((props, ref) => {
|
|
|
185
197
|
/>
|
|
186
198
|
{!isLoading && hasError && (
|
|
187
199
|
<div className={`${CLASSNAME}__fallback`}>
|
|
188
|
-
{
|
|
189
|
-
<Icon icon={fallback} size={Size.xxs} theme={theme} />
|
|
200
|
+
{hasIconErrorFallback ? (
|
|
201
|
+
<Icon icon={fallback as string} size={Size.xxs} theme={theme} />
|
|
190
202
|
) : (
|
|
191
203
|
fallback
|
|
192
204
|
)}
|
|
@@ -2,24 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
exports[`<Thumbnail> Snapshots and structure should render story 'Clickable' 1`] = `
|
|
4
4
|
<button
|
|
5
|
-
className="lumx-thumbnail lumx-thumbnail--size-xxl lumx-thumbnail--theme-light lumx-thumbnail--is-clickable"
|
|
5
|
+
className="lumx-thumbnail lumx-thumbnail--aspect-ratio-original lumx-thumbnail--size-xxl lumx-thumbnail--theme-light lumx-thumbnail--is-clickable lumx-thumbnail--is-loading"
|
|
6
6
|
onClick={[Function]}
|
|
7
7
|
>
|
|
8
8
|
<div
|
|
9
9
|
className="lumx-thumbnail__background"
|
|
10
|
-
style={
|
|
11
|
-
Object {
|
|
12
|
-
"display": undefined,
|
|
13
|
-
"visibility": "hidden",
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
10
|
>
|
|
17
11
|
<img
|
|
18
12
|
alt="Click me"
|
|
19
|
-
className="lumx-thumbnail__image"
|
|
13
|
+
className="lumx-thumbnail__image lumx-thumbnail__image--is-loading"
|
|
20
14
|
loading="lazy"
|
|
21
15
|
src="/demo-assets/landscape1.jpg"
|
|
22
|
-
style={
|
|
16
|
+
style={
|
|
17
|
+
Object {
|
|
18
|
+
"objectPosition": undefined,
|
|
19
|
+
"visibility": "hidden",
|
|
20
|
+
}
|
|
21
|
+
}
|
|
23
22
|
/>
|
|
24
23
|
</div>
|
|
25
24
|
</button>
|
|
@@ -27,24 +26,23 @@ exports[`<Thumbnail> Snapshots and structure should render story 'Clickable' 1`]
|
|
|
27
26
|
|
|
28
27
|
exports[`<Thumbnail> Snapshots and structure should render story 'ClickableCustomLink' 1`] = `
|
|
29
28
|
<CustomLinkComponent
|
|
30
|
-
className="custom-class-name lumx-thumbnail lumx-thumbnail--size-xxl lumx-thumbnail--theme-light lumx-thumbnail--is-clickable"
|
|
29
|
+
className="custom-class-name lumx-thumbnail lumx-thumbnail--aspect-ratio-original lumx-thumbnail--size-xxl lumx-thumbnail--theme-light lumx-thumbnail--is-clickable lumx-thumbnail--is-loading"
|
|
31
30
|
href="https://google.fr"
|
|
32
31
|
>
|
|
33
32
|
<div
|
|
34
33
|
className="lumx-thumbnail__background"
|
|
35
|
-
style={
|
|
36
|
-
Object {
|
|
37
|
-
"display": undefined,
|
|
38
|
-
"visibility": "hidden",
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
34
|
>
|
|
42
35
|
<img
|
|
43
36
|
alt="Click me"
|
|
44
|
-
className="lumx-thumbnail__image"
|
|
37
|
+
className="lumx-thumbnail__image lumx-thumbnail__image--is-loading"
|
|
45
38
|
loading="lazy"
|
|
46
39
|
src="/demo-assets/landscape1.jpg"
|
|
47
|
-
style={
|
|
40
|
+
style={
|
|
41
|
+
Object {
|
|
42
|
+
"objectPosition": undefined,
|
|
43
|
+
"visibility": "hidden",
|
|
44
|
+
}
|
|
45
|
+
}
|
|
48
46
|
/>
|
|
49
47
|
</div>
|
|
50
48
|
</CustomLinkComponent>
|
|
@@ -52,120 +50,46 @@ exports[`<Thumbnail> Snapshots and structure should render story 'ClickableCusto
|
|
|
52
50
|
|
|
53
51
|
exports[`<Thumbnail> Snapshots and structure should render story 'ClickableLink' 1`] = `
|
|
54
52
|
<a
|
|
55
|
-
className="lumx-thumbnail lumx-thumbnail--size-xxl lumx-thumbnail--theme-light lumx-thumbnail--is-clickable"
|
|
53
|
+
className="lumx-thumbnail lumx-thumbnail--aspect-ratio-original lumx-thumbnail--size-xxl lumx-thumbnail--theme-light lumx-thumbnail--is-clickable lumx-thumbnail--is-loading"
|
|
56
54
|
href="https://google.fr"
|
|
57
55
|
>
|
|
58
56
|
<div
|
|
59
57
|
className="lumx-thumbnail__background"
|
|
60
|
-
style={
|
|
61
|
-
Object {
|
|
62
|
-
"display": undefined,
|
|
63
|
-
"visibility": "hidden",
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
58
|
>
|
|
67
59
|
<img
|
|
68
60
|
alt="Click me"
|
|
69
|
-
className="lumx-thumbnail__image"
|
|
61
|
+
className="lumx-thumbnail__image lumx-thumbnail__image--is-loading"
|
|
70
62
|
loading="lazy"
|
|
71
63
|
src="/demo-assets/landscape1.jpg"
|
|
72
|
-
style={
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
exports[`<Thumbnail> Snapshots and structure should render story 'CustomFallback' 1`] = `
|
|
79
|
-
<div
|
|
80
|
-
className="lumx-thumbnail lumx-thumbnail--theme-light"
|
|
81
|
-
>
|
|
82
|
-
<div
|
|
83
|
-
className="lumx-thumbnail__background"
|
|
84
|
-
style={
|
|
85
|
-
Object {
|
|
86
|
-
"display": undefined,
|
|
87
|
-
"visibility": "hidden",
|
|
64
|
+
style={
|
|
65
|
+
Object {
|
|
66
|
+
"objectPosition": undefined,
|
|
67
|
+
"visibility": "hidden",
|
|
68
|
+
}
|
|
88
69
|
}
|
|
89
|
-
}
|
|
90
|
-
>
|
|
91
|
-
<img
|
|
92
|
-
alt="foo"
|
|
93
|
-
className="lumx-thumbnail__image"
|
|
94
|
-
loading="lazy"
|
|
95
|
-
src="foo"
|
|
96
|
-
style={Object {}}
|
|
97
70
|
/>
|
|
98
71
|
</div>
|
|
99
|
-
</
|
|
72
|
+
</a>
|
|
100
73
|
`;
|
|
101
74
|
|
|
102
75
|
exports[`<Thumbnail> Snapshots and structure should render story 'Default' 1`] = `
|
|
103
76
|
<div
|
|
104
|
-
className="lumx-thumbnail lumx-thumbnail--
|
|
77
|
+
className="lumx-thumbnail lumx-thumbnail--aspect-ratio-original lumx-thumbnail--theme-light lumx-thumbnail--variant-squared lumx-thumbnail--is-loading"
|
|
105
78
|
>
|
|
106
79
|
<div
|
|
107
80
|
className="lumx-thumbnail__background"
|
|
108
|
-
style={
|
|
109
|
-
Object {
|
|
110
|
-
"display": undefined,
|
|
111
|
-
"visibility": "hidden",
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
81
|
>
|
|
115
82
|
<img
|
|
116
83
|
alt="Image alt text"
|
|
117
|
-
className="lumx-thumbnail__image"
|
|
84
|
+
className="lumx-thumbnail__image lumx-thumbnail__image--is-loading"
|
|
118
85
|
loading="lazy"
|
|
119
86
|
src="/demo-assets/landscape1.jpg"
|
|
120
|
-
style={
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
exports[`<Thumbnail> Snapshots and structure should render story 'DefaultFallback' 1`] = `
|
|
127
|
-
<div
|
|
128
|
-
className="lumx-thumbnail lumx-thumbnail--theme-light"
|
|
129
|
-
>
|
|
130
|
-
<div
|
|
131
|
-
className="lumx-thumbnail__background"
|
|
132
|
-
style={
|
|
133
|
-
Object {
|
|
134
|
-
"display": undefined,
|
|
135
|
-
"visibility": "hidden",
|
|
87
|
+
style={
|
|
88
|
+
Object {
|
|
89
|
+
"objectPosition": undefined,
|
|
90
|
+
"visibility": "hidden",
|
|
91
|
+
}
|
|
136
92
|
}
|
|
137
|
-
}
|
|
138
|
-
>
|
|
139
|
-
<img
|
|
140
|
-
alt="foo"
|
|
141
|
-
className="lumx-thumbnail__image"
|
|
142
|
-
loading="lazy"
|
|
143
|
-
src="foo"
|
|
144
|
-
style={Object {}}
|
|
145
|
-
/>
|
|
146
|
-
</div>
|
|
147
|
-
</div>
|
|
148
|
-
`;
|
|
149
|
-
|
|
150
|
-
exports[`<Thumbnail> Snapshots and structure should render story 'IconFallback' 1`] = `
|
|
151
|
-
<div
|
|
152
|
-
className="lumx-thumbnail lumx-thumbnail--theme-light"
|
|
153
|
-
>
|
|
154
|
-
<div
|
|
155
|
-
className="lumx-thumbnail__background"
|
|
156
|
-
style={
|
|
157
|
-
Object {
|
|
158
|
-
"display": undefined,
|
|
159
|
-
"visibility": "hidden",
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
>
|
|
163
|
-
<img
|
|
164
|
-
alt="foo"
|
|
165
|
-
className="lumx-thumbnail__image"
|
|
166
|
-
loading="lazy"
|
|
167
|
-
src="foo"
|
|
168
|
-
style={Object {}}
|
|
169
93
|
/>
|
|
170
94
|
</div>
|
|
171
95
|
</div>
|
|
@@ -173,23 +97,22 @@ exports[`<Thumbnail> Snapshots and structure should render story 'IconFallback'
|
|
|
173
97
|
|
|
174
98
|
exports[`<Thumbnail> Snapshots and structure should render story 'WithBadge' 1`] = `
|
|
175
99
|
<div
|
|
176
|
-
className="lumx-thumbnail lumx-thumbnail--aspect-ratio-square lumx-thumbnail--size-l lumx-thumbnail--theme-light lumx-thumbnail--variant-rounded lumx-thumbnail--has-badge"
|
|
100
|
+
className="lumx-thumbnail lumx-thumbnail--aspect-ratio-square lumx-thumbnail--size-l lumx-thumbnail--theme-light lumx-thumbnail--variant-rounded lumx-thumbnail--is-loading lumx-thumbnail--has-badge"
|
|
177
101
|
>
|
|
178
102
|
<div
|
|
179
103
|
className="lumx-thumbnail__background"
|
|
180
|
-
style={
|
|
181
|
-
Object {
|
|
182
|
-
"display": undefined,
|
|
183
|
-
"visibility": "hidden",
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
104
|
>
|
|
187
105
|
<img
|
|
188
106
|
alt="Image alt text"
|
|
189
|
-
className="lumx-thumbnail__image"
|
|
107
|
+
className="lumx-thumbnail__image lumx-thumbnail__image--is-loading"
|
|
190
108
|
loading="lazy"
|
|
191
109
|
src="/demo-assets/landscape1.jpg"
|
|
192
|
-
style={
|
|
110
|
+
style={
|
|
111
|
+
Object {
|
|
112
|
+
"objectPosition": undefined,
|
|
113
|
+
"visibility": "hidden",
|
|
114
|
+
}
|
|
115
|
+
}
|
|
193
116
|
/>
|
|
194
117
|
</div>
|
|
195
118
|
<Badge
|
|
@@ -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 = (
|
|
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
|
|
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 = (
|
|
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
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
|
117
|
+
handleBasicClasses({ prefix: CLASSNAME, orientation, size: componentSize, theme }),
|
|
143
118
|
)}
|
|
144
119
|
onMouseLeave={onMouseLeave}
|
|
145
120
|
onMouseEnter={onMouseEnter}
|
|
146
121
|
>
|
|
147
122
|
{avatarProps && (
|
|
148
|
-
<
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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`}>
|