@lattice-ui/textarea 0.3.2 → 0.4.1
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/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/out/Textarea/TextareaInput.luau +38 -7
- package/out/Textarea/autoResize.d.ts +1 -0
- package/out/Textarea/autoResize.luau +3 -1
- package/package.json +2 -2
- package/src/Textarea/TextareaInput.tsx +46 -3
- package/src/Textarea/autoResize.ts +4 -1
|
@@ -11,15 +11,32 @@ local function toTextBox(instance)
|
|
|
11
11
|
end
|
|
12
12
|
return instance
|
|
13
13
|
end
|
|
14
|
+
local function resolveVerticalPadding(textBox)
|
|
15
|
+
local verticalPadding = 0
|
|
16
|
+
for _, child in textBox:GetChildren() do
|
|
17
|
+
if not child:IsA("UIPadding") then
|
|
18
|
+
continue
|
|
19
|
+
end
|
|
20
|
+
verticalPadding += child.PaddingTop.Offset + child.PaddingBottom.Offset
|
|
21
|
+
verticalPadding += math.floor(child.PaddingTop.Scale * textBox.AbsoluteSize.Y)
|
|
22
|
+
verticalPadding += math.floor(child.PaddingBottom.Scale * textBox.AbsoluteSize.Y)
|
|
23
|
+
end
|
|
24
|
+
return if verticalPadding > 0 then verticalPadding else 14
|
|
25
|
+
end
|
|
26
|
+
local function resolveLineHeight(textBox, explicitLineHeight)
|
|
27
|
+
if explicitLineHeight ~= nil then
|
|
28
|
+
return math.max(1, explicitLineHeight)
|
|
29
|
+
end
|
|
30
|
+
return math.max(1, math.ceil(textBox.TextSize * 1.2))
|
|
31
|
+
end
|
|
32
|
+
local function resolveMeasuredRows(textBox, lineHeight)
|
|
33
|
+
local textBoundsHeight = math.max(lineHeight, textBox.TextBounds.Y)
|
|
34
|
+
return math.max(1, math.ceil(textBoundsHeight / lineHeight))
|
|
35
|
+
end
|
|
14
36
|
local function TextareaInput(props)
|
|
15
37
|
local textareaContext = useTextareaContext()
|
|
16
38
|
local disabled = textareaContext.disabled or props.disabled == true
|
|
17
39
|
local readOnly = textareaContext.readOnly or props.readOnly == true
|
|
18
|
-
local _condition = props.lineHeight
|
|
19
|
-
if _condition == nil then
|
|
20
|
-
_condition = 18
|
|
21
|
-
end
|
|
22
|
-
local lineHeight = _condition
|
|
23
40
|
local setInputRef = React.useCallback(function(instance)
|
|
24
41
|
textareaContext.inputRef.current = toTextBox(instance)
|
|
25
42
|
end, { textareaContext.inputRef })
|
|
@@ -27,17 +44,21 @@ local function TextareaInput(props)
|
|
|
27
44
|
if not textareaContext.autoResize then
|
|
28
45
|
return nil
|
|
29
46
|
end
|
|
47
|
+
local lineHeight = resolveLineHeight(textBox, props.lineHeight)
|
|
48
|
+
local verticalPadding = resolveVerticalPadding(textBox)
|
|
49
|
+
local measuredRows = resolveMeasuredRows(textBox, lineHeight)
|
|
30
50
|
local height = resolveTextareaHeight(textBox.Text, {
|
|
31
51
|
lineHeight = lineHeight,
|
|
32
52
|
minRows = textareaContext.minRows,
|
|
33
53
|
maxRows = textareaContext.maxRows,
|
|
34
|
-
verticalPadding =
|
|
54
|
+
verticalPadding = verticalPadding,
|
|
55
|
+
measuredRows = measuredRows,
|
|
35
56
|
})
|
|
36
57
|
local currentSize = textBox.Size
|
|
37
58
|
if currentSize.Y.Offset ~= height or currentSize.Y.Scale ~= 0 then
|
|
38
59
|
textBox.Size = UDim2.fromOffset(currentSize.X.Offset, height)
|
|
39
60
|
end
|
|
40
|
-
end, { lineHeight, textareaContext.autoResize, textareaContext.maxRows, textareaContext.minRows })
|
|
61
|
+
end, { props.lineHeight, textareaContext.autoResize, textareaContext.maxRows, textareaContext.minRows })
|
|
41
62
|
local handleTextChanged = React.useCallback(function(textBox)
|
|
42
63
|
if disabled or readOnly then
|
|
43
64
|
if textBox.Text ~= textareaContext.value then
|
|
@@ -48,6 +69,11 @@ local function TextareaInput(props)
|
|
|
48
69
|
end
|
|
49
70
|
textareaContext.setValue(textBox.Text)
|
|
50
71
|
applyAutoResize(textBox)
|
|
72
|
+
task.defer(function()
|
|
73
|
+
if textareaContext.inputRef.current == textBox then
|
|
74
|
+
applyAutoResize(textBox)
|
|
75
|
+
end
|
|
76
|
+
end)
|
|
51
77
|
end, { applyAutoResize, disabled, readOnly, textareaContext })
|
|
52
78
|
local handleFocusLost = React.useCallback(function(textBox)
|
|
53
79
|
if disabled then
|
|
@@ -61,6 +87,11 @@ local function TextareaInput(props)
|
|
|
61
87
|
return nil
|
|
62
88
|
end
|
|
63
89
|
applyAutoResize(input)
|
|
90
|
+
task.defer(function()
|
|
91
|
+
if textareaContext.inputRef.current == input then
|
|
92
|
+
applyAutoResize(input)
|
|
93
|
+
end
|
|
94
|
+
end)
|
|
64
95
|
end, { applyAutoResize, textareaContext.inputRef, textareaContext.value })
|
|
65
96
|
local sharedProps = {
|
|
66
97
|
Active = not disabled,
|
|
@@ -14,7 +14,9 @@ local function resolveTextareaHeight(text, options)
|
|
|
14
14
|
_condition = 0
|
|
15
15
|
end
|
|
16
16
|
local verticalPadding = math.max(0, _condition)
|
|
17
|
-
local
|
|
17
|
+
local newlineRows = countLines(text)
|
|
18
|
+
local measuredRows = if options.measuredRows ~= nil then math.max(1, math.floor(options.measuredRows)) else newlineRows
|
|
19
|
+
local naturalRows = math.max(newlineRows, measuredRows)
|
|
18
20
|
local clampedRows = if maxRows ~= nil then math.clamp(naturalRows, minRows, maxRows) else math.max(minRows, naturalRows)
|
|
19
21
|
return clampedRows * lineHeight + verticalPadding
|
|
20
22
|
end
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lattice-ui/textarea",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"main": "out/init.luau",
|
|
6
6
|
"types": "out/index.d.ts",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@lattice-ui/core": "0.
|
|
8
|
+
"@lattice-ui/core": "0.4.1"
|
|
9
9
|
},
|
|
10
10
|
"devDependencies": {
|
|
11
11
|
"@rbxts/react": "17.3.7-ts.1",
|
|
@@ -11,11 +11,39 @@ function toTextBox(instance: Instance | undefined) {
|
|
|
11
11
|
return instance;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
function resolveVerticalPadding(textBox: TextBox) {
|
|
15
|
+
let verticalPadding = 0;
|
|
16
|
+
|
|
17
|
+
for (const child of textBox.GetChildren()) {
|
|
18
|
+
if (!child.IsA("UIPadding")) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
verticalPadding += child.PaddingTop.Offset + child.PaddingBottom.Offset;
|
|
23
|
+
verticalPadding += math.floor(child.PaddingTop.Scale * textBox.AbsoluteSize.Y);
|
|
24
|
+
verticalPadding += math.floor(child.PaddingBottom.Scale * textBox.AbsoluteSize.Y);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return verticalPadding > 0 ? verticalPadding : 14;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function resolveLineHeight(textBox: TextBox, explicitLineHeight: number | undefined) {
|
|
31
|
+
if (explicitLineHeight !== undefined) {
|
|
32
|
+
return math.max(1, explicitLineHeight);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return math.max(1, math.ceil(textBox.TextSize * 1.2));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function resolveMeasuredRows(textBox: TextBox, lineHeight: number) {
|
|
39
|
+
const textBoundsHeight = math.max(lineHeight, textBox.TextBounds.Y);
|
|
40
|
+
return math.max(1, math.ceil(textBoundsHeight / lineHeight));
|
|
41
|
+
}
|
|
42
|
+
|
|
14
43
|
export function TextareaInput(props: TextareaInputProps) {
|
|
15
44
|
const textareaContext = useTextareaContext();
|
|
16
45
|
const disabled = textareaContext.disabled || props.disabled === true;
|
|
17
46
|
const readOnly = textareaContext.readOnly || props.readOnly === true;
|
|
18
|
-
const lineHeight = props.lineHeight ?? 18;
|
|
19
47
|
|
|
20
48
|
const setInputRef = React.useCallback(
|
|
21
49
|
(instance: Instance | undefined) => {
|
|
@@ -30,11 +58,16 @@ export function TextareaInput(props: TextareaInputProps) {
|
|
|
30
58
|
return;
|
|
31
59
|
}
|
|
32
60
|
|
|
61
|
+
const lineHeight = resolveLineHeight(textBox, props.lineHeight);
|
|
62
|
+
const verticalPadding = resolveVerticalPadding(textBox);
|
|
63
|
+
const measuredRows = resolveMeasuredRows(textBox, lineHeight);
|
|
64
|
+
|
|
33
65
|
const height = resolveTextareaHeight(textBox.Text, {
|
|
34
66
|
lineHeight,
|
|
35
67
|
minRows: textareaContext.minRows,
|
|
36
68
|
maxRows: textareaContext.maxRows,
|
|
37
|
-
verticalPadding
|
|
69
|
+
verticalPadding,
|
|
70
|
+
measuredRows,
|
|
38
71
|
});
|
|
39
72
|
|
|
40
73
|
const currentSize = textBox.Size;
|
|
@@ -42,7 +75,7 @@ export function TextareaInput(props: TextareaInputProps) {
|
|
|
42
75
|
textBox.Size = UDim2.fromOffset(currentSize.X.Offset, height);
|
|
43
76
|
}
|
|
44
77
|
},
|
|
45
|
-
[lineHeight, textareaContext.autoResize, textareaContext.maxRows, textareaContext.minRows],
|
|
78
|
+
[props.lineHeight, textareaContext.autoResize, textareaContext.maxRows, textareaContext.minRows],
|
|
46
79
|
);
|
|
47
80
|
|
|
48
81
|
const handleTextChanged = React.useCallback(
|
|
@@ -58,6 +91,11 @@ export function TextareaInput(props: TextareaInputProps) {
|
|
|
58
91
|
|
|
59
92
|
textareaContext.setValue(textBox.Text);
|
|
60
93
|
applyAutoResize(textBox);
|
|
94
|
+
task.defer(() => {
|
|
95
|
+
if (textareaContext.inputRef.current === textBox) {
|
|
96
|
+
applyAutoResize(textBox);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
61
99
|
},
|
|
62
100
|
[applyAutoResize, disabled, readOnly, textareaContext],
|
|
63
101
|
);
|
|
@@ -80,6 +118,11 @@ export function TextareaInput(props: TextareaInputProps) {
|
|
|
80
118
|
}
|
|
81
119
|
|
|
82
120
|
applyAutoResize(input);
|
|
121
|
+
task.defer(() => {
|
|
122
|
+
if (textareaContext.inputRef.current === input) {
|
|
123
|
+
applyAutoResize(input);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
83
126
|
}, [applyAutoResize, textareaContext.inputRef, textareaContext.value]);
|
|
84
127
|
|
|
85
128
|
const sharedProps = {
|
|
@@ -3,6 +3,7 @@ export type TextareaAutoResizeOptions = {
|
|
|
3
3
|
maxRows?: number;
|
|
4
4
|
lineHeight: number;
|
|
5
5
|
verticalPadding?: number;
|
|
6
|
+
measuredRows?: number;
|
|
6
7
|
};
|
|
7
8
|
|
|
8
9
|
function countLines(text: string) {
|
|
@@ -19,7 +20,9 @@ export function resolveTextareaHeight(text: string, options: TextareaAutoResizeO
|
|
|
19
20
|
const lineHeight = math.max(1, options.lineHeight);
|
|
20
21
|
const verticalPadding = math.max(0, options.verticalPadding ?? 0);
|
|
21
22
|
|
|
22
|
-
const
|
|
23
|
+
const newlineRows = countLines(text);
|
|
24
|
+
const measuredRows = options.measuredRows !== undefined ? math.max(1, math.floor(options.measuredRows)) : newlineRows;
|
|
25
|
+
const naturalRows = math.max(newlineRows, measuredRows);
|
|
23
26
|
const clampedRows =
|
|
24
27
|
maxRows !== undefined ? math.clamp(naturalRows, minRows, maxRows) : math.max(minRows, naturalRows);
|
|
25
28
|
|