@evergis/uilib-gl 1.0.139 → 1.0.140
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/dist/molecules/IconButton/types.d.ts +6 -0
- package/dist/molecules/Textarea/constants.d.ts +8 -0
- package/dist/molecules/Textarea/hooks/index.d.ts +2 -0
- package/dist/molecules/Textarea/hooks/useTextareaAutoResize.d.ts +15 -0
- package/dist/molecules/Textarea/hooks/useTextareaResizeTriggers.d.ts +6 -0
- package/dist/molecules/Textarea/types.d.ts +2 -0
- package/dist/molecules/Textarea/utils.d.ts +8 -0
- package/dist/uilib-gl.esm.js +239 -50
- package/dist/uilib-gl.esm.js.map +1 -1
- package/package.json +1 -1
|
@@ -17,6 +17,11 @@ export interface IIconButtonProps extends ButtonHTMLAttributes<HTMLButtonElement
|
|
|
17
17
|
onClick?: (e: MouseEvent<HTMLButtonElement>) => void;
|
|
18
18
|
icon?: ReactNode;
|
|
19
19
|
iconRight?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Иконка над подписью, подпись по центру с переносом по словам, шеврон — под подписью.
|
|
22
|
+
* Перекрывает iconRight. Работает в обоих режимах, сам по себе новый режим не включает.
|
|
23
|
+
*/
|
|
24
|
+
iconTop?: boolean;
|
|
20
25
|
active?: boolean;
|
|
21
26
|
/** Заливка и обводка. Включает новый режим. */
|
|
22
27
|
variant?: IconButtonVariant;
|
|
@@ -42,6 +47,7 @@ export interface IconButtonProps {
|
|
|
42
47
|
error?: boolean;
|
|
43
48
|
notFixedWidth?: boolean;
|
|
44
49
|
iconRight?: boolean;
|
|
50
|
+
iconTop?: boolean;
|
|
45
51
|
active?: boolean;
|
|
46
52
|
hasBg?: boolean;
|
|
47
53
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Минимальная высота поля с autoResize, если `minHeight` не задан. */
|
|
2
|
+
export declare const DEFAULT_AUTO_RESIZE_MIN_HEIGHT = 36;
|
|
3
|
+
/** Текст замера пустого поля без placeholder — даёт высоту одной строки. */
|
|
4
|
+
export declare const EMPTY_MEASURE_TEXT = "x";
|
|
5
|
+
/** Свойства, от которых зависит раскладка текста: замерщик повторяет их за полем. */
|
|
6
|
+
export declare const SIZING_STYLE_PROPERTIES: string[];
|
|
7
|
+
/** Замерщик невидим и нулевой высоты — его `scrollHeight` равен высоте текста с отступами. */
|
|
8
|
+
export declare const HIDDEN_TEXTAREA_STYLE: string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CSSProperties } from "react";
|
|
2
|
+
import { ITextareaProps } from "../types";
|
|
3
|
+
type UseTextareaAutoResizeParams = Pick<ITextareaProps, "autoResize" | "value" | "placeholder" | "minHeight" | "maxHeight" | "innerRef">;
|
|
4
|
+
/**
|
|
5
|
+
* Высота поля с autoResize — по фактической раскладке текста (см. `calculateTextareaHeight`).
|
|
6
|
+
*
|
|
7
|
+
* Пересчёт идёт до отрисовки при смене значения, placeholder и пределов, а события вне React
|
|
8
|
+
* ловит `useTextareaResizeTriggers`. Высота уходит inline-стилем: через styled-проп каждое её
|
|
9
|
+
* значение порождало бы новый класс.
|
|
10
|
+
*/
|
|
11
|
+
export declare const useTextareaAutoResize: ({ autoResize, value, placeholder, minHeight, maxHeight, innerRef, }: UseTextareaAutoResizeParams) => {
|
|
12
|
+
ref: (node: HTMLTextAreaElement | null) => void;
|
|
13
|
+
style: CSSProperties | undefined;
|
|
14
|
+
};
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { MutableRefObject } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Пересчёт высоты на события вне React: ввод в неконтролируемое поле, смена ширины поля (перенос
|
|
4
|
+
* строк меняется вместе с ней) и загрузка шрифтов (меняет ширину глифов и высоту строки).
|
|
5
|
+
*/
|
|
6
|
+
export declare const useTextareaResizeTriggers: (element: MutableRefObject<HTMLTextAreaElement | null>, enabled: boolean | undefined, updateHeight: () => void) => void;
|
|
@@ -4,6 +4,8 @@ export interface ITextareaProps extends ITextFieldProps {
|
|
|
4
4
|
help?: ReactNode;
|
|
5
5
|
id?: string;
|
|
6
6
|
minHeight?: number;
|
|
7
|
+
/** Предел высоты в пикселях: `autoResize` дальше не растит, лишнее прокручивается. */
|
|
8
|
+
maxHeight?: number;
|
|
7
9
|
autoResize?: boolean;
|
|
8
10
|
innerRef?: RefType<HTMLTextAreaElement>;
|
|
9
11
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Высота, при которой текст поля помещается без прокрутки, — в единицах `box-sizing` поля.
|
|
3
|
+
*
|
|
4
|
+
* Текст раскладывает сам браузер: замерщик повторяет ширину, шрифт, отступы и рамки поля, а
|
|
5
|
+
* нулевая высота делает его `scrollHeight` равным высоте текста. Поэтому замер верен для любых
|
|
6
|
+
* глифов, переносов по словам и пустых строк.
|
|
7
|
+
*/
|
|
8
|
+
export declare const calculateTextareaHeight: (textarea: HTMLTextAreaElement) => number;
|
package/dist/uilib-gl.esm.js
CHANGED
|
@@ -14657,12 +14657,24 @@ const getRadius = props => {
|
|
|
14657
14657
|
|
|
14658
14658
|
return props.$shape === "round" ? "9999px" : getSize(props).radius;
|
|
14659
14659
|
};
|
|
14660
|
+
|
|
14661
|
+
const getPaddingX = props => props.$iconOnly ? "0" : getSize(props).paddingX;
|
|
14662
|
+
/** Колонка: иконка, подпись по центру с переносом, шеврон. Вертикальный отступ равен gap размера. */
|
|
14663
|
+
|
|
14664
|
+
|
|
14665
|
+
const iconButtonIconTopMixin = css`
|
|
14666
|
+
flex-direction: column;
|
|
14667
|
+
height: auto;
|
|
14668
|
+
min-height: ${props => getSize(props).height};
|
|
14669
|
+
padding: ${props => getSize(props).gap} ${getPaddingX};
|
|
14670
|
+
white-space: normal;
|
|
14671
|
+
text-align: center;
|
|
14672
|
+
`;
|
|
14660
14673
|
/**
|
|
14661
14674
|
* Состояния: проп active держит «нажатый» вид постоянно (и на hover), data-state="hover|active"
|
|
14662
14675
|
* включает состояние статично (для Storybook). Disabled объявлен последним — побеждает остальные.
|
|
14663
14676
|
*/
|
|
14664
14677
|
|
|
14665
|
-
|
|
14666
14678
|
const iconButtonStatesMixin = _ref2 => {
|
|
14667
14679
|
let {
|
|
14668
14680
|
theme,
|
|
@@ -14708,7 +14720,7 @@ const iconButtonVariantMixin = css`
|
|
|
14708
14720
|
height: ${props => getSize(props).height};
|
|
14709
14721
|
min-width: ${props => getSize(props).height};
|
|
14710
14722
|
width: ${props => props.$iconOnly ? getSize(props).height : "auto"};
|
|
14711
|
-
padding: 0 ${
|
|
14723
|
+
padding: 0 ${getPaddingX};
|
|
14712
14724
|
border: none;
|
|
14713
14725
|
border-radius: ${getRadius};
|
|
14714
14726
|
outline: none;
|
|
@@ -14717,13 +14729,20 @@ const iconButtonVariantMixin = css`
|
|
|
14717
14729
|
text-transform: ${props => getSize(props).textTransform};
|
|
14718
14730
|
white-space: nowrap;
|
|
14719
14731
|
transition: background-color ${transition.hover}, color ${transition.hover}, box-shadow ${transition.hover};
|
|
14732
|
+
${_ref3 => {
|
|
14733
|
+
let {
|
|
14734
|
+
iconTop
|
|
14735
|
+
} = _ref3;
|
|
14736
|
+
return iconTop && iconButtonIconTopMixin;
|
|
14737
|
+
}};
|
|
14720
14738
|
|
|
14721
14739
|
${Icon} {
|
|
14722
|
-
order: ${
|
|
14740
|
+
order: ${_ref4 => {
|
|
14723
14741
|
let {
|
|
14724
|
-
iconRight
|
|
14725
|
-
|
|
14726
|
-
|
|
14742
|
+
iconRight,
|
|
14743
|
+
iconTop
|
|
14744
|
+
} = _ref4;
|
|
14745
|
+
return iconRight && !iconTop ? 2 : 0;
|
|
14727
14746
|
}};
|
|
14728
14747
|
display: flex;
|
|
14729
14748
|
align-items: center;
|
|
@@ -14856,7 +14875,20 @@ const buttonMixin = css`
|
|
|
14856
14875
|
pointer-events: none;
|
|
14857
14876
|
}
|
|
14858
14877
|
`;
|
|
14859
|
-
|
|
14878
|
+
/** Колонка: иконка, под ней подпись по центру; перекрывает iconRight. */
|
|
14879
|
+
|
|
14880
|
+
const defaultIconTopMixin = css`
|
|
14881
|
+
flex-direction: column;
|
|
14882
|
+
height: auto;
|
|
14883
|
+
min-height: 2.25rem;
|
|
14884
|
+
padding: 0.5rem 1rem;
|
|
14885
|
+
text-align: center;
|
|
14886
|
+
|
|
14887
|
+
${IconButtonInnerChild} {
|
|
14888
|
+
margin: 0.25rem 0 0;
|
|
14889
|
+
}
|
|
14890
|
+
`;
|
|
14891
|
+
const defaultIconButtonMixin = css`
|
|
14860
14892
|
&:hover > ${Icon}, &:hover > ${IconButtonInnerChild} {
|
|
14861
14893
|
color: ${_ref7 => {
|
|
14862
14894
|
let {
|
|
@@ -14903,6 +14935,12 @@ const legacyIconButtonMixin = css`
|
|
|
14903
14935
|
}
|
|
14904
14936
|
|
|
14905
14937
|
${buttonMixin};
|
|
14938
|
+
${_ref11 => {
|
|
14939
|
+
let {
|
|
14940
|
+
iconTop
|
|
14941
|
+
} = _ref11;
|
|
14942
|
+
return iconTop && defaultIconTopMixin;
|
|
14943
|
+
}};
|
|
14906
14944
|
`;
|
|
14907
14945
|
const IconButtonButton = /*#__PURE__*/styled.button.attrs(props => ({
|
|
14908
14946
|
tabIndex: -1,
|
|
@@ -14910,11 +14948,11 @@ const IconButtonButton = /*#__PURE__*/styled.button.attrs(props => ({
|
|
|
14910
14948
|
}))`
|
|
14911
14949
|
flex-shrink: 0;
|
|
14912
14950
|
|
|
14913
|
-
${
|
|
14951
|
+
${_ref12 => {
|
|
14914
14952
|
let {
|
|
14915
14953
|
$variant
|
|
14916
|
-
} =
|
|
14917
|
-
return $variant ? iconButtonVariantMixin :
|
|
14954
|
+
} = _ref12;
|
|
14955
|
+
return $variant ? iconButtonVariantMixin : defaultIconButtonMixin;
|
|
14918
14956
|
}};
|
|
14919
14957
|
`;
|
|
14920
14958
|
|
|
@@ -22293,64 +22331,215 @@ const TextField = /*#__PURE__*/styled.textarea.attrs(props => ({
|
|
|
22293
22331
|
}};
|
|
22294
22332
|
`;
|
|
22295
22333
|
|
|
22296
|
-
|
|
22334
|
+
/** Минимальная высота поля с autoResize, если `minHeight` не задан. */
|
|
22335
|
+
const DEFAULT_AUTO_RESIZE_MIN_HEIGHT = 36;
|
|
22336
|
+
/** Текст замера пустого поля без placeholder — даёт высоту одной строки. */
|
|
22297
22337
|
|
|
22298
|
-
const
|
|
22338
|
+
const EMPTY_MEASURE_TEXT = "x";
|
|
22339
|
+
/** Свойства, от которых зависит раскладка текста: замерщик повторяет их за полем. */
|
|
22340
|
+
|
|
22341
|
+
const SIZING_STYLE_PROPERTIES = ["box-sizing", "width", "font-family", "font-size", "font-style", "font-weight", "font-variant", "font-stretch", "font-feature-settings", "letter-spacing", "word-spacing", "line-height", "text-indent", "text-transform", "text-rendering", "tab-size", "white-space", "word-break", "overflow-wrap", "padding-top", "padding-right", "padding-bottom", "padding-left", "border-top-width", "border-right-width", "border-bottom-width", "border-left-width", "border-top-style", "border-right-style", "border-bottom-style", "border-left-style"];
|
|
22342
|
+
/** Замерщик невидим и нулевой высоты — его `scrollHeight` равен высоте текста с отступами. */
|
|
22343
|
+
|
|
22344
|
+
const HIDDEN_TEXTAREA_STYLE = /*#__PURE__*/["min-height:0", "max-height:none", "height:0", "visibility:hidden", "overflow:hidden", "position:absolute", "z-index:-1000", "top:0", "right:0", "pointer-events:none"].map(declaration => `${declaration} !important`).join(";");
|
|
22345
|
+
|
|
22346
|
+
let hiddenTextarea = null;
|
|
22347
|
+
/** Один замерщик на все поля: живёт в `body`, вне раскладки страницы. */
|
|
22348
|
+
|
|
22349
|
+
const getHiddenTextarea = () => {
|
|
22350
|
+
if (!hiddenTextarea || !hiddenTextarea.parentNode) {
|
|
22351
|
+
hiddenTextarea = document.createElement("textarea");
|
|
22352
|
+
hiddenTextarea.setAttribute("tabindex", "-1");
|
|
22353
|
+
hiddenTextarea.setAttribute("aria-hidden", "true");
|
|
22354
|
+
document.body.appendChild(hiddenTextarea);
|
|
22355
|
+
}
|
|
22356
|
+
|
|
22357
|
+
return hiddenTextarea;
|
|
22358
|
+
};
|
|
22359
|
+
/** Пустое поле меряется по placeholder, чтобы длинная подсказка не обрезалась. */
|
|
22360
|
+
|
|
22361
|
+
|
|
22362
|
+
const getMeasureText = _ref => {
|
|
22299
22363
|
let {
|
|
22300
22364
|
value,
|
|
22301
|
-
|
|
22365
|
+
placeholder
|
|
22366
|
+
} = _ref;
|
|
22367
|
+
return value || placeholder || EMPTY_MEASURE_TEXT;
|
|
22368
|
+
};
|
|
22369
|
+
/**
|
|
22370
|
+
* Высота, при которой текст поля помещается без прокрутки, — в единицах `box-sizing` поля.
|
|
22371
|
+
*
|
|
22372
|
+
* Текст раскладывает сам браузер: замерщик повторяет ширину, шрифт, отступы и рамки поля, а
|
|
22373
|
+
* нулевая высота делает его `scrollHeight` равным высоте текста. Поэтому замер верен для любых
|
|
22374
|
+
* глифов, переносов по словам и пустых строк.
|
|
22375
|
+
*/
|
|
22376
|
+
|
|
22377
|
+
|
|
22378
|
+
const calculateTextareaHeight = textarea => {
|
|
22379
|
+
const computedStyle = window.getComputedStyle(textarea);
|
|
22380
|
+
const measurer = getHiddenTextarea();
|
|
22381
|
+
const sizingStyle = SIZING_STYLE_PROPERTIES.map(property => `${property}:${computedStyle.getPropertyValue(property)}`).join(";");
|
|
22382
|
+
measurer.style.cssText = `${sizingStyle};${HIDDEN_TEXTAREA_STYLE}`;
|
|
22383
|
+
measurer.value = getMeasureText(textarea);
|
|
22384
|
+
const {
|
|
22385
|
+
scrollHeight
|
|
22386
|
+
} = measurer; // scrollHeight включает внутренние отступы, но не рамку.
|
|
22387
|
+
|
|
22388
|
+
if (computedStyle.boxSizing === "border-box") {
|
|
22389
|
+
return scrollHeight + getNumberFromPixels(computedStyle.borderTopWidth) + getNumberFromPixels(computedStyle.borderBottomWidth);
|
|
22390
|
+
}
|
|
22391
|
+
|
|
22392
|
+
return scrollHeight - getNumberFromPixels(computedStyle.paddingTop) - getNumberFromPixels(computedStyle.paddingBottom);
|
|
22393
|
+
};
|
|
22394
|
+
|
|
22395
|
+
/**
|
|
22396
|
+
* Пересчёт высоты на события вне React: ввод в неконтролируемое поле, смена ширины поля (перенос
|
|
22397
|
+
* строк меняется вместе с ней) и загрузка шрифтов (меняет ширину глифов и высоту строки).
|
|
22398
|
+
*/
|
|
22399
|
+
|
|
22400
|
+
const useTextareaResizeTriggers = (element, enabled, updateHeight) => {
|
|
22401
|
+
const latestUpdateHeight = useRef(updateHeight);
|
|
22402
|
+
latestUpdateHeight.current = updateHeight;
|
|
22403
|
+
useEffect(() => {
|
|
22404
|
+
const textarea = element.current;
|
|
22405
|
+
if (!enabled || !textarea) return;
|
|
22406
|
+
let frameId = 0;
|
|
22407
|
+
let isActive = true;
|
|
22408
|
+
let width = textarea.offsetWidth; // Через кадр: смена высоты внутри колбэка ResizeObserver зациклила бы его.
|
|
22409
|
+
|
|
22410
|
+
const scheduleUpdate = () => {
|
|
22411
|
+
window.cancelAnimationFrame(frameId);
|
|
22412
|
+
frameId = window.requestAnimationFrame(() => latestUpdateHeight.current());
|
|
22413
|
+
}; // Своя смена высоты тоже будит наблюдателя — пересчёт нужен только при новой ширине.
|
|
22414
|
+
|
|
22415
|
+
|
|
22416
|
+
const onResize = () => {
|
|
22417
|
+
if (textarea.offsetWidth === width) return;
|
|
22418
|
+
width = textarea.offsetWidth;
|
|
22419
|
+
scheduleUpdate();
|
|
22420
|
+
};
|
|
22421
|
+
|
|
22422
|
+
const {
|
|
22423
|
+
ResizeObserver: ResizeObserverClass
|
|
22424
|
+
} = window;
|
|
22425
|
+
const resizeObserver = ResizeObserverClass ? new ResizeObserverClass(onResize) : null;
|
|
22426
|
+
const {
|
|
22427
|
+
fonts
|
|
22428
|
+
} = document;
|
|
22429
|
+
resizeObserver == null ? void 0 : resizeObserver.observe(textarea);
|
|
22430
|
+
textarea.addEventListener("input", scheduleUpdate);
|
|
22431
|
+
fonts == null ? void 0 : fonts.ready.then(() => isActive && scheduleUpdate());
|
|
22432
|
+
return () => {
|
|
22433
|
+
isActive = false;
|
|
22434
|
+
window.cancelAnimationFrame(frameId);
|
|
22435
|
+
resizeObserver == null ? void 0 : resizeObserver.disconnect();
|
|
22436
|
+
textarea.removeEventListener("input", scheduleUpdate);
|
|
22437
|
+
};
|
|
22438
|
+
}, [element, enabled]);
|
|
22439
|
+
};
|
|
22440
|
+
|
|
22441
|
+
/**
|
|
22442
|
+
* Высота поля с autoResize — по фактической раскладке текста (см. `calculateTextareaHeight`).
|
|
22443
|
+
*
|
|
22444
|
+
* Пересчёт идёт до отрисовки при смене значения, placeholder и пределов, а события вне React
|
|
22445
|
+
* ловит `useTextareaResizeTriggers`. Высота уходит inline-стилем: через styled-проп каждое её
|
|
22446
|
+
* значение порождало бы новый класс.
|
|
22447
|
+
*/
|
|
22448
|
+
|
|
22449
|
+
const useTextareaAutoResize = _ref => {
|
|
22450
|
+
let {
|
|
22302
22451
|
autoResize,
|
|
22303
|
-
|
|
22452
|
+
value,
|
|
22453
|
+
placeholder,
|
|
22454
|
+
minHeight = DEFAULT_AUTO_RESIZE_MIN_HEIGHT,
|
|
22455
|
+
maxHeight,
|
|
22456
|
+
innerRef
|
|
22304
22457
|
} = _ref;
|
|
22305
|
-
const [height, setHeight] = useState(0);
|
|
22306
|
-
const [containerSize, setContainerSize] = useState(0);
|
|
22307
|
-
const [lettersSize, setLettersSize] = useState(0);
|
|
22308
22458
|
const element = useRef(null);
|
|
22309
|
-
const
|
|
22310
|
-
const
|
|
22311
|
-
const
|
|
22312
|
-
|
|
22459
|
+
const [size, setSize] = useState(null);
|
|
22460
|
+
const updateHeight = useCallback(() => {
|
|
22461
|
+
const textarea = element.current; // Скрытое поле (display: none) не имеет ширины — замер был бы ложным, его догонит ResizeObserver.
|
|
22462
|
+
|
|
22463
|
+
if (!autoResize || !textarea || !textarea.offsetWidth) return;
|
|
22464
|
+
const contentHeight = calculateTextareaHeight(textarea);
|
|
22465
|
+
const limitedHeight = maxHeight ? Math.min(contentHeight, maxHeight) : contentHeight;
|
|
22466
|
+
const height = Math.max(minHeight, limitedHeight);
|
|
22467
|
+
const overflows = contentHeight > height;
|
|
22468
|
+
setSize(prevSize => (prevSize == null ? void 0 : prevSize.height) === height && prevSize.overflows === overflows ? prevSize : {
|
|
22469
|
+
height,
|
|
22470
|
+
overflows
|
|
22471
|
+
});
|
|
22472
|
+
}, [autoResize, minHeight, maxHeight]); // Значение и placeholder замер читает из DOM — в зависимостях они только будят пересчёт.
|
|
22313
22473
|
|
|
22314
|
-
|
|
22315
|
-
|
|
22316
|
-
|
|
22474
|
+
useLayoutEffect(() => {
|
|
22475
|
+
updateHeight();
|
|
22476
|
+
}, [updateHeight, value, placeholder]);
|
|
22477
|
+
useTextareaResizeTriggers(element, autoResize, updateHeight);
|
|
22478
|
+
const ref = useCallback(node => {
|
|
22479
|
+
element.current = node;
|
|
22480
|
+
|
|
22481
|
+
if (typeof innerRef === "function") {
|
|
22482
|
+
innerRef(node);
|
|
22483
|
+
} else if (innerRef) {
|
|
22484
|
+
innerRef.current = node;
|
|
22485
|
+
}
|
|
22486
|
+
}, [innerRef]);
|
|
22487
|
+
const style = useMemo(() => size ? {
|
|
22488
|
+
height: size.height,
|
|
22489
|
+
overflowY: size.overflows ? "auto" : "hidden"
|
|
22490
|
+
} : undefined, [size]);
|
|
22491
|
+
return {
|
|
22492
|
+
ref,
|
|
22493
|
+
style
|
|
22494
|
+
};
|
|
22495
|
+
};
|
|
22317
22496
|
|
|
22318
|
-
|
|
22319
|
-
|
|
22320
|
-
|
|
22321
|
-
|
|
22322
|
-
|
|
22323
|
-
|
|
22324
|
-
|
|
22325
|
-
|
|
22326
|
-
|
|
22327
|
-
|
|
22328
|
-
|
|
22329
|
-
|
|
22330
|
-
|
|
22331
|
-
|
|
22332
|
-
|
|
22333
|
-
|
|
22334
|
-
|
|
22335
|
-
|
|
22336
|
-
|
|
22337
|
-
|
|
22338
|
-
|
|
22339
|
-
|
|
22497
|
+
const LabeledTextarea = /*#__PURE__*/withLabel(TextField);
|
|
22498
|
+
|
|
22499
|
+
const TextareaComponent = _ref => {
|
|
22500
|
+
let {
|
|
22501
|
+
value,
|
|
22502
|
+
minHeight,
|
|
22503
|
+
maxHeight,
|
|
22504
|
+
autoResize,
|
|
22505
|
+
style,
|
|
22506
|
+
innerRef,
|
|
22507
|
+
...textareaProps
|
|
22508
|
+
} = _ref;
|
|
22509
|
+
const {
|
|
22510
|
+
ref,
|
|
22511
|
+
style: autoResizeStyle
|
|
22512
|
+
} = useTextareaAutoResize({
|
|
22513
|
+
autoResize,
|
|
22514
|
+
value,
|
|
22515
|
+
placeholder: textareaProps.placeholder,
|
|
22516
|
+
minHeight,
|
|
22517
|
+
maxHeight,
|
|
22518
|
+
innerRef
|
|
22519
|
+
});
|
|
22340
22520
|
|
|
22341
22521
|
if (autoResize) {
|
|
22342
22522
|
return React.createElement(LabeledTextarea, {
|
|
22343
|
-
height: `${height}px`,
|
|
22344
22523
|
value: value,
|
|
22345
22524
|
...textareaProps,
|
|
22525
|
+
style: { ...style,
|
|
22526
|
+
...autoResizeStyle
|
|
22527
|
+
},
|
|
22346
22528
|
resize: "none",
|
|
22347
|
-
innerRef: ref
|
|
22529
|
+
innerRef: ref
|
|
22348
22530
|
});
|
|
22349
|
-
}
|
|
22531
|
+
} // Без autoResize высоту держит сам textarea: пределы ограничивают её и ручной resize.
|
|
22532
|
+
|
|
22350
22533
|
|
|
22351
22534
|
return React.createElement(LabeledTextarea, {
|
|
22352
22535
|
value: value,
|
|
22353
|
-
...textareaProps
|
|
22536
|
+
...textareaProps,
|
|
22537
|
+
innerRef: innerRef,
|
|
22538
|
+
style: {
|
|
22539
|
+
minHeight,
|
|
22540
|
+
maxHeight,
|
|
22541
|
+
...style
|
|
22542
|
+
}
|
|
22354
22543
|
});
|
|
22355
22544
|
};
|
|
22356
22545
|
|