-
Notifications
You must be signed in to change notification settings - Fork 9
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
Conversation
Preview is ready. |
|
||
URL.revokeObjectURL(createdUrl); | ||
}; | ||
}, [file]); |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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', () => { |
There was a problem hiding this comment.
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
src/components/FilePreview/README.md
Outdated
className, | ||
file, | ||
description, | ||
onClick, | ||
actions, |
There was a problem hiding this comment.
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> = ({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add diplayName
please
There was a problem hiding this comment.
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
|
||
export const FilePreviewAction: FC<FilePreviewActionProps> = ({icon, title, href, onClick}) => { | ||
const button = ( | ||
<Button |
There was a problem hiding this comment.
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')}> |
There was a problem hiding this comment.
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?
src/components/FilePreview/utils.ts
Outdated
@@ -0,0 +1,23 @@ | |||
import {FileType} from './FilePreview'; |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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
href={href} | ||
target="_blank" | ||
size="s" | ||
aria-label={title || 'FilePreview action'} |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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
?
src/components/FilePreview/README.md
Outdated
| Property | Type | Required | Default | Description | | ||
| -------- | ---------- | -------- | ------- | -------------------- | | ||
| icon | `String` | yes | | Action icon | | ||
| title | `String` | | | Action hint on hover | |
There was a problem hiding this comment.
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} |
There was a problem hiding this comment.
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} /> |
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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)); |
There was a problem hiding this comment.
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'); |
There was a problem hiding this comment.
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'});
9fb73ae
to
9019dcf
Compare
@@ -0,0 +1,129 @@ | |||
import React, {useEffect, useId, useState} from 'react'; |
There was a problem hiding this comment.
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}> |
There was a problem hiding this comment.
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}`} |
There was a problem hiding this comment.
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>}> | ||
{ |
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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
9019dcf
to
9ad7428
Compare
@@ -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", |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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 id
s required for a11y
src/components/FilePreview/README.md
Outdated
| id | `String` | | | Action id | | ||
| icon | `String` | ✓ | | Action icon | | ||
| title | `String` | ✓ | | Action hint on hover | | ||
| label | `String` | | `title` | Action aria-label value | |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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
actions?: FilePreviewActionProps[]; | ||
} | ||
|
||
export const FilePreview: FC<FilePreviewProps> = ({ |
There was a problem hiding this comment.
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
#{$block} { | ||
--gc-file-preview-box-shadow: none; | ||
--gc-file-preview-border-radius: 4px; | ||
--gc-file-preview-color-base-background: transparent; |
There was a problem hiding this comment.
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`} |
There was a problem hiding this comment.
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" |
There was a problem hiding this comment.
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.
$smallRoundedButtonSize: 24px; | ||
|
||
#{$block} { | ||
--gc-_-box-shadow: none; |
There was a problem hiding this comment.
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
src/components/FilePreview/README.md
Outdated
| id | `String` | | | Action id | | ||
| icon | `String` | ✓ | | Action icon | | ||
| title | `String` | ✓ | | Action hint on hover | | ||
| label | `String` | | `title` | Action aria-label value | |
There was a problem hiding this comment.
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', () => { |
There was a problem hiding this comment.
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
No description provided.