maru_design2 2.24.4 → 2.25.0
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/CHANGELOG.md +14 -0
- package/dist/components/atoms/textarea/Textarea.d.ts +13 -0
- package/dist/index.js +87 -27
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.25.0](https://github.com/42maru-ai/maru-design2/compare/v2.24.4...v2.25.0) (2025-04-08)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* :sparkles: Textarea - add minRows, maxRows [#540](https://github.com/42maru-ai/maru-design2/issues/540) ([b907d40](https://github.com/42maru-ai/maru-design2/commit/b907d40834eb48baea693d94364940605478963a))
|
|
9
|
+
* :sparkles: Textarea - add resizable [#553](https://github.com/42maru-ai/maru-design2/issues/553) ([594031e](https://github.com/42maru-ai/maru-design2/commit/594031e12f14870708e691b1f59fc863c948aa20))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* :bug: Textarea - fix condition & update storybook ([7f14d1a](https://github.com/42maru-ai/maru-design2/commit/7f14d1a95f53956e2a5a6fcbcbdfc5a3ed9d440c))
|
|
15
|
+
* :bug: Textarea - fix init scrollHeight ([c6aa3cc](https://github.com/42maru-ai/maru-design2/commit/c6aa3ccf3f2b2e1b1947bf5a70943044ad2e9f40))
|
|
16
|
+
|
|
3
17
|
## [2.24.4](https://github.com/42maru-ai/maru-design2/compare/v2.24.3...v2.24.4) (2025-03-31)
|
|
4
18
|
|
|
5
19
|
|
|
@@ -21,5 +21,18 @@ export interface TextareaProps extends Omit<React.TextareaHTMLAttributes<HTMLTex
|
|
|
21
21
|
*/
|
|
22
22
|
wrapperRef?: React.RefObject<HTMLDivElement>;
|
|
23
23
|
className?: string;
|
|
24
|
+
/**
|
|
25
|
+
* 최소 높이. 없으면 props.rows 이거나 1로 설정.
|
|
26
|
+
*/
|
|
27
|
+
minRows?: number;
|
|
28
|
+
/**
|
|
29
|
+
* 최대 높이. 없으면 무한대 늘어남.
|
|
30
|
+
*/
|
|
31
|
+
maxRows?: number;
|
|
32
|
+
/**
|
|
33
|
+
* 바닥 선분을 마우스로 드래그해서 크기를 조절할 수 있는지 여부
|
|
34
|
+
* - 기본값은 false
|
|
35
|
+
*/
|
|
36
|
+
resizable?: boolean;
|
|
24
37
|
}
|
|
25
38
|
export declare const Textarea: React.ForwardRefExoticComponent<TextareaProps & React.RefAttributes<HTMLTextAreaElement>>;
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import React__default, { useState, useMemo, forwardRef, useEffect, useRef, createElement, Component, useLayoutEffect, createRef } from 'react';
|
|
3
|
+
import React__default, { useState, useMemo, forwardRef, useEffect, useRef, useCallback, createElement, Component, useLayoutEffect, createRef } from 'react';
|
|
4
4
|
import * as ReactDOM from 'react-dom';
|
|
5
5
|
import ReactDOM__default, { findDOMNode } from 'react-dom';
|
|
6
6
|
|
|
@@ -8891,7 +8891,7 @@ function Slider(_a) {
|
|
|
8891
8891
|
}));
|
|
8892
8892
|
}
|
|
8893
8893
|
|
|
8894
|
-
var css_248z$b = ".maru-textarea-wrapper .maru-textarea {\n display: flex;\n justify-content: center;\n align-items: flex-start;\n flex-direction: row;\n padding: 8px 8px 8px 12px;\n border: 1px solid #e4e4e4;\n border-radius: 6px;\n gap: 8px;\n}\n.maru-textarea-wrapper .maru-textarea > textarea {\n width: 100%;\n border: unset;\n outline: unset;\n background-color: transparent;\n font-family: Pretendard;\n font-style: normal;\n line-height: 150%;\n font-size: 14px;\n letter-spacing: -0.56px;\n font-weight: 400;\n color: #5c5c5c;\n resize: none;\n}\n.maru-textarea-wrapper .maru-textarea > textarea::-webkit-input-placeholder {\n font-weight: 300;\n color: #8c8c8c;\n}\n.maru-textarea-wrapper .maru-textarea > textarea::-moz-placeholder {\n font-weight: 300;\n color: #8c8c8c;\n}\n.maru-textarea-wrapper .maru-textarea > textarea:-ms-input-placeholder {\n font-weight: 300;\n color: #8c8c8c;\n}\n.maru-textarea-wrapper .maru-textarea > textarea::-ms-input-placeholder {\n font-weight: 300;\n color: #8c8c8c;\n}\n.maru-textarea-wrapper .maru-textarea > textarea::placeholder {\n font-weight: 300;\n color: #8c8c8c;\n}\n.maru-textarea-wrapper .maru-textarea:focus-visible, .maru-textarea-wrapper .maru-textarea:focus-within {\n border-color: #5c5c5c;\n background-color: #fafafa;\n}\n.maru-textarea-wrapper .maru-textarea.errored {\n outline: 1px solid #e53e3e;\n border-color: #e53e3e;\n}\n.maru-textarea-wrapper .maru-textarea:hover {\n outline: 1px solid #e4e4e4;\n border-color: #e4e4e4;\n background-color: #fafafa;\n}\n.maru-textarea-wrapper .maru-textarea.disabled {\n background-color: #fafafa;\n}\n.maru-textarea-wrapper .maru-textarea.disabled > textarea {\n color: #bdbdbd;\n}\n.maru-textarea-wrapper .maru-textarea.disabled > textarea::-webkit-input-placeholder {\n color: #bdbdbd;\n}\n.maru-textarea-wrapper .maru-textarea.disabled > textarea::-moz-placeholder {\n color: #bdbdbd;\n}\n.maru-textarea-wrapper .maru-textarea.disabled > textarea:-ms-input-placeholder {\n color: #bdbdbd;\n}\n.maru-textarea-wrapper .maru-textarea.disabled > textarea::-ms-input-placeholder {\n color: #bdbdbd;\n}\n.maru-textarea-wrapper .maru-textarea.disabled > textarea::placeholder {\n color: #bdbdbd;\n}\n.maru-textarea-wrapper .maru-textarea.disabled:hover {\n outline: unset;\n}\n.maru-textarea-wrapper .maru-textarea-end-node-wrapper {\n display: flex;\n justify-content: center;\n align-items: center;\n flex-direction: row;\n}\n.maru-textarea-wrapper .maru-textarea-end-node-wrapper > button {\n padding: unset;\n margin: unset;\n border: unset;\n background-color: unset;\n cursor: pointer;\n width: 16px;\n height: 16px;\n}\n.maru-textarea-wrapper .maru-textarea-footer {\n display: block;\n margin-top: 4px;\n}\n.maru-textarea-wrapper .maru-textarea-footer > span {\n font-family: Pretendard;\n font-style: normal;\n line-height: 150%;\n font-size: 12px;\n letter-spacing: -0.48px;\n font-weight: 500;\n color: #e53e3e;\n}";
|
|
8894
|
+
var css_248z$b = ".maru-textarea-wrapper .maru-textarea-resizable-wrapper {\n position: relative;\n}\n.maru-textarea-wrapper .maru-textarea {\n display: flex;\n justify-content: center;\n align-items: flex-start;\n flex-direction: row;\n padding: 8px 8px 8px 12px;\n border: 1px solid #e4e4e4;\n border-radius: 6px;\n gap: 8px;\n}\n.maru-textarea-wrapper .maru-textarea > textarea {\n width: 100%;\n border: unset;\n outline: unset;\n background-color: transparent;\n font-family: Pretendard;\n font-style: normal;\n line-height: 150%;\n font-size: 14px;\n letter-spacing: -0.56px;\n font-weight: 400;\n color: #5c5c5c;\n resize: none;\n}\n.maru-textarea-wrapper .maru-textarea > textarea::-webkit-input-placeholder {\n font-weight: 300;\n color: #8c8c8c;\n}\n.maru-textarea-wrapper .maru-textarea > textarea::-moz-placeholder {\n font-weight: 300;\n color: #8c8c8c;\n}\n.maru-textarea-wrapper .maru-textarea > textarea:-ms-input-placeholder {\n font-weight: 300;\n color: #8c8c8c;\n}\n.maru-textarea-wrapper .maru-textarea > textarea::-ms-input-placeholder {\n font-weight: 300;\n color: #8c8c8c;\n}\n.maru-textarea-wrapper .maru-textarea > textarea::placeholder {\n font-weight: 300;\n color: #8c8c8c;\n}\n.maru-textarea-wrapper .maru-textarea:focus-visible, .maru-textarea-wrapper .maru-textarea:focus-within {\n border-color: #5c5c5c;\n background-color: #fafafa;\n}\n.maru-textarea-wrapper .maru-textarea.errored {\n outline: 1px solid #e53e3e;\n border-color: #e53e3e;\n}\n.maru-textarea-wrapper .maru-textarea:hover {\n outline: 1px solid #e4e4e4;\n border-color: #e4e4e4;\n background-color: #fafafa;\n}\n.maru-textarea-wrapper .maru-textarea.disabled {\n background-color: #fafafa;\n}\n.maru-textarea-wrapper .maru-textarea.disabled > textarea {\n color: #bdbdbd;\n}\n.maru-textarea-wrapper .maru-textarea.disabled > textarea::-webkit-input-placeholder {\n color: #bdbdbd;\n}\n.maru-textarea-wrapper .maru-textarea.disabled > textarea::-moz-placeholder {\n color: #bdbdbd;\n}\n.maru-textarea-wrapper .maru-textarea.disabled > textarea:-ms-input-placeholder {\n color: #bdbdbd;\n}\n.maru-textarea-wrapper .maru-textarea.disabled > textarea::-ms-input-placeholder {\n color: #bdbdbd;\n}\n.maru-textarea-wrapper .maru-textarea.disabled > textarea::placeholder {\n color: #bdbdbd;\n}\n.maru-textarea-wrapper .maru-textarea.disabled:hover {\n outline: unset;\n}\n.maru-textarea-wrapper .maru-textarea-end-node-wrapper {\n display: flex;\n justify-content: center;\n align-items: center;\n flex-direction: row;\n}\n.maru-textarea-wrapper .maru-textarea-end-node-wrapper > button {\n padding: unset;\n margin: unset;\n border: unset;\n background-color: unset;\n cursor: pointer;\n width: 16px;\n height: 16px;\n}\n.maru-textarea-wrapper .resizer {\n position: absolute;\n bottom: 0;\n left: 0;\n height: 5px;\n width: 100%;\n cursor: ns-resize;\n background: transparent;\n}\n.maru-textarea-wrapper .maru-textarea-footer {\n display: block;\n margin-top: 4px;\n}\n.maru-textarea-wrapper .maru-textarea-footer > span {\n font-family: Pretendard;\n font-style: normal;\n line-height: 150%;\n font-size: 12px;\n letter-spacing: -0.48px;\n font-weight: 500;\n color: #e53e3e;\n}";
|
|
8895
8895
|
styleInject(css_248z$b);
|
|
8896
8896
|
|
|
8897
8897
|
var Textarea = /*#__PURE__*/forwardRef(function (_a, textareaRef) {
|
|
@@ -8900,15 +8900,40 @@ var Textarea = /*#__PURE__*/forwardRef(function (_a, textareaRef) {
|
|
|
8900
8900
|
hiddenClearButton = _a.hiddenClearButton,
|
|
8901
8901
|
wrapperRef = _a.wrapperRef,
|
|
8902
8902
|
className = _a.className,
|
|
8903
|
-
|
|
8904
|
-
|
|
8905
|
-
|
|
8906
|
-
|
|
8903
|
+
minRows = _a.minRows,
|
|
8904
|
+
maxRows = _a.maxRows,
|
|
8905
|
+
_b = _a.resizable,
|
|
8906
|
+
resizable = _b === void 0 ? false : _b,
|
|
8907
|
+
props = __rest(_a, ["invalid", "onClear", "hiddenClearButton", "wrapperRef", "className", "minRows", "maxRows", "resizable"]);
|
|
8908
|
+
var _c = useState(false),
|
|
8909
|
+
showClearButton = _c[0],
|
|
8910
|
+
setShowClearButton = _c[1];
|
|
8907
8911
|
var combineRef = useCombineRef(textareaRef);
|
|
8912
|
+
var minHeight = useCallback(function (lineHeight) {
|
|
8913
|
+
return minRows ? minRows * lineHeight : 0;
|
|
8914
|
+
}, [minRows]);
|
|
8915
|
+
var maxHeight = useCallback(function (lineHeight) {
|
|
8916
|
+
return maxRows ? maxRows * lineHeight : Infinity;
|
|
8917
|
+
}, [maxRows]);
|
|
8918
|
+
/**
|
|
8919
|
+
* textarea의 높이를 조절하는 함수
|
|
8920
|
+
* - rows는 기본적으로 초기 높이 설정하는데에만 쓰임
|
|
8921
|
+
* - 동적 높이 조정은 css height 속성 변경으로 조정해야함
|
|
8922
|
+
*/
|
|
8908
8923
|
var resizeHeight = function resizeHeight() {
|
|
8909
8924
|
if (combineRef.current) {
|
|
8925
|
+
// 항상 그때의 scrollHeight를 가져오도록 높이를 초기화
|
|
8910
8926
|
combineRef.current.style.height = 'auto';
|
|
8911
|
-
|
|
8927
|
+
var lineHeight = parseInt(window.getComputedStyle(combineRef.current).lineHeight || '0', 10);
|
|
8928
|
+
var scrollHeight = combineRef.current.scrollHeight;
|
|
8929
|
+
if (lineHeight) {
|
|
8930
|
+
var min = minHeight(lineHeight);
|
|
8931
|
+
var max = maxHeight(lineHeight);
|
|
8932
|
+
var newHeight = Math.min(Math.max(scrollHeight, min), max);
|
|
8933
|
+
combineRef.current.style.height = "".concat(newHeight, "px");
|
|
8934
|
+
} else {
|
|
8935
|
+
combineRef.current.style.height = "".concat(scrollHeight, "px");
|
|
8936
|
+
}
|
|
8912
8937
|
}
|
|
8913
8938
|
};
|
|
8914
8939
|
useEffect(function () {
|
|
@@ -8955,33 +8980,65 @@ var Textarea = /*#__PURE__*/forwardRef(function (_a, textareaRef) {
|
|
|
8955
8980
|
onClear === null || onClear === void 0 ? void 0 : onClear();
|
|
8956
8981
|
resizeHeight();
|
|
8957
8982
|
};
|
|
8983
|
+
var handleResizerMouseDown = function handleResizerMouseDown(e) {
|
|
8984
|
+
var combine = combineRef === null || combineRef === void 0 ? void 0 : combineRef.current;
|
|
8985
|
+
if (resizable && combine) {
|
|
8986
|
+
var startY_1 = e.clientY;
|
|
8987
|
+
var startHeight_1 = combine.clientHeight;
|
|
8988
|
+
document.body.style.userSelect = 'none';
|
|
8989
|
+
var lineHeight = parseInt(window.getComputedStyle(combine).lineHeight || '0', 10);
|
|
8990
|
+
var min_1 = minHeight(lineHeight);
|
|
8991
|
+
var max_1 = maxHeight(lineHeight);
|
|
8992
|
+
var handleMouseMove_1 = function handleMouseMove_1(moveEvent) {
|
|
8993
|
+
var newHeight = startHeight_1 + moveEvent.clientY - startY_1;
|
|
8994
|
+
if (min_1 <= newHeight && newHeight <= max_1) {
|
|
8995
|
+
combine.style.height = "".concat(newHeight, "px");
|
|
8996
|
+
}
|
|
8997
|
+
};
|
|
8998
|
+
var handleMouseUp_1 = function handleMouseUp_1() {
|
|
8999
|
+
document.body.style.userSelect = '';
|
|
9000
|
+
document.removeEventListener('mousemove', handleMouseMove_1);
|
|
9001
|
+
document.removeEventListener('mouseup', handleMouseUp_1);
|
|
9002
|
+
};
|
|
9003
|
+
document.addEventListener('mousemove', handleMouseMove_1);
|
|
9004
|
+
document.addEventListener('mouseup', handleMouseUp_1);
|
|
9005
|
+
}
|
|
9006
|
+
};
|
|
8958
9007
|
return jsxs("div", __assign({
|
|
8959
9008
|
ref: wrapperRef,
|
|
8960
9009
|
className: classNames('maru-textarea-wrapper', className)
|
|
8961
9010
|
}, {
|
|
8962
9011
|
children: [jsxs("div", __assign({
|
|
8963
|
-
className:
|
|
8964
|
-
errored: invalid === null || invalid === void 0 ? void 0 : invalid.on,
|
|
8965
|
-
disabled: props.disabled
|
|
8966
|
-
})
|
|
9012
|
+
className: "maru-textarea-resizable-wrapper"
|
|
8967
9013
|
}, {
|
|
8968
|
-
children: [
|
|
8969
|
-
|
|
8970
|
-
|
|
8971
|
-
|
|
8972
|
-
|
|
9014
|
+
children: [jsxs("div", __assign({
|
|
9015
|
+
className: classNames('maru-textarea', {
|
|
9016
|
+
errored: invalid === null || invalid === void 0 ? void 0 : invalid.on,
|
|
9017
|
+
disabled: props.disabled
|
|
9018
|
+
})
|
|
8973
9019
|
}, {
|
|
8974
|
-
children:
|
|
8975
|
-
|
|
8976
|
-
|
|
8977
|
-
|
|
9020
|
+
children: [jsx("textarea", __assign({}, props, {
|
|
9021
|
+
ref: combineRef,
|
|
9022
|
+
onChange: handleTextareaChange,
|
|
9023
|
+
rows: props.rows || minRows || 1
|
|
9024
|
+
})), jsx("div", __assign({
|
|
9025
|
+
className: "maru-textarea-end-node-wrapper"
|
|
8978
9026
|
}, {
|
|
8979
|
-
children: jsx(
|
|
8980
|
-
|
|
8981
|
-
|
|
8982
|
-
|
|
8983
|
-
|
|
8984
|
-
|
|
9027
|
+
children: showClearButton && !props.disabled && jsx("button", __assign({
|
|
9028
|
+
type: "button",
|
|
9029
|
+
onClick: handleClearClick,
|
|
9030
|
+
tabIndex: -1
|
|
9031
|
+
}, {
|
|
9032
|
+
children: jsx(Icon, {
|
|
9033
|
+
name: ICONS.X_s1615,
|
|
9034
|
+
color: "#5c5c5c"
|
|
9035
|
+
})
|
|
9036
|
+
}))
|
|
9037
|
+
}))]
|
|
9038
|
+
})), resizable && jsx("div", {
|
|
9039
|
+
className: "resizer",
|
|
9040
|
+
onMouseDown: handleResizerMouseDown
|
|
9041
|
+
})]
|
|
8985
9042
|
})), invalid && invalid.on && jsx("div", __assign({
|
|
8986
9043
|
className: "maru-textarea-footer"
|
|
8987
9044
|
}, {
|
|
@@ -8996,7 +9053,10 @@ Textarea.defaultProps = {
|
|
|
8996
9053
|
onClear: undefined,
|
|
8997
9054
|
hiddenClearButton: undefined,
|
|
8998
9055
|
wrapperRef: undefined,
|
|
8999
|
-
className: undefined
|
|
9056
|
+
className: undefined,
|
|
9057
|
+
minRows: undefined,
|
|
9058
|
+
maxRows: undefined,
|
|
9059
|
+
resizable: false
|
|
9000
9060
|
};
|
|
9001
9061
|
Textarea.displayName = 'Textarea';
|
|
9002
9062
|
|