Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: rework Avatar, User and UserLabel components #1991

Merged
merged 1 commit into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions playwright/core/expectScreenshotFixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ export const expectScreenshotFixture: PlaywrightFixture<ExpectScreenshotFixture>

const themes = paramsThemes || defaultParams.themes;

// Wait for loading of all the images
const locators = await page.locator('//img').all();
await Promise.all(
locators.map((locator) =>
locator.evaluate(
(image: HTMLImageElement) =>
image.complete ||
new Promise<unknown>((resolve) => image.addEventListener('load', resolve)),
),
),
);

if (themes?.includes('light')) {
await page.emulateMedia({colorScheme: 'light'});

Expand Down
2 changes: 0 additions & 2 deletions playwright/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ const config: PlaywrightTestConfig = {
updateSnapshots: process.env.UPDATE_REQUEST ? 'all' : 'missing',
snapshotPathTemplate:
'{testDir}/{testFileDir}/../__snapshots__/{testFileName}-snapshots/{arg}{-projectName}-linux{ext}',
/* The base directory, relative to the config file, for snapshot files created with toMatchSnapshot and toHaveScreenshot. */
/* Maximum time one test can run for. */
timeout: 10 * 1000,
/* Run tests in files in parallel */
Expand All @@ -52,7 +51,6 @@ const config: PlaywrightTestConfig = {
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
headless: true,
/* Port to use for Playwright component endpoint. */
screenshot: 'only-on-failure',
timezoneId: 'UTC',
ctCacheDir: process.env.IS_DOCKER ? '.cache-docker' : '.cache',
Expand Down
22 changes: 11 additions & 11 deletions scripts/playwright-docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ command_exists() {
}

run_command() {
$CONTAINER_TOOL run --rm --network host -it -w /work \
-v $(pwd):/work \
-v "$NODE_MODULES_CACHE_DIR:/work/node_modules" \
-e IS_DOCKER=1 \
"$IMAGE_NAME:$IMAGE_TAG" \
/bin/bash -c "$1"
$CONTAINER_TOOL run --rm --network host -it -w /work \
-v $(pwd):/work \
-v "$NODE_MODULES_CACHE_DIR:/work/node_modules" \
-e IS_DOCKER=1 \
"$IMAGE_NAME:$IMAGE_TAG" \
/bin/bash -c "$1"
}

if command_exists docker; then
Expand All @@ -30,14 +30,14 @@ else
fi

if [[ "$1" = "clear-cache" ]]; then
rm -rf "$NODE_MODULES_CACHE_DIR"
rm -rf "./playwright/.cache-docker"
exit 0
rm -rf "$NODE_MODULES_CACHE_DIR"
rm -rf "./playwright/.cache-docker"
exit 0
fi

if [[ ! -d "$NODE_MODULES_CACHE_DIR" ]]; then
mkdir -p "$NODE_MODULES_CACHE_DIR"
run_command 'npm ci'
mkdir -p "$NODE_MODULES_CACHE_DIR"
run_command 'npm ci'
fi

run_command "$1"
96 changes: 58 additions & 38 deletions src/components/Avatar/Avatar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ $block: '.#{variables.$ns}avatar';

#{$block} {
--_--size: #{avatar-variables.$default-size};
--_--background-color: var(--g-color-base-misc-light);
--_--border-width: 2px;
--_--inner-border-width: 3px;
--_--border-color: currentColor;
--_--color: var(--g-color-text-misc);
--_--background-color: var(--g-color-base-misc-light);
--_--text-color: var(--g-color-text-misc);
--_--font-weight: var(--g-text-body-font-weight);
--_--font-size: var(--g-text-body-1-font-size);
--_--line-height: var(--g-text-body-1-line-height);
--_--font-weight: var(--g-text-body-font-weight);

overflow: hidden;
display: inline-flex;
Expand All @@ -21,28 +23,6 @@ $block: '.#{variables.$ns}avatar';
border-radius: 50%;
background-color: var(--g-avatar-background-color, var(--_--background-color));

&__image {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}

&__icon {
color: var(--g-avatar-color, var(--_--color));

& > svg {
display: block;
}
}

&__text {
color: var(--g-avatar-color, var(--_--color));
font-size: var(--g-avatar-font-size, var(--_--font-size));
line-height: var(--g-avatar-line-height, var(--_--line-height));
font-weight: var(--_--font-weight);
}

&_with-border,
&_view_outlined {
position: relative;
Expand All @@ -57,11 +37,13 @@ $block: '.#{variables.$ns}avatar';
}

&::before {
border: 3px solid var(--g-color-base-background);
border: var(--g-avatar-inner-border-width, var(--_--inner-border-width)) solid
var(--g-color-base-background);
}

&::after {
border: 2px solid var(--g-avatar-border-color, var(--_--border-color));
border: var(--g-avatar-border-width, var(--_--border-width)) solid
var(--g-avatar-border-color, var(--_--border-color));
}
}

Expand All @@ -72,30 +54,46 @@ $block: '.#{variables.$ns}avatar';
}
}

&_2xs {
&_3xs,
&_2xs,
&_xs {
--_--font-weight: var(--g-text-caption-font-weight);
--_--font-size: var(--g-text-caption-1-font-size);
--_--line-height: var(--g-text-caption-1-line-height);
--_--font-weight: var(--g-text-caption-font-weight);
}

&_xs,
&_s {
--_--font-size: var(--g-text-caption-1-font-size);
--_--line-height: var(--g-text-caption-1-line-height);
--_--font-weight: var(--g-text-caption-font-weight);
--_--font-size: var(--g-text-caption-2-font-size);
--_--line-height: var(--g-text-caption-2-line-height);
}

&_m,
&_l {
--_--font-weight: var(--g-text-subheader-font-weight);
--_--font-size: var(--g-text-subheader-1-font-size);
--_--line-height: var(--g-text-subheader-1-line-height);
--_--font-weight: var(--g-text-subheader-font-weight);
}

&_xl {
--_--font-weight: var(--g-text-subheader-font-weight);
--_--font-size: var(--g-text-subheader-2-font-size);
--_--line-height: var(--g-text-subheader-2-line-height);
--_--font-weight: var(--g-text-subheader-font-weight);
}

&_3xs,
&_2xs {
--_--border-width: 1.5px;
--_--inner-border-width: 2.5px;
}

&_xs,
&_s,
&_m,
&_l,
&_xl {
--_--border-width: 2px;
--_--inner-border-width: 3px;
}
}

Expand All @@ -104,13 +102,13 @@ $block: '.#{variables.$ns}avatar';
&#{$block}_view {
&_filled {
--_--background-color: var(--g-color-base-misc-light);
--_--color: var(--g-color-text-misc);
--_--text-color: var(--g-color-text-misc);
}

&_outlined {
--_--background-color: var(--g-color-base-background);
--_--border-color: var(--g-color-text-misc);
--_--color: var(--g-color-text-misc);
--_--text-color: var(--g-color-text-misc);
}
}
}
Expand All @@ -119,15 +117,37 @@ $block: '.#{variables.$ns}avatar';
&#{$block}_view {
&_filled {
--_--background-color: var(--g-color-base-brand);
--_--color: var(--g-color-text-brand-contrast);
--_--text-color: var(--g-color-text-brand-contrast);
}

&_outlined {
--_--background-color: var(--g-color-base-background);
--_--border-color: var(--g-color-text-brand);
--_--color: var(--g-color-text-brand);
--_--text-color: var(--g-color-text-brand);
}
}
}
}

&__image {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}

&__icon {
color: var(--g-avatar-text-color, var(--_--text-color));

& > svg {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we need it? Looks unreliable

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is used to center svg element in the icon properly

display: block;
}
}

&__text {
color: var(--g-avatar-text-color, var(--_--text-color));
font-weight: var(--g-avatar-font-weight, var(--_--font-weight));
font-size: var(--g-avatar-font-size, var(--_--font-size));
line-height: var(--g-avatar-line-height, var(--_--line-height));
}
}
6 changes: 2 additions & 4 deletions src/components/Avatar/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';

import {block} from '../utils/cn';
import {filterDOMProps} from '../utils/filterDOMProps';

import {AvatarIcon} from './AvatarIcon';
import {AvatarImage} from './AvatarImage';
Expand All @@ -20,8 +21,6 @@ export const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>((props, ref)
backgroundColor,
borderColor,
title,
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledby,
className,
style: styleProp,
qa,
Expand Down Expand Up @@ -75,11 +74,10 @@ export const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>((props, ref)
className={b({size, theme, view, 'with-border': Boolean(borderColor)}, className)}
title={title}
role="img"
aria-label={ariaLabel}
aria-labelledby={ariaLabelledby}
style={style}
data-qa={qa}
ref={ref}
{...filterDOMProps(props, {labelable: true})}
>
{renderContent()}
</div>
Expand Down
1 change: 1 addition & 0 deletions src/components/Avatar/AvatarIcon/AvatarIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {AvatarSize} from '../types/common';
import type {AvatarIconProps} from './types';

const avatarSizeToIconSize: Record<AvatarSize, number> = {
'3xs': 10,
'2xs': 12,
xs: 14,
s: 16,
Expand Down
4 changes: 2 additions & 2 deletions src/components/Avatar/AvatarText/AvatarText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import React from 'react';
import type {AvatarTextProps} from './types';
import {getAvatarDisplayText} from './utils';

export const AvatarText = ({text, color, className}: AvatarTextProps) => {
export const AvatarText = ({text, color, size, className}: AvatarTextProps) => {
const style = {color};
const displayText = getAvatarDisplayText(text);
const displayText = getAvatarDisplayText(text, size);

return (
<div style={style} className={className}>
Expand Down
18 changes: 13 additions & 5 deletions src/components/Avatar/AvatarText/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
export const getAvatarDisplayText = (text: string) => {
const words = text.split(/\s+/);
const result =
words.length > 1 ? [words[0][0], words[1][0]].filter(Boolean).join('') : text.slice(0, 2);
import type {AvatarSize} from '../types/common';

return result.toUpperCase();
export const getAvatarDisplayText = (text: string, size: AvatarSize) => {
if (size === '3xs') {
return text[0].toUpperCase();
}

const words = text.split(/[^a-zA-Z]+/);

if (words.length <= 1) {
return text.slice(0, 2).toUpperCase();
}

return [words[0][0], words[1][0]].filter(Boolean).join('').toUpperCase();
};
51 changes: 29 additions & 22 deletions src/components/Avatar/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,13 @@ LANDING_BLOCK-->

### Size

To control the size of the `Avatar` use the `size` property. The default size is `m`. Possible values: `2xs`, `xs`, `s`, `m`, `l`, `xl`.
To control the size of the `Avatar` use the `size` property. The default size is `m`. Possible values: `3xs`, `2xs`, `xs`, `s`, `m`, `l`, `xl`.

<!--LANDING_BLOCK

<ExampleBlock
code={`
<Avatar text="Charles Darwin" theme="brand" size="3xs" />
<Avatar text="Charles Darwin" theme="brand" size="2xs" />
<Avatar text="Charles Darwin" theme="brand" size="xs" />
<Avatar text="Charles Darwin" theme="brand" size="s" />
Expand All @@ -155,6 +156,7 @@ To control the size of the `Avatar` use the `size` property. The default size is
<Avatar text="Charles Darwin" theme="brand" size="xl" />
`}
>
<UIKit.Avatar text="Charles Darwin" theme="brand" size="3xs" />
<UIKit.Avatar text="Charles Darwin" theme="brand" size="2xs" />
<UIKit.Avatar text="Charles Darwin" theme="brand" size="xs" />
<UIKit.Avatar text="Charles Darwin" theme="brand" size="s" />
Expand All @@ -169,19 +171,21 @@ LANDING_BLOCK-->

### Common

| Name | Description | Type | Default |
| :-------------- | :-------------------------------------- | :-------------------------------------: | :------: |
| size | Avatar size | `'2xs'` `'xs'` `'s'` `'m'` `'l'` `'xl'` | `m` |
| theme | Avatar theme | `'normal'` `'brand'` | `normal` |
| view | Avatar view | `'filled'` `'outlined'` | `filled` |
| backgroundColor | Custom background color | `string` | |
| borderColor | Custom border color | `string` | |
| title | HTML `title` attributes | `string` | |
| aria-label | `aria-label` for avatar block | `string` | |
| aria-labelledby | `aria-labelledby` for avatar block | `string` | |
| className | Custom CSS class for root element | `string` | |
| style | HTML style attribute | `React.CSSProperties` | |
| qa | HTML `data-qa` attribute, used in tests | `string` | |
| Name | Description | Type | Default |
| :--------------- | :-------------------------------------- | :---------------------------------------------: | :------: |
| size | Avatar size | `'3xs'` `'2xs'` `'xs'` `'s'` `'m'` `'l'` `'xl'` | `m` |
| theme | Avatar theme | `'normal'` `'brand'` | `normal` |
| view | Avatar view | `'filled'` `'outlined'` | `filled` |
| backgroundColor | Custom background color | `string` | |
| borderColor | Custom border color | `string` | |
| title | HTML `title` attributes | `string` | |
| aria-label | `aria-label` for avatar block | `string` | |
| aria-labelledby | `aria-labelledby` for avatar block | `string` | |
| aria-describedby | `aria-describedby` for avatar block | `string` | |
| aria-details | `aria-details` for avatar block | `string` | |
| className | Custom CSS class for root element | `string` | |
| style | HTML style attribute | `React.CSSProperties` | |
| qa | HTML `data-qa` attribute, used in tests | `string` | |

### Image-specific

Expand Down Expand Up @@ -210,11 +214,14 @@ LANDING_BLOCK-->

## CSS API

| Name | Description |
| :---------------------------- | :---------------------- |
| `--g-avatar-size` | Size (width and height) |
| `--g-avatar-background-color` | Background color |
| `--g-avatar-border-color` | Border color |
| `--g-avatar-color` | Icon and text color |
| `--g-avatar-font-size` | Text font size |
| `--g-avatar-line-height` | Text line height |
| Name | Description |
| :------------------------------ | :---------------------- |
| `--g-avatar-size` | Size (width and height) |
| `--g-avatar-border-width` | Border width |
| `--g-avatar-inner-border-width` | Inner border width |
| `--g-avatar-border-color` | Border color |
| `--g-avatar-background-color` | Background color |
| `--g-avatar-text-color` | Icon and text color |
| `--g-avatar-font-weight` | Text font weight |
| `--g-avatar-font-size` | Text font size |
| `--g-avatar-line-height` | Text line height |
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Loading
Loading