Skip to content

Commit 6177ded

Browse files
authored
Merge pull request #113 from YAPP-Github/design/#108-design-system-change
[design] #108 디자인 시스템 변경사항 반영
2 parents c5c9d1c + c52e1a8 commit 6177ded

40 files changed

Lines changed: 1473 additions & 720 deletions

File tree

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
package com.neki.android.core.designsystem
2+
3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.border
5+
import androidx.compose.foundation.interaction.MutableInteractionSource
6+
import androidx.compose.foundation.interaction.collectIsFocusedAsState
7+
import androidx.compose.foundation.layout.Arrangement
8+
import androidx.compose.foundation.layout.Box
9+
import androidx.compose.foundation.layout.Column
10+
import androidx.compose.foundation.layout.Row
11+
import androidx.compose.foundation.layout.Spacer
12+
import androidx.compose.foundation.layout.fillMaxWidth
13+
import androidx.compose.foundation.layout.heightIn
14+
import androidx.compose.foundation.layout.padding
15+
import androidx.compose.foundation.layout.width
16+
import androidx.compose.foundation.shape.RoundedCornerShape
17+
import androidx.compose.foundation.text.BasicTextField
18+
import androidx.compose.foundation.text.KeyboardOptions
19+
import androidx.compose.foundation.text.input.InputTransformation
20+
import androidx.compose.foundation.text.input.OutputTransformation
21+
import androidx.compose.foundation.text.input.TextFieldLineLimits
22+
import androidx.compose.foundation.text.input.TextFieldState
23+
import androidx.compose.material3.Text
24+
import androidx.compose.runtime.Composable
25+
import androidx.compose.runtime.getValue
26+
import androidx.compose.runtime.remember
27+
import androidx.compose.ui.Alignment
28+
import androidx.compose.ui.Modifier
29+
import androidx.compose.ui.graphics.Brush
30+
import androidx.compose.ui.graphics.SolidColor
31+
import androidx.compose.ui.text.TextStyle
32+
import androidx.compose.ui.tooling.preview.Preview
33+
import androidx.compose.ui.unit.dp
34+
import com.neki.android.core.designsystem.ui.theme.NekiTheme
35+
36+
@Composable
37+
fun NekiTextField(
38+
textFieldState: TextFieldState,
39+
modifier: Modifier = Modifier,
40+
titleLabel: String? = null,
41+
placeholder: String = "",
42+
maxLength: Int? = null,
43+
isError: Boolean = false,
44+
textStyle: TextStyle = NekiTheme.typography.body16Medium.copy(
45+
color = NekiTheme.colorScheme.gray900,
46+
),
47+
cursorBrush: Brush = SolidColor(NekiTheme.colorScheme.gray800),
48+
lineLimits: TextFieldLineLimits = TextFieldLineLimits.SingleLine,
49+
inputTransformation: InputTransformation? = null,
50+
outputTransformation: OutputTransformation? = null,
51+
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
52+
) {
53+
val interactionSource = remember { MutableInteractionSource() }
54+
val isFocused by interactionSource.collectIsFocusedAsState()
55+
56+
val borderColor = when {
57+
isError -> NekiTheme.colorScheme.primary600
58+
isFocused -> NekiTheme.colorScheme.gray700
59+
else -> NekiTheme.colorScheme.gray75
60+
}
61+
62+
Column(
63+
modifier = modifier,
64+
verticalArrangement = Arrangement.spacedBy(6.dp),
65+
) {
66+
titleLabel?.let {
67+
Text(
68+
modifier = Modifier
69+
.fillMaxWidth()
70+
.padding(horizontal = 2.dp),
71+
text = it,
72+
style = NekiTheme.typography.body14Medium,
73+
color = NekiTheme.colorScheme.gray700,
74+
)
75+
}
76+
77+
BasicTextField(
78+
state = textFieldState,
79+
modifier = Modifier
80+
.fillMaxWidth()
81+
.background(
82+
color = NekiTheme.colorScheme.white,
83+
shape = RoundedCornerShape(8.dp),
84+
)
85+
.border(
86+
width = 1.dp,
87+
color = borderColor,
88+
shape = RoundedCornerShape(8.dp),
89+
)
90+
.padding(horizontal = 16.dp, vertical = 13.dp),
91+
textStyle = textStyle,
92+
inputTransformation = inputTransformation,
93+
outputTransformation = outputTransformation,
94+
interactionSource = interactionSource,
95+
cursorBrush = cursorBrush,
96+
lineLimits = lineLimits,
97+
keyboardOptions = keyboardOptions,
98+
decorator = { innerTextField ->
99+
Row(
100+
modifier = Modifier.fillMaxWidth(),
101+
horizontalArrangement = Arrangement.SpaceBetween,
102+
verticalAlignment = Alignment.CenterVertically,
103+
) {
104+
Box(modifier = Modifier.weight(1f)) {
105+
if (textFieldState.text.isEmpty()) {
106+
Text(
107+
text = placeholder,
108+
style = NekiTheme.typography.body16Regular,
109+
color = NekiTheme.colorScheme.gray300,
110+
)
111+
}
112+
innerTextField()
113+
}
114+
maxLength?.let {
115+
Spacer(modifier = Modifier.width(4.dp))
116+
Text(
117+
text = "${textFieldState.text.length}/$maxLength",
118+
style = NekiTheme.typography.caption12Regular,
119+
color = NekiTheme.colorScheme.gray300,
120+
)
121+
}
122+
}
123+
},
124+
)
125+
}
126+
}
127+
128+
@Composable
129+
fun NekiTextFieldWithError(
130+
textFieldState: TextFieldState,
131+
modifier: Modifier = Modifier,
132+
titleLabel: String? = null,
133+
placeholder: String = "",
134+
maxLength: Int? = null,
135+
isError: Boolean = false,
136+
errorMessage: String? = null,
137+
textStyle: TextStyle = NekiTheme.typography.body16Medium.copy(
138+
color = NekiTheme.colorScheme.gray900,
139+
),
140+
cursorBrush: Brush = SolidColor(NekiTheme.colorScheme.gray800),
141+
lineLimits: TextFieldLineLimits = TextFieldLineLimits.SingleLine,
142+
inputTransformation: InputTransformation? = null,
143+
outputTransformation: OutputTransformation? = null,
144+
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
145+
) {
146+
Column(
147+
modifier = modifier,
148+
verticalArrangement = Arrangement.spacedBy(6.dp),
149+
) {
150+
NekiTextField(
151+
textFieldState = textFieldState,
152+
titleLabel = titleLabel,
153+
placeholder = placeholder,
154+
maxLength = maxLength,
155+
isError = isError,
156+
textStyle = textStyle,
157+
cursorBrush = cursorBrush,
158+
lineLimits = lineLimits,
159+
inputTransformation = inputTransformation,
160+
outputTransformation = outputTransformation,
161+
keyboardOptions = keyboardOptions,
162+
)
163+
164+
Text(
165+
modifier = Modifier.heightIn(min = 16.dp),
166+
text = if (isError) errorMessage.orEmpty() else "",
167+
style = NekiTheme.typography.caption12Regular,
168+
color = NekiTheme.colorScheme.primary600,
169+
)
170+
}
171+
}
172+
173+
@Preview(showBackground = true)
174+
@Composable
175+
private fun NekiTextFieldPreview() {
176+
NekiTheme {
177+
Column(
178+
modifier = Modifier.padding(16.dp),
179+
verticalArrangement = Arrangement.spacedBy(16.dp),
180+
) {
181+
NekiTextField(
182+
textFieldState = remember { TextFieldState() },
183+
placeholder = "플레이스홀더",
184+
)
185+
186+
NekiTextField(
187+
textFieldState = remember { TextFieldState("입력된 텍스트") },
188+
maxLength = 20,
189+
)
190+
191+
NekiTextField(
192+
textFieldState = remember { TextFieldState("에러 상태") },
193+
isError = true,
194+
)
195+
}
196+
}
197+
}
198+
199+
@Preview(showBackground = true)
200+
@Composable
201+
private fun NekiTextFieldWithTitleLabelPreview() {
202+
NekiTheme {
203+
Column(
204+
modifier = Modifier.padding(16.dp),
205+
verticalArrangement = Arrangement.spacedBy(16.dp),
206+
) {
207+
NekiTextField(
208+
textFieldState = remember { TextFieldState() },
209+
titleLabel = "닉네임",
210+
placeholder = "닉네임을 입력해주세요",
211+
)
212+
213+
NekiTextField(
214+
textFieldState = remember { TextFieldState("입력된 텍스트") },
215+
titleLabel = "닉네임",
216+
maxLength = 10,
217+
)
218+
}
219+
}
220+
}
221+
222+
@Preview(showBackground = true)
223+
@Composable
224+
private fun NekiTextFieldWithErrorPreview() {
225+
NekiTheme {
226+
Column(
227+
modifier = Modifier.padding(16.dp),
228+
verticalArrangement = Arrangement.spacedBy(16.dp),
229+
) {
230+
NekiTextFieldWithError(
231+
textFieldState = remember { TextFieldState() },
232+
placeholder = "플레이스홀더",
233+
)
234+
235+
NekiTextFieldWithError(
236+
textFieldState = remember { TextFieldState("입력된 텍스트") },
237+
placeholder = "플레이스홀더",
238+
)
239+
240+
NekiTextFieldWithError(
241+
textFieldState = remember { TextFieldState("에러 상태") },
242+
isError = true,
243+
errorMessage = "올바른 값을 입력해주세요",
244+
)
245+
}
246+
}
247+
}
248+
249+
@Preview(showBackground = true)
250+
@Composable
251+
private fun NekiTextFieldWithErrorAndTitleLabelPreview() {
252+
NekiTheme {
253+
Column(
254+
modifier = Modifier.padding(16.dp),
255+
verticalArrangement = Arrangement.spacedBy(16.dp),
256+
) {
257+
NekiTextFieldWithError(
258+
textFieldState = remember { TextFieldState() },
259+
titleLabel = "닉네임",
260+
placeholder = "닉네임을 입력해주세요",
261+
maxLength = 10,
262+
)
263+
264+
NekiTextFieldWithError(
265+
textFieldState = remember { TextFieldState("입력된 텍스트") },
266+
placeholder = "플레이스홀더",
267+
maxLength = 10,
268+
)
269+
270+
NekiTextFieldWithError(
271+
textFieldState = remember { TextFieldState("에러 상태") },
272+
titleLabel = "닉네임",
273+
isError = true,
274+
errorMessage = "이미 사용 중인 닉네임입니다",
275+
maxLength = 10,
276+
)
277+
}
278+
}
279+
}

0 commit comments

Comments
 (0)