@hh.ru/magritte-ui-textarea 3.3.53 → 3.3.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/TextArea.d.ts +2 -2
- package/TextArea.js +244 -135
- package/TextArea.js.map +1 -1
- package/TextAreaGrowLimiter.d.ts +2 -2
- package/TextAreaGrowLimiter.js +67 -55
- package/TextAreaGrowLimiter.js.map +1 -1
- package/UncontrolledTextArea.d.ts +2 -2
- package/UncontrolledTextArea.js +11 -8
- package/UncontrolledTextArea.js.map +1 -1
- package/index.css +283 -283
- package/index.d.ts +3 -3
- package/package.json +8 -8
- package/types.js +3 -3
- package/types.js.map +1 -1
- package/useFocus.js +16 -10
- package/useFocus.js.map +1 -1
- package/useHeightObserver.d.ts +1 -1
- package/useHeightObserver.js +40 -34
- package/useHeightObserver.js.map +1 -1
- package/useLimitGrow.d.ts +1 -1
- package/useLimitGrow.js +47 -66
- package/useLimitGrow.js.map +1 -1
package/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from '
|
|
2
|
-
export * from '
|
|
3
|
-
export { TextAreaGrowLimiter } from '
|
|
1
|
+
export * from './TextArea';
|
|
2
|
+
export * from './UncontrolledTextArea';
|
|
3
|
+
export { TextAreaGrowLimiter } from './TextAreaGrowLimiter';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hh.ru/magritte-ui-textarea",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.55",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"types": "index.d.ts",
|
|
6
6
|
"sideEffects": [
|
|
@@ -23,13 +23,13 @@
|
|
|
23
23
|
"@hh.ru/magritte-common-use-disabled": "1.0.16",
|
|
24
24
|
"@hh.ru/magritte-common-use-multiple-refs": "1.1.12",
|
|
25
25
|
"@hh.ru/magritte-common-use-translation": "3.6.1",
|
|
26
|
-
"@hh.ru/magritte-design-tokens": "
|
|
26
|
+
"@hh.ru/magritte-design-tokens": "26.0.1",
|
|
27
27
|
"@hh.ru/magritte-ui-breakpoint": "6.1.2",
|
|
28
|
-
"@hh.ru/magritte-ui-form-helper": "2.1.
|
|
29
|
-
"@hh.ru/magritte-ui-icon": "15.1.
|
|
30
|
-
"@hh.ru/magritte-ui-input": "9.4.
|
|
31
|
-
"@hh.ru/magritte-ui-scrollbar": "1.0.
|
|
32
|
-
"@hh.ru/magritte-ui-typography": "5.3.
|
|
28
|
+
"@hh.ru/magritte-ui-form-helper": "2.1.25",
|
|
29
|
+
"@hh.ru/magritte-ui-icon": "15.1.5",
|
|
30
|
+
"@hh.ru/magritte-ui-input": "9.4.52",
|
|
31
|
+
"@hh.ru/magritte-ui-scrollbar": "1.0.39",
|
|
32
|
+
"@hh.ru/magritte-ui-typography": "5.3.16"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"classnames": ">=2.3.2",
|
|
@@ -39,5 +39,5 @@
|
|
|
39
39
|
"publishConfig": {
|
|
40
40
|
"access": "public"
|
|
41
41
|
},
|
|
42
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "f6539d7a0e7cd42dd851458db1de04a748bbee03"
|
|
43
43
|
}
|
package/types.js
CHANGED
package/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sources":["src/types.ts"],"sourcesContent":["import type {\n ReactNode,\n FocusEventHandler,\n ChangeEventHandler,\n PropsWithChildren,\n RefObject,\n HTMLAttributes,\n} from 'react';\n\nexport type TextAreaGrowLimiterProps = PropsWithChildren<{\n /**\n * Ссылка на контейнер, который должен ограничивать высоту TextArea.\n * Если не указан, то используется непосредственный родитель компонента в DOM\n * */\n containerRef?: RefObject<HTMLElement>;\n /**\n * Применять ли дебаунс при пересчете размера TextArea.\n * Если вы ожидаете, что для изменения размера контента или контейнера будет использоваться анимация, то имеет\n * смысл использовать дебаунс для вызова перерасчета. В случае если анимации нет дебаунс можно не использовать.\n */\n debounce?: boolean;\n /**\n * Функция вызываемая перед снятием метрик с контейнера. Может понадобиться при наличии кастомной логики на\n * контейнере. Например если контейнер фиксирует свой размер, но при изменении размера контента подстраивает свой\n * размер под него. В этом случае перед съемом метрик может понадобиться убрать фиксированный размер на контейнере.\n */\n preMeasurement?: VoidFunction;\n /**\n * Функция вызываемая после снятия метрик с контейнера.\n */\n postMeasurement?: VoidFunction;\n style?: HTMLAttributes<HTMLDivElement>['style'];\n className?: HTMLAttributes<HTMLDivElement>['className'];\n}> &\n HTMLAttributes<HTMLDivElement>;\n\nexport type TextAreaSize = 'small' | 'medium' | 'large';\nexport type TextAreaLayout = 'fixed' | 'hug' | 'fill-vertical' | 'fill-horizontal' | 'fill-both';\n\nexport type BaseTextAreaProps<Layout extends TextAreaLayout> = {\n /** Текст плейсхолдера */\n placeholder?: ReactNode;\n /** Обработчик события получения фокуса */\n onFocus?: FocusEventHandler<HTMLTextAreaElement>;\n /** Обработчик события потери фокуса */\n onBlur?: FocusEventHandler<HTMLTextAreaElement>;\n /** Текст подсказки под textarea */\n description?: ReactNode;\n /** Текст сообщения об ошибке */\n errorMessage?: ReactNode;\n /** Флаг отключения textarea */\n disabled?: boolean;\n /** Признак невалидности */\n invalid?: boolean;\n /** Признак невалидности по лимиту */\n invalidLimit?: boolean;\n /** Флаг управляющий режимом отображения полейсхолдера */\n elevatePlaceholder?: boolean;\n /** Определяет отступы и типографику компонента */\n size?: TextAreaSize;\n /** Лимит на количество символов, отображает текущее состояние и лимит */\n maxLength?: number;\n /** Функция для связывания внешней валидации с внутренней */\n onValidate?: (invalidState: { invalidLimit: boolean }) => void;\n /** Позволяет задать в каком направлении допустимо ручное изменение размера. Доступно только с `layout=\"fixed\"` */\n resize?: Layout extends 'fixed' ? 'none' | 'both' | 'horizontal' | 'vertical' : 'none';\n layout?: Layout;\n /** Позволяет задать максимальную высоту при `layout=\"hug\"`. Если значение равно 0 высота не ограничена. */\n maxHeight?: Layout extends 'hug' ? number : never;\n} & TextAreaSizes<Layout>;\n\ntype TextAreaSizes<\n Layout extends TextAreaLayout = 'fixed',\n AllowBothHeight extends boolean = Layout extends 'hug' ? true : false,\n> =\n | { size: 'small'; minHeight?: AllowBothHeight extends true ? 40 | 80 : 80 }\n | { size: 'medium'; minHeight?: AllowBothHeight extends true ? 48 | 96 : 96 }\n | { size?: 'large'; minHeight?: AllowBothHeight extends true ? 56 | 112 : 112 };\n\nexport interface ControlledProps {\n /** Обработчик события изменения */\n onChange: ChangeEventHandler<HTMLTextAreaElement>;\n /** Значение textarea */\n value: string;\n}\n\nexport type UncontrolledTextAreaProps<Layout extends TextAreaLayout> = Partial<ControlledProps> &\n BaseTextAreaProps<Layout>;\n\nexport type ControlledTextAreaProps<Layout extends TextAreaLayout> = BaseTextAreaProps<Layout> & ControlledProps;\n\nexport const MIN_HEIGHT_BY_SIZE = {\n small: [40, 80],\n medium: [48, 96],\n large: [56, 112],\n} as const;\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sources":["src/types.ts"],"sourcesContent":["import type {\n ReactNode,\n FocusEventHandler,\n ChangeEventHandler,\n PropsWithChildren,\n RefObject,\n HTMLAttributes,\n} from 'react';\n\nexport type TextAreaGrowLimiterProps = PropsWithChildren<{\n /**\n * Ссылка на контейнер, который должен ограничивать высоту TextArea.\n * Если не указан, то используется непосредственный родитель компонента в DOM\n * */\n containerRef?: RefObject<HTMLElement>;\n /**\n * Применять ли дебаунс при пересчете размера TextArea.\n * Если вы ожидаете, что для изменения размера контента или контейнера будет использоваться анимация, то имеет\n * смысл использовать дебаунс для вызова перерасчета. В случае если анимации нет дебаунс можно не использовать.\n */\n debounce?: boolean;\n /**\n * Функция вызываемая перед снятием метрик с контейнера. Может понадобиться при наличии кастомной логики на\n * контейнере. Например если контейнер фиксирует свой размер, но при изменении размера контента подстраивает свой\n * размер под него. В этом случае перед съемом метрик может понадобиться убрать фиксированный размер на контейнере.\n */\n preMeasurement?: VoidFunction;\n /**\n * Функция вызываемая после снятия метрик с контейнера.\n */\n postMeasurement?: VoidFunction;\n style?: HTMLAttributes<HTMLDivElement>['style'];\n className?: HTMLAttributes<HTMLDivElement>['className'];\n}> &\n HTMLAttributes<HTMLDivElement>;\n\nexport type TextAreaSize = 'small' | 'medium' | 'large';\nexport type TextAreaLayout = 'fixed' | 'hug' | 'fill-vertical' | 'fill-horizontal' | 'fill-both';\n\nexport type BaseTextAreaProps<Layout extends TextAreaLayout> = {\n /** Текст плейсхолдера */\n placeholder?: ReactNode;\n /** Обработчик события получения фокуса */\n onFocus?: FocusEventHandler<HTMLTextAreaElement>;\n /** Обработчик события потери фокуса */\n onBlur?: FocusEventHandler<HTMLTextAreaElement>;\n /** Текст подсказки под textarea */\n description?: ReactNode;\n /** Текст сообщения об ошибке */\n errorMessage?: ReactNode;\n /** Флаг отключения textarea */\n disabled?: boolean;\n /** Признак невалидности */\n invalid?: boolean;\n /** Признак невалидности по лимиту */\n invalidLimit?: boolean;\n /** Флаг управляющий режимом отображения полейсхолдера */\n elevatePlaceholder?: boolean;\n /** Определяет отступы и типографику компонента */\n size?: TextAreaSize;\n /** Лимит на количество символов, отображает текущее состояние и лимит */\n maxLength?: number;\n /** Функция для связывания внешней валидации с внутренней */\n onValidate?: (invalidState: { invalidLimit: boolean }) => void;\n /** Позволяет задать в каком направлении допустимо ручное изменение размера. Доступно только с `layout=\"fixed\"` */\n resize?: Layout extends 'fixed' ? 'none' | 'both' | 'horizontal' | 'vertical' : 'none';\n layout?: Layout;\n /** Позволяет задать максимальную высоту при `layout=\"hug\"`. Если значение равно 0 высота не ограничена. */\n maxHeight?: Layout extends 'hug' ? number : never;\n} & TextAreaSizes<Layout>;\n\ntype TextAreaSizes<\n Layout extends TextAreaLayout = 'fixed',\n AllowBothHeight extends boolean = Layout extends 'hug' ? true : false,\n> =\n | { size: 'small'; minHeight?: AllowBothHeight extends true ? 40 | 80 : 80 }\n | { size: 'medium'; minHeight?: AllowBothHeight extends true ? 48 | 96 : 96 }\n | { size?: 'large'; minHeight?: AllowBothHeight extends true ? 56 | 112 : 112 };\n\nexport interface ControlledProps {\n /** Обработчик события изменения */\n onChange: ChangeEventHandler<HTMLTextAreaElement>;\n /** Значение textarea */\n value: string;\n}\n\nexport type UncontrolledTextAreaProps<Layout extends TextAreaLayout> = Partial<ControlledProps> &\n BaseTextAreaProps<Layout>;\n\nexport type ControlledTextAreaProps<Layout extends TextAreaLayout> = BaseTextAreaProps<Layout> & ControlledProps;\n\nexport const MIN_HEIGHT_BY_SIZE = {\n small: [40, 80],\n medium: [48, 96],\n large: [56, 112],\n} as const;\n"],"names":[],"mappings":"AA2FO,MAAM,kBAAqB,GAAA;AAAA,EAC9B,KAAA,EAAO,CAAC,EAAA,EAAI,EAAE,CAAA;AAAA,EACd,MAAA,EAAQ,CAAC,EAAA,EAAI,EAAE,CAAA;AAAA,EACf,KAAA,EAAO,CAAC,EAAA,EAAI,GAAG,CAAA;AACnB;;;;"}
|
package/useFocus.js
CHANGED
|
@@ -2,16 +2,22 @@ import './index.css';
|
|
|
2
2
|
import { useState, useCallback } from 'react';
|
|
3
3
|
|
|
4
4
|
const useFocus = (onFocus, onBlur) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
const [isFocused, setFocused] = useState(false);
|
|
6
|
+
const focusHandler = useCallback(
|
|
7
|
+
(event) => {
|
|
8
|
+
setFocused(true);
|
|
9
|
+
onFocus?.(event);
|
|
10
|
+
},
|
|
11
|
+
[setFocused, onFocus]
|
|
12
|
+
);
|
|
13
|
+
const blurHandler = useCallback(
|
|
14
|
+
(event) => {
|
|
15
|
+
setFocused(false);
|
|
16
|
+
onBlur?.(event);
|
|
17
|
+
},
|
|
18
|
+
[setFocused, onBlur]
|
|
19
|
+
);
|
|
20
|
+
return { focusHandler, blurHandler, isFocused };
|
|
15
21
|
};
|
|
16
22
|
|
|
17
23
|
export { useFocus };
|
package/useFocus.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFocus.js","sources":["src/useFocus.ts"],"sourcesContent":["import { useCallback, useState, FocusEventHandler } from 'react';\n\nexport const useFocus = <T extends HTMLTextAreaElement = HTMLTextAreaElement>(\n onFocus: FocusEventHandler<T> | undefined,\n onBlur: FocusEventHandler<T> | undefined\n): {\n focusHandler: FocusEventHandler<T>;\n blurHandler: FocusEventHandler<T>;\n isFocused: boolean;\n} => {\n const [isFocused, setFocused] = useState(false);\n const focusHandler = useCallback<FocusEventHandler<T>>(\n (event) => {\n setFocused(true);\n onFocus?.(event);\n },\n [setFocused, onFocus]\n );\n\n const blurHandler = useCallback<FocusEventHandler<T>>(\n (event) => {\n setFocused(false);\n onBlur?.(event);\n },\n [setFocused, onBlur]\n );\n\n return { focusHandler, blurHandler, isFocused };\n};\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"useFocus.js","sources":["src/useFocus.ts"],"sourcesContent":["import { useCallback, useState, FocusEventHandler } from 'react';\n\nexport const useFocus = <T extends HTMLTextAreaElement = HTMLTextAreaElement>(\n onFocus: FocusEventHandler<T> | undefined,\n onBlur: FocusEventHandler<T> | undefined\n): {\n focusHandler: FocusEventHandler<T>;\n blurHandler: FocusEventHandler<T>;\n isFocused: boolean;\n} => {\n const [isFocused, setFocused] = useState(false);\n const focusHandler = useCallback<FocusEventHandler<T>>(\n (event) => {\n setFocused(true);\n onFocus?.(event);\n },\n [setFocused, onFocus]\n );\n\n const blurHandler = useCallback<FocusEventHandler<T>>(\n (event) => {\n setFocused(false);\n onBlur?.(event);\n },\n [setFocused, onBlur]\n );\n\n return { focusHandler, blurHandler, isFocused };\n};\n"],"names":[],"mappings":";;AAEa,MAAA,QAAA,GAAW,CACpB,OAAA,EACA,MAKC,KAAA;AACD,EAAA,MAAM,CAAC,SAAA,EAAW,UAAU,CAAA,GAAI,SAAS,KAAK,CAAA,CAAA;AAC9C,EAAA,MAAM,YAAe,GAAA,WAAA;AAAA,IACjB,CAAC,KAAU,KAAA;AACP,MAAA,UAAA,CAAW,IAAI,CAAA,CAAA;AACf,MAAA,OAAA,GAAU,KAAK,CAAA,CAAA;AAAA,KACnB;AAAA,IACA,CAAC,YAAY,OAAO,CAAA;AAAA,GACxB,CAAA;AAEA,EAAA,MAAM,WAAc,GAAA,WAAA;AAAA,IAChB,CAAC,KAAU,KAAA;AACP,MAAA,UAAA,CAAW,KAAK,CAAA,CAAA;AAChB,MAAA,MAAA,GAAS,KAAK,CAAA,CAAA;AAAA,KAClB;AAAA,IACA,CAAC,YAAY,MAAM,CAAA;AAAA,GACvB,CAAA;AAEA,EAAO,OAAA,EAAE,YAAc,EAAA,WAAA,EAAa,SAAU,EAAA,CAAA;AAClD;;;;"}
|
package/useHeightObserver.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type RefObject } from 'react';
|
|
2
|
-
import { type TextAreaLayout, type TextAreaSize } from '
|
|
2
|
+
import { type TextAreaLayout, type TextAreaSize } from './types';
|
|
3
3
|
type UseHeightObserverArgs = {
|
|
4
4
|
size: TextAreaSize;
|
|
5
5
|
minHeight: number | undefined;
|
package/useHeightObserver.js
CHANGED
|
@@ -2,41 +2,47 @@ import './index.css';
|
|
|
2
2
|
import { useState, useRef, useEffect } from 'react';
|
|
3
3
|
import { MIN_HEIGHT_BY_SIZE } from './types.js';
|
|
4
4
|
|
|
5
|
-
const useHeightObserver = ({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
range.selectNodeContents(contentCloneRef.current);
|
|
25
|
-
const rects = range.getClientRects();
|
|
26
|
-
if (rectsLengthRef.current !== rects.length && rectsLengthRef.current !== null) {
|
|
27
|
-
onHeightChangeRef.current?.();
|
|
28
|
-
}
|
|
29
|
-
rectsLengthRef.current = rects.length;
|
|
30
|
-
setActualMinHeight(MIN_HEIGHT_BY_SIZE[size][rects.length > 1 ? 1 : 0]);
|
|
31
|
-
});
|
|
32
|
-
observer.observe(contentCloneRef.current);
|
|
33
|
-
return () => observer.disconnect();
|
|
34
|
-
}, [layout, size, contentCloneRef]);
|
|
35
|
-
let resultMinHeight = isSizeChanged || isMaxSizeHeight ? _minHeight : actualMinHeight;
|
|
36
|
-
if (layout !== 'hug') {
|
|
37
|
-
resultMinHeight = MIN_HEIGHT_BY_SIZE[size][1];
|
|
5
|
+
const useHeightObserver = ({
|
|
6
|
+
size,
|
|
7
|
+
minHeight,
|
|
8
|
+
layout,
|
|
9
|
+
contentCloneRef,
|
|
10
|
+
onHeightChange
|
|
11
|
+
}) => {
|
|
12
|
+
const _minHeight = minHeight ?? MIN_HEIGHT_BY_SIZE[size][1];
|
|
13
|
+
const isMaxSizeHeight = _minHeight === MIN_HEIGHT_BY_SIZE[size][1];
|
|
14
|
+
const [actualMinHeight, setActualMinHeight] = useState(_minHeight);
|
|
15
|
+
const lastProcessedSizeRef = useRef(size);
|
|
16
|
+
const isSizeChanged = lastProcessedSizeRef.current !== size;
|
|
17
|
+
lastProcessedSizeRef.current = size;
|
|
18
|
+
const onHeightChangeRef = useRef(onHeightChange);
|
|
19
|
+
onHeightChangeRef.current = onHeightChange;
|
|
20
|
+
const rectsLengthRef = useRef(null);
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (!contentCloneRef.current) {
|
|
23
|
+
return void 0;
|
|
38
24
|
}
|
|
39
|
-
|
|
25
|
+
const range = document.createRange();
|
|
26
|
+
const observer = new ResizeObserver(() => {
|
|
27
|
+
if (!contentCloneRef.current) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
range.selectNodeContents(contentCloneRef.current);
|
|
31
|
+
const rects = range.getClientRects();
|
|
32
|
+
if (rectsLengthRef.current !== rects.length && rectsLengthRef.current !== null) {
|
|
33
|
+
onHeightChangeRef.current?.();
|
|
34
|
+
}
|
|
35
|
+
rectsLengthRef.current = rects.length;
|
|
36
|
+
setActualMinHeight(MIN_HEIGHT_BY_SIZE[size][rects.length > 1 ? 1 : 0]);
|
|
37
|
+
});
|
|
38
|
+
observer.observe(contentCloneRef.current);
|
|
39
|
+
return () => observer.disconnect();
|
|
40
|
+
}, [layout, size, contentCloneRef]);
|
|
41
|
+
let resultMinHeight = isSizeChanged || isMaxSizeHeight ? _minHeight : actualMinHeight;
|
|
42
|
+
if (layout !== "hug") {
|
|
43
|
+
resultMinHeight = MIN_HEIGHT_BY_SIZE[size][1];
|
|
44
|
+
}
|
|
45
|
+
return { minHeight: resultMinHeight, maxedHeight: resultMinHeight === MIN_HEIGHT_BY_SIZE[size][1] };
|
|
40
46
|
};
|
|
41
47
|
|
|
42
48
|
export { useHeightObserver };
|
package/useHeightObserver.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useHeightObserver.js","sources":["src/useHeightObserver.ts"],"sourcesContent":["import { type RefObject, useState, useEffect, useRef } from 'react';\n\nimport { type TextAreaLayout, type TextAreaSize, MIN_HEIGHT_BY_SIZE } from '@hh.ru/magritte-ui-textarea/types';\n\ntype UseHeightObserverArgs = {\n size: TextAreaSize;\n minHeight: number | undefined;\n layout: TextAreaLayout;\n contentCloneRef: RefObject<HTMLElement>;\n onHeightChange?: VoidFunction;\n};\n\nexport const useHeightObserver = ({\n size,\n minHeight,\n layout,\n contentCloneRef,\n onHeightChange,\n}: UseHeightObserverArgs): { minHeight: number; maxedHeight: boolean } => {\n const _minHeight = minHeight ?? MIN_HEIGHT_BY_SIZE[size][1];\n const isMaxSizeHeight = _minHeight === MIN_HEIGHT_BY_SIZE[size][1];\n const [actualMinHeight, setActualMinHeight] = useState(_minHeight);\n const lastProcessedSizeRef = useRef<TextAreaSize>(size);\n const isSizeChanged = lastProcessedSizeRef.current !== size;\n lastProcessedSizeRef.current = size;\n const onHeightChangeRef = useRef(onHeightChange);\n onHeightChangeRef.current = onHeightChange;\n const rectsLengthRef = useRef<number | null>(null);\n\n useEffect(() => {\n if (!contentCloneRef.current) {\n return void 0;\n }\n\n const range = document.createRange();\n const observer = new ResizeObserver(() => {\n if (!contentCloneRef.current) {\n return;\n }\n\n range.selectNodeContents(contentCloneRef.current);\n const rects = range.getClientRects();\n if (rectsLengthRef.current !== rects.length && rectsLengthRef.current !== null) {\n onHeightChangeRef.current?.();\n }\n rectsLengthRef.current = rects.length;\n setActualMinHeight(MIN_HEIGHT_BY_SIZE[size][rects.length > 1 ? 1 : 0]);\n });\n observer.observe(contentCloneRef.current);\n return () => observer.disconnect();\n }, [layout, size, contentCloneRef]);\n\n let resultMinHeight = isSizeChanged || isMaxSizeHeight ? _minHeight : actualMinHeight;\n if (layout !== 'hug') {\n resultMinHeight = MIN_HEIGHT_BY_SIZE[size][1];\n }\n\n return { minHeight: resultMinHeight, maxedHeight: resultMinHeight === MIN_HEIGHT_BY_SIZE[size][1] };\n};\n"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"useHeightObserver.js","sources":["src/useHeightObserver.ts"],"sourcesContent":["import { type RefObject, useState, useEffect, useRef } from 'react';\n\nimport { type TextAreaLayout, type TextAreaSize, MIN_HEIGHT_BY_SIZE } from '@hh.ru/magritte-ui-textarea/types';\n\ntype UseHeightObserverArgs = {\n size: TextAreaSize;\n minHeight: number | undefined;\n layout: TextAreaLayout;\n contentCloneRef: RefObject<HTMLElement>;\n onHeightChange?: VoidFunction;\n};\n\nexport const useHeightObserver = ({\n size,\n minHeight,\n layout,\n contentCloneRef,\n onHeightChange,\n}: UseHeightObserverArgs): { minHeight: number; maxedHeight: boolean } => {\n const _minHeight = minHeight ?? MIN_HEIGHT_BY_SIZE[size][1];\n const isMaxSizeHeight = _minHeight === MIN_HEIGHT_BY_SIZE[size][1];\n const [actualMinHeight, setActualMinHeight] = useState(_minHeight);\n const lastProcessedSizeRef = useRef<TextAreaSize>(size);\n const isSizeChanged = lastProcessedSizeRef.current !== size;\n lastProcessedSizeRef.current = size;\n const onHeightChangeRef = useRef(onHeightChange);\n onHeightChangeRef.current = onHeightChange;\n const rectsLengthRef = useRef<number | null>(null);\n\n useEffect(() => {\n if (!contentCloneRef.current) {\n return void 0;\n }\n\n const range = document.createRange();\n const observer = new ResizeObserver(() => {\n if (!contentCloneRef.current) {\n return;\n }\n\n range.selectNodeContents(contentCloneRef.current);\n const rects = range.getClientRects();\n if (rectsLengthRef.current !== rects.length && rectsLengthRef.current !== null) {\n onHeightChangeRef.current?.();\n }\n rectsLengthRef.current = rects.length;\n setActualMinHeight(MIN_HEIGHT_BY_SIZE[size][rects.length > 1 ? 1 : 0]);\n });\n observer.observe(contentCloneRef.current);\n return () => observer.disconnect();\n }, [layout, size, contentCloneRef]);\n\n let resultMinHeight = isSizeChanged || isMaxSizeHeight ? _minHeight : actualMinHeight;\n if (layout !== 'hug') {\n resultMinHeight = MIN_HEIGHT_BY_SIZE[size][1];\n }\n\n return { minHeight: resultMinHeight, maxedHeight: resultMinHeight === MIN_HEIGHT_BY_SIZE[size][1] };\n};\n"],"names":[],"mappings":";;;AAYO,MAAM,oBAAoB,CAAC;AAAA,EAC9B,IAAA;AAAA,EACA,SAAA;AAAA,EACA,MAAA;AAAA,EACA,eAAA;AAAA,EACA,cAAA;AACJ,CAA0E,KAAA;AACtE,EAAA,MAAM,UAAa,GAAA,SAAA,IAAa,kBAAmB,CAAA,IAAI,EAAE,CAAC,CAAA,CAAA;AAC1D,EAAA,MAAM,eAAkB,GAAA,UAAA,KAAe,kBAAmB,CAAA,IAAI,EAAE,CAAC,CAAA,CAAA;AACjE,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,CAAA,GAAI,SAAS,UAAU,CAAA,CAAA;AACjE,EAAM,MAAA,oBAAA,GAAuB,OAAqB,IAAI,CAAA,CAAA;AACtD,EAAM,MAAA,aAAA,GAAgB,qBAAqB,OAAY,KAAA,IAAA,CAAA;AACvD,EAAA,oBAAA,CAAqB,OAAU,GAAA,IAAA,CAAA;AAC/B,EAAM,MAAA,iBAAA,GAAoB,OAAO,cAAc,CAAA,CAAA;AAC/C,EAAA,iBAAA,CAAkB,OAAU,GAAA,cAAA,CAAA;AAC5B,EAAM,MAAA,cAAA,GAAiB,OAAsB,IAAI,CAAA,CAAA;AAEjD,EAAA,SAAA,CAAU,MAAM;AACZ,IAAI,IAAA,CAAC,gBAAgB,OAAS,EAAA;AAC1B,MAAO,OAAA,KAAA,CAAA,CAAA;AAAA,KACX;AAEA,IAAM,MAAA,KAAA,GAAQ,SAAS,WAAY,EAAA,CAAA;AACnC,IAAM,MAAA,QAAA,GAAW,IAAI,cAAA,CAAe,MAAM;AACtC,MAAI,IAAA,CAAC,gBAAgB,OAAS,EAAA;AAC1B,QAAA,OAAA;AAAA,OACJ;AAEA,MAAM,KAAA,CAAA,kBAAA,CAAmB,gBAAgB,OAAO,CAAA,CAAA;AAChD,MAAM,MAAA,KAAA,GAAQ,MAAM,cAAe,EAAA,CAAA;AACnC,MAAA,IAAI,eAAe,OAAY,KAAA,KAAA,CAAM,MAAU,IAAA,cAAA,CAAe,YAAY,IAAM,EAAA;AAC5E,QAAA,iBAAA,CAAkB,OAAU,IAAA,CAAA;AAAA,OAChC;AACA,MAAA,cAAA,CAAe,UAAU,KAAM,CAAA,MAAA,CAAA;AAC/B,MAAmB,kBAAA,CAAA,kBAAA,CAAmB,IAAI,CAAE,CAAA,KAAA,CAAM,SAAS,CAAI,GAAA,CAAA,GAAI,CAAC,CAAC,CAAA,CAAA;AAAA,KACxE,CAAA,CAAA;AACD,IAAS,QAAA,CAAA,OAAA,CAAQ,gBAAgB,OAAO,CAAA,CAAA;AACxC,IAAO,OAAA,MAAM,SAAS,UAAW,EAAA,CAAA;AAAA,GAClC,EAAA,CAAC,MAAQ,EAAA,IAAA,EAAM,eAAe,CAAC,CAAA,CAAA;AAElC,EAAI,IAAA,eAAA,GAAkB,aAAiB,IAAA,eAAA,GAAkB,UAAa,GAAA,eAAA,CAAA;AACtE,EAAA,IAAI,WAAW,KAAO,EAAA;AAClB,IAAkB,eAAA,GAAA,kBAAA,CAAmB,IAAI,CAAA,CAAE,CAAC,CAAA,CAAA;AAAA,GAChD;AAEA,EAAO,OAAA,EAAE,WAAW,eAAiB,EAAA,WAAA,EAAa,oBAAoB,kBAAmB,CAAA,IAAI,CAAE,CAAA,CAAC,CAAE,EAAA,CAAA;AACtG;;;;"}
|
package/useLimitGrow.d.ts
CHANGED
package/useLimitGrow.js
CHANGED
|
@@ -5,73 +5,54 @@ import 'react/jsx-runtime';
|
|
|
5
5
|
import '@hh.ru/magritte-common-func-utils';
|
|
6
6
|
import '@hh.ru/magritte-common-use-multiple-refs';
|
|
7
7
|
|
|
8
|
-
const useLimitGrow = ({
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
const useLimitGrow = ({
|
|
9
|
+
layout,
|
|
10
|
+
contentCloneRef,
|
|
11
|
+
contentCloneWrapperRef,
|
|
12
|
+
resizableDivRef,
|
|
13
|
+
textAreaRef,
|
|
14
|
+
minHeight
|
|
15
|
+
}) => {
|
|
16
|
+
const growLimiterContext = useContext(GrowLimiterContext);
|
|
17
|
+
const allowScrollRef = useRef(false);
|
|
18
|
+
const maxHeightRef = useRef(null);
|
|
19
|
+
if (layout !== "hug" || !growLimiterContext.hasLimit) {
|
|
20
|
+
maxHeightRef.current = null;
|
|
21
|
+
allowScrollRef.current = true;
|
|
22
|
+
}
|
|
23
|
+
useLayoutEffect(() => {
|
|
24
|
+
if (layout !== "hug" || !contentCloneRef.current || !growLimiterContext.hasLimit) {
|
|
25
|
+
return void 0;
|
|
15
26
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// Убеждаемся, что высота не стала меньше минимальной допустимой
|
|
46
|
-
const appliedHeight = Math.max(height + Math.min(contentHeightDelta, heightDiff), minHeight);
|
|
47
|
-
allowScrollRef.current = contentHeightDelta > heightDiff || heightDiff < 0;
|
|
48
|
-
textAreaRef.current.style.overflowY = allowScrollRef.current ? 'auto' : 'hidden';
|
|
49
|
-
resizableDivRef.current.style.height = `${appliedHeight}px`;
|
|
50
|
-
maxHeightRef.current = `${appliedHeight}px`;
|
|
51
|
-
if (appliedHeight !== height) {
|
|
52
|
-
// При тестировании в хроме с 20x slowdown сброс кеша в height diff контексте не успевал сработать за
|
|
53
|
-
// период дебаунса, из-за этого если зажать enter компонент мог стать больше по высоте чем контейнер
|
|
54
|
-
// и ограничение срабатывало только после отпускания клавиши,поэтому добавил принудительный сброс кеша
|
|
55
|
-
// при изменении размера компонента
|
|
56
|
-
growLimiterContext.heightUpdated();
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
const observer = new ResizeObserver(applyHeightLimit);
|
|
60
|
-
// Запускаем процесс пересчета максимальной высоты текстарии каждый раз
|
|
61
|
-
// когда вертикальный размер контента меняется
|
|
62
|
-
observer.observe(contentCloneRef.current, { box: 'border-box' });
|
|
63
|
-
const context = growLimiterContext;
|
|
64
|
-
// Так же запускаем его когда меняется размер контейнера скролла в котором мы пытаемся избежать.
|
|
65
|
-
// Или размер обертки которую создает TextAreaGrowLimiter, например вследствие добавления или удаления
|
|
66
|
-
// контента рядом с текстарией.
|
|
67
|
-
context.onHeightChange(applyHeightLimit);
|
|
68
|
-
applyHeightLimit();
|
|
69
|
-
return () => {
|
|
70
|
-
observer.disconnect();
|
|
71
|
-
context.offHeightChange(applyHeightLimit);
|
|
72
|
-
};
|
|
73
|
-
}, [layout, growLimiterContext, contentCloneRef, contentCloneWrapperRef, resizableDivRef, minHeight, textAreaRef]);
|
|
74
|
-
return { maxHeightRef, allowScrollRef };
|
|
27
|
+
const applyHeightLimit = () => {
|
|
28
|
+
if (!resizableDivRef.current || !contentCloneWrapperRef.current || !contentCloneRef.current || !textAreaRef.current) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const contentCloneHeight = contentCloneRef.current.offsetHeight;
|
|
32
|
+
const contentCloneWrapperHeight = contentCloneWrapperRef.current.offsetHeight;
|
|
33
|
+
const contentHeightDelta = contentCloneHeight - contentCloneWrapperHeight;
|
|
34
|
+
const height = resizableDivRef.current.offsetHeight;
|
|
35
|
+
const heightDiff = growLimiterContext.getHeightDiff();
|
|
36
|
+
const appliedHeight = Math.max(height + Math.min(contentHeightDelta, heightDiff), minHeight);
|
|
37
|
+
allowScrollRef.current = contentHeightDelta > heightDiff || heightDiff < 0;
|
|
38
|
+
textAreaRef.current.style.overflowY = allowScrollRef.current ? "auto" : "hidden";
|
|
39
|
+
resizableDivRef.current.style.height = `${appliedHeight}px`;
|
|
40
|
+
maxHeightRef.current = `${appliedHeight}px`;
|
|
41
|
+
if (appliedHeight !== height) {
|
|
42
|
+
growLimiterContext.heightUpdated();
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const observer = new ResizeObserver(applyHeightLimit);
|
|
46
|
+
observer.observe(contentCloneRef.current, { box: "border-box" });
|
|
47
|
+
const context = growLimiterContext;
|
|
48
|
+
context.onHeightChange(applyHeightLimit);
|
|
49
|
+
applyHeightLimit();
|
|
50
|
+
return () => {
|
|
51
|
+
observer.disconnect();
|
|
52
|
+
context.offHeightChange(applyHeightLimit);
|
|
53
|
+
};
|
|
54
|
+
}, [layout, growLimiterContext, contentCloneRef, contentCloneWrapperRef, resizableDivRef, minHeight, textAreaRef]);
|
|
55
|
+
return { maxHeightRef, allowScrollRef };
|
|
75
56
|
};
|
|
76
57
|
|
|
77
58
|
export { useLimitGrow };
|
package/useLimitGrow.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLimitGrow.js","sources":["src/useLimitGrow.ts"],"sourcesContent":["import { useRef, useContext, useLayoutEffect, type RefObject } from 'react';\n\nimport { GrowLimiterContext } from '@hh.ru/magritte-ui-textarea/TextAreaGrowLimiter';\nimport type { TextAreaLayout } from '@hh.ru/magritte-ui-textarea/types';\n\ntype UseLimitGrowArgs = {\n layout: TextAreaLayout;\n contentCloneRef: RefObject<HTMLElement>;\n contentCloneWrapperRef: RefObject<HTMLElement>;\n resizableDivRef: RefObject<HTMLElement>;\n textAreaRef: RefObject<HTMLTextAreaElement>;\n minHeight: number;\n};\n\nexport const useLimitGrow = ({\n layout,\n contentCloneRef,\n contentCloneWrapperRef,\n resizableDivRef,\n textAreaRef,\n minHeight,\n}: UseLimitGrowArgs): { maxHeightRef: RefObject<string>; allowScrollRef: RefObject<boolean> } => {\n const growLimiterContext = useContext(GrowLimiterContext);\n const allowScrollRef = useRef(false);\n const maxHeightRef = useRef<string | null>(null);\n\n if (layout !== 'hug' || !growLimiterContext.hasLimit) {\n maxHeightRef.current = null;\n allowScrollRef.current = true;\n }\n\n useLayoutEffect(() => {\n if (layout !== 'hug' || !contentCloneRef.current || !growLimiterContext.hasLimit) {\n return void 0;\n }\n\n const applyHeightLimit = () => {\n if (\n !resizableDivRef.current ||\n !contentCloneWrapperRef.current ||\n !contentCloneRef.current ||\n !textAreaRef.current\n ) {\n return;\n }\n\n // Сравниваем высоту контейнера содержащего клон контента текстарии и его обертки. Контейнер может свободно\n // менять высоту чтобы уместить весь контент. Обертка может только свободно уменьшаться, при увеличении\n // размера контента размер обертки не меняется. Вычитая одно из другого получаем положительное число равное\n // изменению размера контента если контент стал больше, и 0 если он уменьшился.\n const contentCloneHeight = contentCloneRef.current.offsetHeight;\n const contentCloneWrapperHeight = contentCloneWrapperRef.current.offsetHeight;\n const contentHeightDelta = contentCloneHeight - contentCloneWrapperHeight;\n // Размер внешнего контейнера текстарии\n const height = resizableDivRef.current.offsetHeight;\n\n // Получаем количество свободного пространства в контейнере которое можем занять до получения скролла\n // Число может быть отрицательным если в контейнере уже присутствует скролл, тогда это количество пикселей\n // на которое нужно уменьшить высоту контента чтобы скролл исчез.\n const heightDiff = growLimiterContext.getHeightDiff();\n // Вычисляем новую высоту внешнего контейнера как сумму его текущей высоты и дельты высоты контента.\n // Убеждаемся что добавляем к высоте текстарии не больше пикселей, чем доступно в контейнере до появления\n // скролла. В результате размер текстарии может уменьшиться, если в контейнере доступно отрицательное\n // количество пикселей до появления скролла (в случае если скролл уже появился из-за добавления другого\n // контента например).\n // Убеждаемся, что высота не стала меньше минимальной допустимой\n const appliedHeight = Math.max(height + Math.min(contentHeightDelta, heightDiff), minHeight);\n allowScrollRef.current = contentHeightDelta > heightDiff || heightDiff < 0;\n textAreaRef.current.style.overflowY = allowScrollRef.current ? 'auto' : 'hidden';\n resizableDivRef.current.style.height = `${appliedHeight}px`;\n maxHeightRef.current = `${appliedHeight}px`;\n if (appliedHeight !== height) {\n // При тестировании в хроме с 20x slowdown сброс кеша в height diff контексте не успевал сработать за\n // период дебаунса, из-за этого если зажать enter компонент мог стать больше по высоте чем контейнер\n // и ограничение срабатывало только после отпускания клавиши,поэтому добавил принудительный сброс кеша\n // при изменении размера компонента\n growLimiterContext.heightUpdated();\n }\n };\n\n const observer = new ResizeObserver(applyHeightLimit);\n // Запускаем процесс пересчета максимальной высоты текстарии каждый раз\n // когда вертикальный размер контента меняется\n observer.observe(contentCloneRef.current, { box: 'border-box' });\n const context = growLimiterContext;\n // Так же запускаем его когда меняется размер контейнера скролла в котором мы пытаемся избежать.\n // Или размер обертки которую создает TextAreaGrowLimiter, например вследствие добавления или удаления\n // контента рядом с текстарией.\n context.onHeightChange(applyHeightLimit);\n applyHeightLimit();\n\n return () => {\n observer.disconnect();\n context.offHeightChange(applyHeightLimit);\n };\n }, [layout, growLimiterContext, contentCloneRef, contentCloneWrapperRef, resizableDivRef, minHeight, textAreaRef]);\n\n return { maxHeightRef, allowScrollRef };\n};\n"],"names":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"useLimitGrow.js","sources":["src/useLimitGrow.ts"],"sourcesContent":["import { useRef, useContext, useLayoutEffect, type RefObject } from 'react';\n\nimport { GrowLimiterContext } from '@hh.ru/magritte-ui-textarea/TextAreaGrowLimiter';\nimport type { TextAreaLayout } from '@hh.ru/magritte-ui-textarea/types';\n\ntype UseLimitGrowArgs = {\n layout: TextAreaLayout;\n contentCloneRef: RefObject<HTMLElement>;\n contentCloneWrapperRef: RefObject<HTMLElement>;\n resizableDivRef: RefObject<HTMLElement>;\n textAreaRef: RefObject<HTMLTextAreaElement>;\n minHeight: number;\n};\n\nexport const useLimitGrow = ({\n layout,\n contentCloneRef,\n contentCloneWrapperRef,\n resizableDivRef,\n textAreaRef,\n minHeight,\n}: UseLimitGrowArgs): { maxHeightRef: RefObject<string>; allowScrollRef: RefObject<boolean> } => {\n const growLimiterContext = useContext(GrowLimiterContext);\n const allowScrollRef = useRef(false);\n const maxHeightRef = useRef<string | null>(null);\n\n if (layout !== 'hug' || !growLimiterContext.hasLimit) {\n maxHeightRef.current = null;\n allowScrollRef.current = true;\n }\n\n useLayoutEffect(() => {\n if (layout !== 'hug' || !contentCloneRef.current || !growLimiterContext.hasLimit) {\n return void 0;\n }\n\n const applyHeightLimit = () => {\n if (\n !resizableDivRef.current ||\n !contentCloneWrapperRef.current ||\n !contentCloneRef.current ||\n !textAreaRef.current\n ) {\n return;\n }\n\n // Сравниваем высоту контейнера содержащего клон контента текстарии и его обертки. Контейнер может свободно\n // менять высоту чтобы уместить весь контент. Обертка может только свободно уменьшаться, при увеличении\n // размера контента размер обертки не меняется. Вычитая одно из другого получаем положительное число равное\n // изменению размера контента если контент стал больше, и 0 если он уменьшился.\n const contentCloneHeight = contentCloneRef.current.offsetHeight;\n const contentCloneWrapperHeight = contentCloneWrapperRef.current.offsetHeight;\n const contentHeightDelta = contentCloneHeight - contentCloneWrapperHeight;\n // Размер внешнего контейнера текстарии\n const height = resizableDivRef.current.offsetHeight;\n\n // Получаем количество свободного пространства в контейнере которое можем занять до получения скролла\n // Число может быть отрицательным если в контейнере уже присутствует скролл, тогда это количество пикселей\n // на которое нужно уменьшить высоту контента чтобы скролл исчез.\n const heightDiff = growLimiterContext.getHeightDiff();\n // Вычисляем новую высоту внешнего контейнера как сумму его текущей высоты и дельты высоты контента.\n // Убеждаемся что добавляем к высоте текстарии не больше пикселей, чем доступно в контейнере до появления\n // скролла. В результате размер текстарии может уменьшиться, если в контейнере доступно отрицательное\n // количество пикселей до появления скролла (в случае если скролл уже появился из-за добавления другого\n // контента например).\n // Убеждаемся, что высота не стала меньше минимальной допустимой\n const appliedHeight = Math.max(height + Math.min(contentHeightDelta, heightDiff), minHeight);\n allowScrollRef.current = contentHeightDelta > heightDiff || heightDiff < 0;\n textAreaRef.current.style.overflowY = allowScrollRef.current ? 'auto' : 'hidden';\n resizableDivRef.current.style.height = `${appliedHeight}px`;\n maxHeightRef.current = `${appliedHeight}px`;\n if (appliedHeight !== height) {\n // При тестировании в хроме с 20x slowdown сброс кеша в height diff контексте не успевал сработать за\n // период дебаунса, из-за этого если зажать enter компонент мог стать больше по высоте чем контейнер\n // и ограничение срабатывало только после отпускания клавиши,поэтому добавил принудительный сброс кеша\n // при изменении размера компонента\n growLimiterContext.heightUpdated();\n }\n };\n\n const observer = new ResizeObserver(applyHeightLimit);\n // Запускаем процесс пересчета максимальной высоты текстарии каждый раз\n // когда вертикальный размер контента меняется\n observer.observe(contentCloneRef.current, { box: 'border-box' });\n const context = growLimiterContext;\n // Так же запускаем его когда меняется размер контейнера скролла в котором мы пытаемся избежать.\n // Или размер обертки которую создает TextAreaGrowLimiter, например вследствие добавления или удаления\n // контента рядом с текстарией.\n context.onHeightChange(applyHeightLimit);\n applyHeightLimit();\n\n return () => {\n observer.disconnect();\n context.offHeightChange(applyHeightLimit);\n };\n }, [layout, growLimiterContext, contentCloneRef, contentCloneWrapperRef, resizableDivRef, minHeight, textAreaRef]);\n\n return { maxHeightRef, allowScrollRef };\n};\n"],"names":[],"mappings":"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"}
|