Skip to content

fix(plasma-web,plasma-b2c): Add useResizeObserver and fix behavior with resize in TextArea #1186

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
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.
24 changes: 20 additions & 4 deletions packages/plasma-b2c/src/components/TextArea/TextArea.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { createRef, useMemo, useState } from 'react';
import styled from 'styled-components';
import {
TextFieldRoot,
Expand All @@ -7,6 +7,7 @@ import {
primary,
secondary,
tertiary,
useResizeObserver,
} from '@sberdevices/plasma-core';
import type { TextAreaProps as BaseProps } from '@sberdevices/plasma-core';

Expand Down Expand Up @@ -44,6 +45,10 @@ const StyledTextArea = styled(BaseArea)`
}
`;

const StyledFieldHelpers = styled(FieldHelpers)<{ width: number }>`
width: ${({ width }) => width}px;
`;

/**
* Поле ввода многострочного текста.
*/
Expand All @@ -66,10 +71,21 @@ export const TextArea = React.forwardRef<HTMLTextAreaElement, TextAreaProps>(
className,
...rest
},
ref,
outerRef,
) => {
const [width, setWidth] = useState(0);
const ref = useMemo(() => (outerRef && 'current' in outerRef ? outerRef : createRef<HTMLTextAreaElement>()), [
outerRef,
]);

const placeLabel = (label || placeholder) as string | undefined;

useResizeObserver(ref, (currentElement) => {
const { width: elementWidth } = currentElement.getBoundingClientRect();

setWidth(elementWidth);
});

return (
<TextFieldRoot
status={status}
Expand All @@ -92,10 +108,10 @@ export const TextArea = React.forwardRef<HTMLTextAreaElement, TextAreaProps>(
aria-describedby={id ? `${id}-helper` : undefined}
{...rest}
/>
<FieldHelpers id={id ? `${id}-helper` : undefined}>
<StyledFieldHelpers width={width} id={id ? `${id}-helper` : undefined}>
<FieldHelper as={TextFieldHelper}>{leftHelper}</FieldHelper>
<FieldHelper>{rightHelper}</FieldHelper>
</FieldHelpers>
</StyledFieldHelpers>
</FieldWrapper>
</TextFieldRoot>
);
Expand Down
6 changes: 6 additions & 0 deletions packages/plasma-core/package-lock.json

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

20 changes: 3 additions & 17 deletions packages/plasma-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,7 @@
"main": "index.js",
"module": "es/index.js",
"types": "index.d.ts",
"files": [
"components",
"hocs",
"hooks",
"mixins",
"tokens",
"types",
"utils",
"index.d.ts",
"index.js",
"es"
],
"files": ["components", "hocs", "hooks", "mixins", "tokens", "types", "utils", "index.d.ts", "index.js", "es"],
"peerDependencies": {
"react": ">=16.13.1",
"react-dom": ">=16.13.1",
Expand All @@ -36,6 +25,7 @@
"@types/node": "15.14.9",
"@types/react": "16.9.38",
"@types/react-dom": "16.9.8",
"@types/resize-observer-browser": "0.1.7",
"@types/styled-components": "5.1.0",
"babel-loader": "8.2.2",
"babel-plugin-annotate-pure-calls": "0.4.0",
Expand Down Expand Up @@ -63,11 +53,7 @@
"test": "NODE_ICU_DATA=node_modules/full-icu jest",
"test:watch": "NODE_ICU_DATA=node_modules/full-icu jest --watch"
},
"contributors": [
"Vasiliy Loginevskiy",
"Виноградов Антон Александрович",
"Зубаиров Фаниль Асхатович"
],
"contributors": ["Vasiliy Loginevskiy", "Виноградов Антон Александрович", "Зубаиров Фаниль Асхатович"],
"sideEffects": false,
"dependencies": {
"focus-visible": "5.2.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ describe('plasma-core: TextArea', () => {
</CypressTestDecorator>,
);

cy.root().get('textarea').last().invoke('attr', 'style', 'width: 280px; height: 140px;');

cy.matchImageSnapshot();
});

Expand Down
1 change: 1 addition & 0 deletions packages/plasma-core/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { useDebouncedFunction } from './useDebouncedFunction';
export { useForkRef } from './useForkRef';
export { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect';
export { useUniqId } from './useUniqId';
export { useResizeObserver } from './useResizeObserver';
34 changes: 34 additions & 0 deletions packages/plasma-core/src/hooks/useResizeObserver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useEffect } from 'react';

/**
* Отслеживает изменение размеров переданного элемента
* @param {React.Ref<T>} ref - реф элемента, за которым нужно следить
* @callback callback - функция, которая вызывается при изменении элемента
* @param {Element} element - элемент, размер которого изменился
*/
export const useResizeObserver = <T extends HTMLElement>(
ref: React.MutableRefObject<T | null>,
callback: (element: T) => void,
) => {
useEffect(() => {
/* istanbul ignore if: убираем проверку на рефы из покрытия */
if (!ref?.current) {
return;
}

const { current } = ref;

const resizeObserver = new window.ResizeObserver(() => callback(current));

resizeObserver.observe(ref.current);

return () => {
/* istanbul ignore if: убираем проверку на рефы из покрытия */
if (!ref?.current) {
Copy link
Contributor

Choose a reason for hiding this comment

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

а этот ифак зачем? у тебя же не дойдет сюда если рефа нет

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ага, я тоже так думал, но почему-то ts ругается

return;
}

resizeObserver.unobserve(ref.current);
};
}, [ref]);
};
37 changes: 33 additions & 4 deletions packages/plasma-web/src/components/TextArea/TextArea.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import React, { forwardRef } from 'react';
import React, { forwardRef, useState, useMemo, createRef } from 'react';
import styled from 'styled-components';
import { FieldRoot, FieldContent, FieldHelper, TextArea as BaseArea } from '@sberdevices/plasma-core';
import {
FieldRoot,
FieldContent,
FieldHelper,
TextArea as BaseArea,
useResizeObserver,
} from '@sberdevices/plasma-core';
import type { TextAreaProps as BaseProps } from '@sberdevices/plasma-core';

import { applyInputStyles } from '../Field';
Expand All @@ -16,14 +22,35 @@ const StyledTextArea = styled(BaseArea)`
${applyInputStyles}
`;

const StyledFieldHelperWrapper = styled.div<{ width: number }>`
position: absolute;
top: 0;

display: flex;
justify-content: flex-end;

width: ${({ width }) => width}px;
`;

/**
* Поле ввода многострочного текста.
*/
// eslint-disable-next-line prefer-arrow-callback
export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(function TextArea(
{ id, disabled, status, label, placeholder, contentRight, helperText, style, className, ...rest },
ref,
outerRef,
) {
const [width, setWidth] = useState(0);
const ref = useMemo(() => (outerRef && 'current' in outerRef ? outerRef : createRef<HTMLTextAreaElement>()), [
Copy link
Contributor

Choose a reason for hiding this comment

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

не сломается, если сюда функцию передадут в outerRef?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

не должно, как раз проверкой на 'current' in outerRef я чекаю, штоб это было именно ref объектом

outerRef,
]);

useResizeObserver(ref, (currentElement) => {
const { width: elementWidth } = currentElement.getBoundingClientRect();

setWidth(elementWidth);
});

Comment on lines +43 to +53
Copy link
Contributor

@LamaEats LamaEats Apr 13, 2022

Choose a reason for hiding this comment

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

не хочется это в отдельный хуй отнести? один и тот же код два раза встречается

Copy link
Contributor Author

Choose a reason for hiding this comment

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

кажется, что пока нет в этом необходимости, т.к. конкретно эти случаи очень специфичны и появляются в двух компонентах.
По-хорошему бы там вообще эти компоненты как-то в Core перетащить вместе с логикой, потому что они сильно похожи, но это уже задача на рефакторинг

const placeLabel = (label || placeholder) as string | undefined;

return (
Expand All @@ -44,8 +71,10 @@ export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(function
aria-describedby={id ? `${id}-helpertext` : undefined}
{...rest}
/>
{contentRight && <FieldContent pos="right">{contentRight}</FieldContent>}
{helperText && <FieldHelper id={id ? `${id}-helpertext` : undefined}>{helperText}</FieldHelper>}
<StyledFieldHelperWrapper width={width}>
{contentRight && <FieldContent pos="right">{contentRight}</FieldContent>}
</StyledFieldHelperWrapper>
</FieldRoot>
);
});