Skip to content

Commit

Permalink
Merge branch 'main' into feat/divider-render-content
Browse files Browse the repository at this point in the history
  • Loading branch information
blasdfaa authored Jul 19, 2024
2 parents 0c4f76b + 23c2e54 commit a4d69ab
Show file tree
Hide file tree
Showing 68 changed files with 917 additions and 101 deletions.
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
# Changelog

## [6.21.0](https://github.com/gravity-ui/uikit/compare/v6.20.1...v6.21.0) (2024-07-16)


### Features

* **PinInput:** form support ([#1686](https://github.com/gravity-ui/uikit/issues/1686)) ([b82262e](https://github.com/gravity-ui/uikit/commit/b82262e6ac3ac656f0d87a6275a081f9990aeb6a))
* **Select:** new label and value resize behaviour ([#1694](https://github.com/gravity-ui/uikit/issues/1694)) ([891fa88](https://github.com/gravity-ui/uikit/commit/891fa886ce5b2d9c8753abbfe49f833ff35619a6))
* **TreeList:** add ListTreeItemType interface export and id argument to renderItem prop ([#1707](https://github.com/gravity-ui/uikit/issues/1707)) ([de544b8](https://github.com/gravity-ui/uikit/commit/de544b871f722fe63f677e17f4272767bebf973e))
* **TreeSelect:** add placeholder prop ([#1705](https://github.com/gravity-ui/uikit/issues/1705)) ([88696a3](https://github.com/gravity-ui/uikit/commit/88696a3f529c44dc9bd17024c926a77fea67acaa))
* **useControlledState:** support update callback with additional params ([#1688](https://github.com/gravity-ui/uikit/issues/1688)) ([8bff882](https://github.com/gravity-ui/uikit/commit/8bff8821b4e8bb20e1bedb01c07a3ba8f22dfe16))
* **useResizeObserver:** support box option ([#1687](https://github.com/gravity-ui/uikit/issues/1687)) ([a178dff](https://github.com/gravity-ui/uikit/commit/a178dffefb2d1cfa481417a2dea6297034ae22a0))


### Bug Fixes

* **Avatar:** update text font weight ([#1684](https://github.com/gravity-ui/uikit/issues/1684)) ([0ae513a](https://github.com/gravity-ui/uikit/commit/0ae513a2e2a595f2cc7f5d0b2fe532a6f7f46b03))
* **ListItemView:** div -> li default list item html tag ([#1698](https://github.com/gravity-ui/uikit/issues/1698)) ([07a16c9](https://github.com/gravity-ui/uikit/commit/07a16c959198bedfa45dbb14b5ad804bd11a6d82))
* **Sheet:** fix incorrect content height calculation ([#1700](https://github.com/gravity-ui/uikit/issues/1700)) ([7e4dd23](https://github.com/gravity-ui/uikit/commit/7e4dd2374cb83f72168e0b2fc416fa76dd6fbe6e))
* **TextArea:** fix content width & height styles ([#1690](https://github.com/gravity-ui/uikit/issues/1690)) ([94979cf](https://github.com/gravity-ui/uikit/commit/94979cf8c43194dd347481929dc1e217ac2bd84b))
* **TreeSelect:** add disabled prop ([#1697](https://github.com/gravity-ui/uikit/issues/1697)) ([f9650da](https://github.com/gravity-ui/uikit/commit/f9650dab0b999e5efa03e2e8f513e62074083f67))
* **TreeSelect:** fix page gap on component focus in some cases ([#1708](https://github.com/gravity-ui/uikit/issues/1708)) ([cd4eb93](https://github.com/gravity-ui/uikit/commit/cd4eb93375ad7a6cfc6e4c87a92e3a20679b3047))
* **useList:** fix disabled elements activate logic ([#1706](https://github.com/gravity-ui/uikit/issues/1706)) ([f12d49f](https://github.com/gravity-ui/uikit/commit/f12d49f125c189ff6ceaba86b5000920a811586d))

## [6.20.1](https://github.com/gravity-ui/uikit/compare/v6.20.0...v6.20.1) (2024-07-01)


Expand Down
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/src/components/Alert @IsaevAlexandr
/src/components/ArrowToggle @Marginy605
/src/components/Avatar @DakEnviy
/src/components/AvatarStack @ogonkov
#/src/components/Breadcrumbs
/src/components/Button @amje
/src/components/Card @Lunory
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@gravity-ui/uikit",
"version": "6.20.1",
"version": "6.21.0",
"description": "Gravity UI base styling and components",
"keywords": [
"component",
Expand Down Expand Up @@ -108,7 +108,7 @@
"lint": "run-p lint:*",
"typecheck": "tsc --noEmit",
"prepublishOnly": "npm run build && npm pkg delete engines",
"playwright:install": "playwright install --with-deps",
"playwright:install": "playwright install chromium webkit --with-deps",
"playwright": "playwright test --config=playwright/playwright.config.ts",
"playwright:update": "npm run playwright -- -u",
"playwright:docker": "./scripts/playwright-docker.sh 'npm run playwright'",
Expand Down
14 changes: 9 additions & 5 deletions src/components/Avatar/Avatar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ $block: '.#{variables.$ns}avatar';
--_--color: var(--g-color-text-misc);
--_--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 Down Expand Up @@ -39,7 +40,7 @@ $block: '.#{variables.$ns}avatar';
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: 500;
font-weight: var(--_--font-weight);
}

&_with-border,
Expand Down Expand Up @@ -75,17 +76,20 @@ $block: '.#{variables.$ns}avatar';
&_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);
}

&_m,
&_l {
--_--font-size: var(--g-text-body-1-font-size);
--_--line-height: var(--g-text-body-1-line-height);
--_--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-size: var(--g-text-body-2-font-size);
--_--line-height: var(--g-text-body-2-line-height);
--_--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);
}
}

Expand Down
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.
61 changes: 61 additions & 0 deletions src/components/AvatarStack/AvatarStack.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
@use '../../../styles/mixins';
@use '../Avatar/variables' as avatar-variables;
@use '../variables';

$block: '.#{variables.$ns}avatar-stack';

#{$block} {
--_--more-button-size: #{avatar-variables.$default-size};
--_--more-button-border-width: 1px;

display: inline-flex;
justify-content: flex-end;
flex-direction: row-reverse;

margin: 0;
padding: 0;

&_overlap-size_s {
--_--overlap: var(--g-spacing-1);
}

&_overlap-size_m {
--_--overlap: var(--g-spacing-2);
}

&_overlap-size_l {
--_--overlap: var(--g-spacing-3);
}

&__item {
display: flex;
z-index: 0;
border-radius: 100%;

&:not(:first-child) {
margin-inline-end: calc(-1 * var(--_--overlap));
}
}

&__more-button {
@include mixins.button-reset;

border-radius: 100%;

width: var(--_--more-button-size);
height: var(--_--more-button-size);

&:focus-visible {
outline: var(--g-color-line-focus) solid 2px;
outline-offset: 0;
}

&_size {
@each $size-name, $size-value in avatar-variables.$sizes {
&_#{$size-name} {
--_--more-button-size: #{$size-value};
}
}
}
}
}
69 changes: 69 additions & 0 deletions src/components/AvatarStack/AvatarStack.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React from 'react';

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

import {AvatarStackItem} from './AvatarStackItem';
import {AvatarStackMoreButton} from './AvatarStackMoreButton';
import i18n from './i18n';
import type {AvatarStackProps} from './types';

import './AvatarStack.scss';

const b = block('avatar-stack');

const AvatarStackComponent = ({
max = 3,
overlapSize = 's',
size,
children,
className,
renderMore,
}: AvatarStackProps) => {
const visibleItems: React.ReactElement[] = [];
let moreItems = 0;

React.Children.forEach(children, (child) => {
if (!React.isValidElement(child)) {
return;
}

const item = <AvatarStackItem key={visibleItems.length}>{child}</AvatarStackItem>;

if (visibleItems.length <= max) {
visibleItems.unshift(item);
} else {
moreItems += 1;
}
});

const hasMoreButton = moreItems > 0;
/** Avatars + more button, or just avatars, when avatars count is equal to `max` or less */
const normalOverflow = moreItems >= 1;

return (
// Safari remove role=list with some styles, applied to li items, so we need
// to restore role manually
// eslint-disable-next-line jsx-a11y/no-redundant-roles
<ul className={b({'overlap-size': overlapSize}, className)} role={'list'}>
{hasMoreButton ? (
<AvatarStackItem key="more-button">
{renderMore ? (
renderMore({count: moreItems})
) : (
<Avatar
text={`+${moreItems}`}
aria-label={i18n('more', {count: moreItems})}
size={size}
/>
)}
</AvatarStackItem>
) : null}
{normalOverflow ? visibleItems.slice(0, max) : visibleItems}
</ul>
);
};

AvatarStackComponent.displayName = 'AvatarStack';

export const AvatarStack = Object.assign(AvatarStackComponent, {MoreButton: AvatarStackMoreButton});
13 changes: 13 additions & 0 deletions src/components/AvatarStack/AvatarStackItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';

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

const b = block('avatar-stack');

type Props = React.PropsWithChildren<{}>;

export const AvatarStackItem = ({children}: Props) => {
return <li className={b('item')}>{children}</li>;
};

AvatarStackItem.displayName = 'AvatarStack.Item';
39 changes: 39 additions & 0 deletions src/components/AvatarStack/AvatarStackMoreButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';

import type {AvatarSize} from '../Avatar';
import {Avatar, DEFAULT_AVATAR_SIZE} from '../Avatar';
import {block} from '../utils/cn';

import i18n from './i18n';

const b = block('avatar-stack');

export type AvatarStackMoreButtonProps = Pick<
React.HTMLProps<HTMLButtonElement>,
'className' | 'onClick' | 'aria-label'
> & {
size?: AvatarSize;
count: number;
};

export const AvatarStackMoreButton = React.forwardRef<
HTMLButtonElement,
AvatarStackMoreButtonProps
>(({className, size = DEFAULT_AVATAR_SIZE, onClick, count, 'aria-label': ariaLabel}, ref) => {
return (
<button
ref={ref}
type="button"
className={b('more-button', {size}, className)}
onClick={onClick}
>
<Avatar
text={`+${count}`}
size={size}
aria-label={ariaLabel || i18n('more', {count})}
/>
</button>
);
});

AvatarStackMoreButton.displayName = 'AvatarStack.MoreButton';
52 changes: 52 additions & 0 deletions src/components/AvatarStack/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<!--GITHUB_BLOCK-->

# AvatarStack

<!--/GITHUB_BLOCK-->

```ts
import {AvatarStack} from '@gravity-ui/uikit';
```

Stack of images with overlap over next image and optional control. This is usually users avatars.

## Usage

Component is not limit you to what components to render, basic usage is:

```tsx
<AvatarStack>
<Avatar imgUrl={`https://i.pravatar.cc/150?u=login1`} />
<Avatar imgUrl={`https://i.pravatar.cc/150?u=login2`} />
<Avatar imgUrl={`https://i.pravatar.cc/150?u=login3`} />
</AvatarStack>
```

## Properties

| Name | Description | Type | Default |
| :---------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------: | :-----: |
| max | How much avatars should be visible before more button. If avatars count is only 1 short from `max`, than more button would be replaced with avatar. | `number` | 3 |
| overlapSize | How much each item should overlap next one. `s` recommended for `Avatar`'s of sizes `xs`-`m`, `m` recomended for `l` size avatars and `l` overlap for `xl` avatars | `s`, `m`, `l` | `s` |
| size | Size for control displaying extra avatars. Value same to `Avatar` size. | `AvatarSize` | |
| className | Class name of root DOM node | `string` | |
| children | List of avatars, probably with some extra wrappers | `Object[]` | |
| renderMore | Custom render for control displaying extra avatars | `function(options: {count: number}): ReactElement` | |

### AvatarStack.MoreButton

Component for overriding more button

```tsx
<AvatarStack
renderMore={({count}) => (
<Tooltip content={'More users'}>
<AvatarStack.MoreButton count={count} />
</Tooltip>
)}
>
<Avatar imgUrl={`https://i.pravatar.cc/150?u=login1`} />
<Avatar imgUrl={`https://i.pravatar.cc/150?u=login2`} />
<Avatar imgUrl={`https://i.pravatar.cc/150?u=login3`} />
</AvatarStack>
```
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.
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.
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.
139 changes: 139 additions & 0 deletions src/components/AvatarStack/__stories__/AvatarStack.stories.tsx

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions src/components/AvatarStack/__tests__/AvatarStack.visual.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';

import {test} from '~playwright/core';

import {AvatarStackStories} from './stories';

test.describe('AvatarStack', () => {
test('render story <SingleItem>', async ({mount, expectScreenshot}) => {
await mount(<AvatarStackStories.SingleItem randomAvatar={false} />);

await expectScreenshot();
});

test('render story <MoreButton>', async ({mount, expectScreenshot}) => {
await mount(<AvatarStackStories.MoreButton randomAvatar={false} />);

await expectScreenshot();
});

test('render story <MoreButtonOmit>', async ({mount, expectScreenshot}) => {
await mount(<AvatarStackStories.MoreButtonOmit randomAvatar={false} />);

await expectScreenshot();
});
});
5 changes: 5 additions & 0 deletions src/components/AvatarStack/__tests__/stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {composeStories} from '@storybook/react';

import * as CSFStories from '../__stories__/AvatarStack.stories';

export const AvatarStackStories = composeStories(CSFStories);
3 changes: 3 additions & 0 deletions src/components/AvatarStack/i18n/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"more": ["and {{count}} more", "and {{count}} more", "and {{count}} more"]
}
8 changes: 8 additions & 0 deletions src/components/AvatarStack/i18n/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {addComponentKeysets} from '../../utils/addComponentKeysets';

import en from './en.json';
import ru from './ru.json';

const COMPONENT = 'AvatarStack';

export default addComponentKeysets({en, ru}, COMPONENT);
3 changes: 3 additions & 0 deletions src/components/AvatarStack/i18n/ru.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"more": ["И eщё {{count}}", "И eщё {{count}}", "И eщё {{count}}"]
}
Loading

0 comments on commit a4d69ab

Please sign in to comment.