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: add FilePreview component #79

Merged
merged 14 commits into from
Aug 23, 2023
Merged

feat: add FilePreview component #79

merged 14 commits into from
Aug 23, 2023

Conversation

KirillDyachkovskiy
Copy link
Contributor

No description provided.

@gravity-ui-bot
Copy link
Contributor

Preview is ready.

@KirillDyachkovskiy KirillDyachkovskiy changed the title feat(FilePreview): add FilePreview component feat: add FilePreview component Jul 23, 2023

URL.revokeObjectURL(createdUrl);
};
}, [file]);

Choose a reason for hiding this comment

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

Shouldn't there be previewSrc in dependencies list?

} catch (err) {}

return () => {
if (!createdUrl) return;
Copy link
Contributor

Choose a reason for hiding this comment

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

just return it inside try..catch

import {FilePreview} from '../FilePreview';
import {CircleExclamation} from '@gravity-ui/icons';

describe('FilePreview', () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

I suggest to not to add wrappers for tests, this is already covered by Jest itself

Comment on lines 5 to 9
className,
file,
description,
onClick,
actions,
Copy link
Contributor

Choose a reason for hiding this comment

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

is it still needed?

actions?: FilePreviewActionProps[];
}

export const FilePreview: FC<FilePreviewProps> = ({
Copy link
Contributor

Choose a reason for hiding this comment

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

add diplayName please

Copy link
Contributor

Choose a reason for hiding this comment

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

Or use raw function instead, FC type has no advantages

src/components/FilePreview/FilePreviewAction.tsx Outdated Show resolved Hide resolved

export const FilePreviewAction: FC<FilePreviewActionProps> = ({icon, title, href, onClick}) => {
const button = (
<Button
Copy link
Contributor

Choose a reason for hiding this comment

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

button must have aria-label, to be accessible

</Tooltip>
)}
</Card>
<div className={cn('actions')}>
Copy link
Contributor

Choose a reason for hiding this comment

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

should it be rendered, if actions didn't exist?

@@ -0,0 +1,23 @@
import {FileType} from './FilePreview';
Copy link
Contributor

Choose a reason for hiding this comment

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

may be move FileType to types.ts?


padding: 4px 10px;

&-icon {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm personally prefer not to split Element name via & (OK if it is Modificator), but that not a hard rule

src/components/FilePreview/FilePreview.tsx Show resolved Hide resolved
href={href}
target="_blank"
size="s"
aria-label={title || 'FilePreview action'}
Copy link
Contributor

Choose a reason for hiding this comment

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

That should be explicitly set by user, it should not be omited

position: absolute;
top: -10px;
right: -10px;
z-index: 10;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why 10?

&__actions {
position: absolute;
top: -10px;
right: -10px;
Copy link
Contributor

Choose a reason for hiding this comment

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

this 10px is because of padding 10px in __card?

| Property | Type | Required | Default | Description |
| -------- | ---------- | -------- | ------- | -------------------- |
| icon | `String` | yes | | Action icon |
| title | `String` | | | Action hint on hover |
Copy link
Contributor

Choose a reason for hiding this comment

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

required

href={href}
target="_blank"
size="s"
aria-label={title}
Copy link
Contributor

Choose a reason for hiding this comment

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

may be we should separate aria-label and tooltip text?

<Card className={cn('card')} view="clear" type="selection" onClick={onClick}>
{typeof imageSrc === 'string' ? (
<div className={cn('card-image')}>
<img className={cn('card-image-img')} src={imageSrc} alt={file.name} />
Copy link
Contributor

Choose a reason for hiding this comment

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

alt here is looks redundant, since we have visible file name

i suggest we should use aria-labelledby with id of visible text with filename


const filePreview = screen.getByTestId(qaId);

expect(filePreview).toBeDefined();
Copy link
Contributor

Choose a reason for hiding this comment

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

this always will be true, since get* will fail when element is not present

const filePreview = screen.getByText(fileName);

const user = userEvent.setup();
await act(() => user.click(filePreview));
Copy link
Contributor

Choose a reason for hiding this comment

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

why act?

usually it just

await userEvent.click(...)
``

/>,
);

const actions = screen.getAllByRole('button');
Copy link
Contributor

Choose a reason for hiding this comment

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

check by name

screen.getByRole('button', {name: 'some hint'});

@@ -0,0 +1,129 @@
import React, {useEffect, useId, useState} from 'react';
Copy link
Contributor

Choose a reason for hiding this comment

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

useId usage is breaking change, this library is compatible up to react 16, as peerDependencies

<Icon className={cn('icon-svg')} data={FILE_ICON[type]} size={20} />
</div>
)}
<Tooltip id={`${id}-file-name`} content={file.name}>
Copy link
Contributor

Choose a reason for hiding this comment

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

this id is html attribute, that should be globally unique, i guess it's would be better to add some component prefix here like gc-file-preview-${id}-file-name

<div className={cn('actions')}>
{actions.map((action, index) => (
<FilePreviewAction
key={`${id}-file-actions-${index}`}
Copy link
Contributor

Choose a reason for hiding this comment

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

id is not unique enough?

onClick,
}) => (
<Tooltip id={id} content={<Text variant="caption-2">{title}</Text>}>
{
Copy link
Contributor

Choose a reason for hiding this comment

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

this is required?

);

const firstAction = screen.getByRole('button', {name: firstActionText});
expect(firstAction).toBeDefined();
Copy link
Contributor

Choose a reason for hiding this comment

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

this actually always be true, since get* throws when node could not be found

@@ -54,7 +54,7 @@
"@gravity-ui/prettier-config": "^1.0.1",
"@gravity-ui/stylelint-config": "^2.0.0",
"@gravity-ui/tsconfig": "^1.0.0",
"@gravity-ui/uikit": "^5.0.0",
Copy link
Contributor

Choose a reason for hiding this comment

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

Update version in peers aswell

actions,
}) => {
const defaultId = useUniqId();
const id = outerId ?? defaultId;
Copy link
Contributor

Choose a reason for hiding this comment

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

outerId is not required, id is for component itself, there is no need or user to override ids required for a11y

| id | `String` | | | Action id |
| icon | `String` | ✓ | | Action icon |
| title | `String` | ✓ | | Action hint on hover |
| label | `String` | | `title` | Action aria-label value |
Copy link
Contributor

@ogonkov ogonkov Aug 10, 2023

Choose a reason for hiding this comment

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

you mean value of title prop?

}

export const FilePreviewAction: FC<FilePreviewActionProps> = ({
id,
Copy link
Contributor

Choose a reason for hiding this comment

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

Generate this id in component, there is no point ti pass id that required only for a11y

src/components/FilePreview/FilePreviewAction.tsx Outdated Show resolved Hide resolved
actions?: FilePreviewActionProps[];
}

export const FilePreview: FC<FilePreviewProps> = ({
Copy link
Contributor

Choose a reason for hiding this comment

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

Or use raw function instead, FC type has no advantages

src/components/FilePreview/FilePreview.tsx Outdated Show resolved Hide resolved
src/components/FilePreview/FilePreview.tsx Outdated Show resolved Hide resolved
src/components/FilePreview/FilePreviewAction.tsx Outdated Show resolved Hide resolved
src/components/FilePreview/FilePreview.tsx Outdated Show resolved Hide resolved
src/components/FilePreview/index.ts Outdated Show resolved Hide resolved
src/components/FilePreview/index.ts Show resolved Hide resolved
#{$block} {
--gc-file-preview-box-shadow: none;
--gc-file-preview-border-radius: 4px;
--gc-file-preview-color-base-background: transparent;
Copy link
Contributor

Choose a reason for hiding this comment

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

Use "private" prefix here: --_--box-shadow. And don't use component name

<img
className={cn('image-img')}
src={previewSrc}
aria-labelledby={`${id}-file-name`}
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the purpose of this? img don't need an accessible name, it's not interactive. Besides, this id is not used anywhere else

view="raised"
pin="circle-circle"
href={href}
target="_blank"
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure if _blank should be the default.

@KirillDyachkovskiy KirillDyachkovskiy changed the title feat: add FilePreview component fix: add FilePreview component Aug 21, 2023
@KirillDyachkovskiy KirillDyachkovskiy changed the title fix: add FilePreview component feat: add FilePreview component Aug 21, 2023
$smallRoundedButtonSize: 24px;

#{$block} {
--gc-_-box-shadow: none;
Copy link
Contributor

Choose a reason for hiding this comment

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

no need in gc prefix these vars are local anyway. Let's follow the pattern --_--{name}, so it will be --_--box-shadow

| id | `String` | | | Action id |
| icon | `String` | ✓ | | Action icon |
| title | `String` | ✓ | | Action hint on hover |
| label | `String` | | `title` | Action aria-label value |
Copy link
Contributor

Choose a reason for hiding this comment

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

We decided to remove this prop, and add extraProps


import {FilePreview} from '../FilePreview';

test('Renders base content', () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's wrap the tests into describe block to name test suite

@KirillDyachkovskiy KirillDyachkovskiy merged commit c910ec5 into main Aug 23, 2023
3 checks passed
@KirillDyachkovskiy KirillDyachkovskiy deleted the add-file-preview branch August 23, 2023 12:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants