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

fix(Popup): displaying SVG icons #2946

Merged
merged 17 commits into from
Aug 11, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions packages/react-ui/components/Hint/Hint.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@
<Hint text="Подсказка">Базовая</Hint>
```

Пример подсказки с иконкой.

```jsx harmony
<Hint text="Редактирование">
<svg width="16" height="16" viewBox="0 0 16 16">
<path
fillRule="evenodd"
d="M13 12V12.998H8V12H13ZM3 13V11L9 4.99999L11 6.99999L5 13H3ZM13 5L11.5 6.5L9.5 4.5L11 3L13 5Z"
clipRule="evenodd"
/>
</svg>
</Hint>
```

Пример подсказки, всегда всплывающей слева.

```jsx harmony
Expand Down
2 changes: 1 addition & 1 deletion packages/react-ui/components/Hint/Hint.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ export class Hint extends React.PureComponent<HintProps, HintState> implements I
);
}

public getAnchorElement = (): Nullable<HTMLElement> => {
public getAnchorElement = (): Nullable<Element> => {
return this.popupRef.current?.anchorElement;
};

Expand Down
47 changes: 47 additions & 0 deletions packages/react-ui/components/Hint/__stories__/Hint.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,53 @@ SetManualAndOpenedPropOnClick.parameters = {
},
};

export const WithSVGIcon: Story = () => {
return (
<Hint text="hint">
<svg data-tid="icon" width="16" height="16" viewBox="0 0 16 16">
<path d="M9 3H7V7H3V9H7V13H9V9H13V7H9V3Z" />
</svg>
</Hint>
);
};

WithSVGIcon.parameters = {
creevey: {
skip: [
{
in: [
'chromeDark',
'chrome8px',
'firefox8px',
'firefox',
'firefoxFlat8px',
'firefoxDark',
'ie118px',
'ie11',
'ie11Dark',
],
reason: 'internal logic being tested and not something UI related',
},
],
tests: {
async idle() {
await this.expect(await this.takeScreenshot()).to.matchImage('idle');
},
async hover() {
await this.browser
.actions()
.move({
origin: this.browser.findElement({ css: '[data-tid="icon"]' }),
})
.perform();
await delay(1000);

await this.expect(await this.browser.takeScreenshot()).to.matchImage('open');
},
},
},
};

@rootNode
class CustomClassComponent extends React.Component<{}, {}> {
private setRootNode!: TSetRootNode;
Expand Down
54 changes: 36 additions & 18 deletions packages/react-ui/components/Hint/__tests__/Hint-test.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,54 @@
import { mount } from 'enzyme';
import React from 'react';
import React, { useState } from 'react';
import userEvent from '@testing-library/user-event';
import { render, screen } from '@testing-library/react';

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

describe('Hint', () => {
it('render without crash', () => {
const wrapper = mount<Hint>(<Hint text="world">Hello</Hint>);
it('should render without crash', () => {
const hintChildrenText = 'Hello';
render(<Hint text="world">{hintChildrenText}</Hint>);

expect(wrapper).toHaveLength(1);
const hintChildren = screen.getByText(hintChildrenText);
expect(hintChildren).toBeInTheDocument();
});

it('controlled opening only if manual prop passed', () => {
const wrapper = mount<Hint>(
<Hint opened text="world">
it('should not open be controlled manually without `manual` prop passed', () => {
const hintText = 'world';
render(
<Hint opened text={hintText}>
Hello
</Hint>,
);

expect(wrapper.state('opened')).toBe(false);
const hintContent = screen.queryByText(hintText);
expect(hintContent).not.toBeInTheDocument();
});

it('manual opening', () => {
const wrapper = mount<Hint>(
<Hint manual text="world">
Hello
</Hint>,
);
it('should open hint manually', () => {
const hintText = 'world';
const Component = () => {
const [isOpen, setIsOpen] = useState(false);

return (
<>
<Hint opened={isOpen} manual text="world">
Hello
</Hint>
<button onClick={() => setIsOpen(true)}>open manually</button>
</>
);
};

render(<Component />);

expect(wrapper.state('opened')).toBe(false);
const hintContent = screen.queryByText(hintText);
expect(hintContent).not.toBeInTheDocument();

wrapper.setProps({ opened: true });
const openButton = screen.getByRole('button');
userEvent.click(openButton);

expect(wrapper.state('opened')).toBe(true);
const hintContentUpdated = screen.getByText(hintText);
expect(hintContentUpdated).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ export const getScrollSizeParams = (inner: HTMLElement, axis: 'x' | 'y') => {
};

export const getScrollYOffset = (element: HTMLElement, container: HTMLElement) => {
const elementOffset = element.offsetTop;
const elementTopOffset = element.offsetTop;

if (container.scrollTop > elementOffset) {
return elementOffset;
if (container.scrollTop > elementTopOffset) {
return elementTopOffset;
}

const offset = elementOffset + element.scrollHeight - container.offsetHeight;
const offset = elementTopOffset + element.scrollHeight - container.offsetHeight;
if (container.scrollTop < offset) {
return offset;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export class ScrollContainer extends React.Component<ScrollContainerProps> {

/**
* @public
* @param {HTMLElement} element
* @param {Element} element
*/
public scrollTo(element: Nullable<HTMLElement>) {
if (!element || !this.inner) {
Expand Down
2 changes: 1 addition & 1 deletion packages/react-ui/components/Toast/Toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export class Toast extends React.Component<ToastProps, ToastState> {
);
}

private setRootRef = (element: Nullable<HTMLElement>) => {
private setRootRef = (element: Nullable<Element>) => {
this.setRootNode(element);
// @ts-ignore
this.rootRef.current = element;
Expand Down
2 changes: 1 addition & 1 deletion packages/react-ui/components/Tooltip/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ export class Tooltip extends React.PureComponent<TooltipProps, TooltipState> imp
);
}

public getAnchorElement = (): Nullable<HTMLElement> => {
public getAnchorElement = (): Nullable<Element> => {
return this.popupRef.current?.anchorElement;
};

Expand Down
2 changes: 1 addition & 1 deletion packages/react-ui/internal/CommonWrapper/CommonWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface CommonProps {
}

interface CommonPropsRootNodeRef {
rootNodeRef?: (instance: Nullable<HTMLElement>) => void;
rootNodeRef?: (instance: Nullable<Element>) => void;
}

export type NotCommonProps<P> = Omit<P, keyof CommonProps>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export interface DropdownContainerPosition {

export interface DropdownContainerProps {
align?: 'left' | 'right';
getParent: () => Nullable<HTMLElement>;
getParent: () => Nullable<Element>;
children?: React.ReactNode;
disablePortal?: boolean;
offsetY?: number;
Expand Down
18 changes: 15 additions & 3 deletions packages/react-ui/internal/InternalMenu/InternalMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';

import { isHTMLElement } from '../../lib/SSRSafe';
import { isNonNullable, isNullable } from '../../lib/utils';
import { isKeyArrowDown, isKeyArrowUp, isKeyEnter } from '../../lib/events/keyboard/identifiers';
import { ScrollContainer, ScrollContainerScrollState } from '../../components/ScrollContainer';
Expand Down Expand Up @@ -222,7 +223,10 @@ export class InternalMenu extends React.PureComponent<MenuProps, MenuState> {
};

private focusOnRootElement = (): void => {
getRootNode(this)?.focus();
const rootNode = getRootNode(this);
if (isHTMLElement(rootNode)) {
rootNode?.focus();
}
};

private shouldRecalculateMaxHeight = (prevProps: MenuProps): boolean => {
Expand Down Expand Up @@ -296,7 +300,11 @@ export class InternalMenu extends React.PureComponent<MenuProps, MenuState> {

private scrollToSelected = () => {
if (this.scrollContainer && this.highlighted) {
this.scrollContainer.scrollTo(getRootNode(this.highlighted));
const rootNode = getRootNode(this.highlighted);
// TODO: Remove this check once IF-647 is resolved
if (rootNode instanceof HTMLElement) {
this.scrollContainer.scrollTo(rootNode);
}
}
};

Expand Down Expand Up @@ -324,7 +332,11 @@ export class InternalMenu extends React.PureComponent<MenuProps, MenuState> {

private highlightItem = (index: number): void => {
this.setState({ highlightedIndex: index });
getRootNode(this)?.focus();

const rootNode = getRootNode(this);
if (isHTMLElement(rootNode)) {
rootNode?.focus();
}
};

private unhighlight = () => {
Expand Down
6 changes: 5 additions & 1 deletion packages/react-ui/internal/Menu/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,11 @@ export class Menu extends React.Component<MenuProps, MenuState> {

private scrollToSelected = () => {
if (this.scrollContainer && this.highlighted) {
this.scrollContainer.scrollTo(getRootNode(this.highlighted));
const rootNode = getRootNode(this.highlighted);
// TODO: Remove this check once IF-647 is resolved
if (rootNode instanceof HTMLElement) {
this.scrollContainer.scrollTo(rootNode);
}
}
};

Expand Down