From 620c1bfa05a67e8612b3d62cde688a5fcf55692e Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Thu, 29 Jan 2026 01:14:04 +0900 Subject: [PATCH 01/12] =?UTF-8?q?feat:=20PrezelSnackBar=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 디자인시스템에 커스텀 스낵바 컴포넌트인 `PrezelSnackBar`를 추가했습니다. * `PrezelSnackBar` 및 스타일 정의 (`PrezelSnackBarStyle`) * 아이콘 및 액션 버튼(Action Label) 지원 * 미리보기를 위한 Preview 코드 추가 --- .../designsystem/component/PrezelSnackBar.kt | 192 ++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelSnackBar.kt diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelSnackBar.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelSnackBar.kt new file mode 100644 index 0000000..dff24df --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelSnackBar.kt @@ -0,0 +1,192 @@ +package com.team.prezel.core.designsystem.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.team.prezel.core.designsystem.foundation.typography.PrezelTextStyles +import com.team.prezel.core.designsystem.icon.DrawableIcon +import com.team.prezel.core.designsystem.icon.IconSource +import com.team.prezel.core.designsystem.icon.PrezelIcons +import com.team.prezel.core.designsystem.preview.ThemePreview +import com.team.prezel.core.designsystem.theme.PrezelColorScheme +import com.team.prezel.core.designsystem.theme.PrezelTheme + +@Immutable +data class PrezelSnackBarStyle( + val iconSize: Dp = 20.dp, + val contentPadding: PaddingValues = PaddingValues( + start = 16.dp, + end = 8.dp, + top = 6.dp, + bottom = 6.dp, + ), + val shape: Shape = RoundedCornerShape(12.dp), + val iconMessageSpacing: Dp = 8.dp, + val messageActionSpacing: Dp = 16.dp, + val actionTouchPadding: PaddingValues = PaddingValues(horizontal = 12.dp, vertical = 8.dp), +) + +@Immutable +data class PrezelSnackBarAction( + val label: String, + val onClick: () -> Unit, +) + +@Composable +fun PrezelSnackBar( + message: String, + modifier: Modifier = Modifier, + leadingIcon: IconSource? = null, + action: PrezelSnackBarAction? = null, + style: PrezelSnackBarStyle = PrezelSnackBarStyle(), +) { + Surface( + modifier = modifier, + shape = style.shape, + color = PrezelColorScheme.Dark.bgMedium, + ) { + PrezelSnackBarContent( + message = message, + leadingIcon = leadingIcon, + action = action, + style = style, + ) + } +} + +@Composable +private fun PrezelSnackBarContent( + message: String, + modifier: Modifier = Modifier, + leadingIcon: IconSource? = null, + action: PrezelSnackBarAction?, + style: PrezelSnackBarStyle = PrezelSnackBarStyle(), +) { + Row( + modifier = modifier + .fillMaxWidth() + .padding(style.contentPadding), + verticalAlignment = Alignment.CenterVertically, + ) { + if (leadingIcon != null) { + PrezelSnackBarLeadingIcon(icon = leadingIcon, style = style) + Spacer(Modifier.width(style.iconMessageSpacing)) + } + + Text( + text = message, + modifier = Modifier + .padding(vertical = 8.dp) + .weight(1f), + color = PrezelColorScheme.Dark.textLarge, + overflow = TextOverflow.Ellipsis, + style = PrezelTextStyles.Body3Regular.toTextStyle(), + ) + + action?.let { + Spacer(Modifier.width(style.messageActionSpacing)) + + Text( + text = it.label, + modifier = Modifier + .clickable(role = Role.Button, onClick = it.onClick) + .padding(style.actionTouchPadding), + color = PrezelColorScheme.Dark.interactiveRegular, + maxLines = 1, + style = PrezelTextStyles.Body3Medium.toTextStyle(), + ) + } + } +} + +@Composable +private fun PrezelSnackBarLeadingIcon( + icon: IconSource, + style: PrezelSnackBarStyle, + modifier: Modifier = Modifier, +) { + Icon( + painter = icon.painter(), + contentDescription = icon.contentDescription(), + modifier = modifier.size(style.iconSize), + tint = PrezelColorScheme.Dark.iconLarge, + ) +} + +@ThemePreview +@Composable +private fun PrezelSnackBarPreview() { + PrezelTheme { + Column( + modifier = Modifier + .background(PrezelTheme.colors.bgRegular) + .padding(16.dp), + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + val previewAction = PrezelSnackBarAction( + label = "Action", + onClick = {}, + ) + + Text("SnackBar") + SnackBarPreviewItem( + message = "Message", icon = DrawableIcon(PrezelIcons.Blank), + action = previewAction, + ) + SnackBarPreviewItem( + message = "Message Message Message Message Message", icon = DrawableIcon(PrezelIcons.Blank), + action = previewAction, + ) + SnackBarPreviewItem( + message = "Message", icon = null, + action = previewAction, + ) + SnackBarPreviewItem( + message = "Message Message Message Message Message", icon = null, + action = previewAction, + ) + + Text("Toast") + SnackBarPreviewItem(message = "Message", icon = null) + SnackBarPreviewItem(message = "Message Message Message Message Message Message", icon = null) + SnackBarPreviewItem(message = "Message", icon = DrawableIcon(PrezelIcons.Blank)) + SnackBarPreviewItem(message = "Message Message Message Message Message Message", icon = DrawableIcon(PrezelIcons.Blank)) + } + } +} + + +@Composable +private fun SnackBarPreviewItem( + message: String, + icon: IconSource?, + action: PrezelSnackBarAction? = null, +) { + PrezelSnackBar( + message = message, + leadingIcon = icon, + action = action, + modifier = Modifier.fillMaxWidth(), + ) +} From f20165b0fa46a029aa90625b47c65ddbd67ec5ba Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Thu, 29 Jan 2026 01:18:35 +0900 Subject: [PATCH 02/12] =?UTF-8?q?style:=20PrezelSnackBar=20Preview=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PrezelSnackBar.kt 내 Preview 관련 코드의 가독성을 위해 파라미터 줄바꿈을 적용하고 불필요한 공백을 제거했습니다. --- .../core/designsystem/component/PrezelSnackBar.kt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelSnackBar.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelSnackBar.kt index dff24df..82e65f5 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelSnackBar.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelSnackBar.kt @@ -151,19 +151,23 @@ private fun PrezelSnackBarPreview() { Text("SnackBar") SnackBarPreviewItem( - message = "Message", icon = DrawableIcon(PrezelIcons.Blank), + message = "Message", + icon = DrawableIcon(PrezelIcons.Blank), action = previewAction, ) SnackBarPreviewItem( - message = "Message Message Message Message Message", icon = DrawableIcon(PrezelIcons.Blank), + message = "Message Message Message Message Message", + icon = DrawableIcon(PrezelIcons.Blank), action = previewAction, ) SnackBarPreviewItem( - message = "Message", icon = null, + message = "Message", + icon = null, action = previewAction, ) SnackBarPreviewItem( - message = "Message Message Message Message Message", icon = null, + message = "Message Message Message Message Message", + icon = null, action = previewAction, ) @@ -176,7 +180,6 @@ private fun PrezelSnackBarPreview() { } } - @Composable private fun SnackBarPreviewItem( message: String, From 0e682ecc738c510f30316453e1d64aba3209f777 Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Thu, 29 Jan 2026 02:01:41 +0900 Subject: [PATCH 03/12] =?UTF-8?q?feat:=20PrezelSnackBar=20Preview=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기존 `PrezelSnackBarPreview`를 `PrezelSnackBarAllPreview`로 변경하고, 스낵바와 토스트 프리뷰를 각각 `PrezelSnackbarPreview`와 `PrezelToastPreview`로 분리하여 추가했습니다. --- .../designsystem/component/PrezelSnackBar.kt | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelSnackBar.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelSnackBar.kt index 82e65f5..26c90be 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelSnackBar.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelSnackBar.kt @@ -136,13 +136,27 @@ private fun PrezelSnackBarLeadingIcon( @ThemePreview @Composable -private fun PrezelSnackBarPreview() { +private fun PrezelSnackBarAllPreview() { PrezelTheme { Column( modifier = Modifier .background(PrezelTheme.colors.bgRegular) .padding(16.dp), verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + PrezelSnackbarPreview() + PrezelToastPreview() + } + } +} + +@ThemePreview +@Composable +private fun PrezelSnackbarPreview() { + PrezelTheme { + Column( + modifier = Modifier, + verticalArrangement = Arrangement.spacedBy(12.dp), ) { val previewAction = PrezelSnackBarAction( label = "Action", @@ -170,7 +184,18 @@ private fun PrezelSnackBarPreview() { icon = null, action = previewAction, ) + } + } +} +@ThemePreview +@Composable +private fun PrezelToastPreview() { + PrezelTheme { + Column( + modifier = Modifier, + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { Text("Toast") SnackBarPreviewItem(message = "Message", icon = null) SnackBarPreviewItem(message = "Message Message Message Message Message Message", icon = null) From 0e1dcba34a505003cd1a7ae6bf2af6ae39387f98 Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Thu, 29 Jan 2026 23:44:27 +0900 Subject: [PATCH 04/12] =?UTF-8?q?refactor:=20PrezelSnackbar=20=EA=B0=9C?= =?UTF-8?q?=ED=8E=B8=20=EB=B0=8F=20SnackbarHost=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기존 `PrezelSnackBar.kt`를 `snackbar/PrezelSnackbar.kt`로 이동 및 구조를 변경하고, `SnackbarHostState`와 연동 가능한 컴포넌트들을 추가했습니다. * `PrezelSnackbar`: `SnackbarData`를 직접 받도록 변경하고 `PrezelSnackbarDefaults` 객체를 통해 스타일 상수를 관리하도록 수정 * `PrezelSnackbarHost`: Material3 `SnackbarHost`를 기반으로 하는 커스텀 스낵바 호스트 추가 * `showPrezelSnackbar`: `leadingIcon`을 포함할 수 있는 `SnackbarHostState` 확장 함수 추가 * `PrezelSnackbarVisuals`: 커스텀 아이콘 지원을 위한 `SnackbarVisuals` 인터페이스 구현체 추가 * 기타: 파일 경로 이동 및 미리보기(Preview) 코드 최신화 (Ellipsis 제거 및 최소 높이 설정 등) --- .../designsystem/component/PrezelSnackBar.kt | 220 ------------------ .../component/snackbar/PrezelSnackbar.kt | 197 ++++++++++++++++ .../component/snackbar/SnackbarHost.kt | 54 +++++ 3 files changed, 251 insertions(+), 220 deletions(-) delete mode 100644 Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelSnackBar.kt create mode 100644 Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt create mode 100644 Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelSnackBar.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelSnackBar.kt deleted file mode 100644 index 26c90be..0000000 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/PrezelSnackBar.kt +++ /dev/null @@ -1,220 +0,0 @@ -package com.team.prezel.core.designsystem.component - -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Icon -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.Immutable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Shape -import androidx.compose.ui.semantics.Role -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp -import com.team.prezel.core.designsystem.foundation.typography.PrezelTextStyles -import com.team.prezel.core.designsystem.icon.DrawableIcon -import com.team.prezel.core.designsystem.icon.IconSource -import com.team.prezel.core.designsystem.icon.PrezelIcons -import com.team.prezel.core.designsystem.preview.ThemePreview -import com.team.prezel.core.designsystem.theme.PrezelColorScheme -import com.team.prezel.core.designsystem.theme.PrezelTheme - -@Immutable -data class PrezelSnackBarStyle( - val iconSize: Dp = 20.dp, - val contentPadding: PaddingValues = PaddingValues( - start = 16.dp, - end = 8.dp, - top = 6.dp, - bottom = 6.dp, - ), - val shape: Shape = RoundedCornerShape(12.dp), - val iconMessageSpacing: Dp = 8.dp, - val messageActionSpacing: Dp = 16.dp, - val actionTouchPadding: PaddingValues = PaddingValues(horizontal = 12.dp, vertical = 8.dp), -) - -@Immutable -data class PrezelSnackBarAction( - val label: String, - val onClick: () -> Unit, -) - -@Composable -fun PrezelSnackBar( - message: String, - modifier: Modifier = Modifier, - leadingIcon: IconSource? = null, - action: PrezelSnackBarAction? = null, - style: PrezelSnackBarStyle = PrezelSnackBarStyle(), -) { - Surface( - modifier = modifier, - shape = style.shape, - color = PrezelColorScheme.Dark.bgMedium, - ) { - PrezelSnackBarContent( - message = message, - leadingIcon = leadingIcon, - action = action, - style = style, - ) - } -} - -@Composable -private fun PrezelSnackBarContent( - message: String, - modifier: Modifier = Modifier, - leadingIcon: IconSource? = null, - action: PrezelSnackBarAction?, - style: PrezelSnackBarStyle = PrezelSnackBarStyle(), -) { - Row( - modifier = modifier - .fillMaxWidth() - .padding(style.contentPadding), - verticalAlignment = Alignment.CenterVertically, - ) { - if (leadingIcon != null) { - PrezelSnackBarLeadingIcon(icon = leadingIcon, style = style) - Spacer(Modifier.width(style.iconMessageSpacing)) - } - - Text( - text = message, - modifier = Modifier - .padding(vertical = 8.dp) - .weight(1f), - color = PrezelColorScheme.Dark.textLarge, - overflow = TextOverflow.Ellipsis, - style = PrezelTextStyles.Body3Regular.toTextStyle(), - ) - - action?.let { - Spacer(Modifier.width(style.messageActionSpacing)) - - Text( - text = it.label, - modifier = Modifier - .clickable(role = Role.Button, onClick = it.onClick) - .padding(style.actionTouchPadding), - color = PrezelColorScheme.Dark.interactiveRegular, - maxLines = 1, - style = PrezelTextStyles.Body3Medium.toTextStyle(), - ) - } - } -} - -@Composable -private fun PrezelSnackBarLeadingIcon( - icon: IconSource, - style: PrezelSnackBarStyle, - modifier: Modifier = Modifier, -) { - Icon( - painter = icon.painter(), - contentDescription = icon.contentDescription(), - modifier = modifier.size(style.iconSize), - tint = PrezelColorScheme.Dark.iconLarge, - ) -} - -@ThemePreview -@Composable -private fun PrezelSnackBarAllPreview() { - PrezelTheme { - Column( - modifier = Modifier - .background(PrezelTheme.colors.bgRegular) - .padding(16.dp), - verticalArrangement = Arrangement.spacedBy(12.dp), - ) { - PrezelSnackbarPreview() - PrezelToastPreview() - } - } -} - -@ThemePreview -@Composable -private fun PrezelSnackbarPreview() { - PrezelTheme { - Column( - modifier = Modifier, - verticalArrangement = Arrangement.spacedBy(12.dp), - ) { - val previewAction = PrezelSnackBarAction( - label = "Action", - onClick = {}, - ) - - Text("SnackBar") - SnackBarPreviewItem( - message = "Message", - icon = DrawableIcon(PrezelIcons.Blank), - action = previewAction, - ) - SnackBarPreviewItem( - message = "Message Message Message Message Message", - icon = DrawableIcon(PrezelIcons.Blank), - action = previewAction, - ) - SnackBarPreviewItem( - message = "Message", - icon = null, - action = previewAction, - ) - SnackBarPreviewItem( - message = "Message Message Message Message Message", - icon = null, - action = previewAction, - ) - } - } -} - -@ThemePreview -@Composable -private fun PrezelToastPreview() { - PrezelTheme { - Column( - modifier = Modifier, - verticalArrangement = Arrangement.spacedBy(12.dp), - ) { - Text("Toast") - SnackBarPreviewItem(message = "Message", icon = null) - SnackBarPreviewItem(message = "Message Message Message Message Message Message", icon = null) - SnackBarPreviewItem(message = "Message", icon = DrawableIcon(PrezelIcons.Blank)) - SnackBarPreviewItem(message = "Message Message Message Message Message Message", icon = DrawableIcon(PrezelIcons.Blank)) - } - } -} - -@Composable -private fun SnackBarPreviewItem( - message: String, - icon: IconSource?, - action: PrezelSnackBarAction? = null, -) { - PrezelSnackBar( - message = message, - leadingIcon = icon, - action = action, - modifier = Modifier.fillMaxWidth(), - ) -} diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt new file mode 100644 index 0000000..12e1338 --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt @@ -0,0 +1,197 @@ +package com.team.prezel.core.designsystem.component.snackbar + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.material3.SnackbarData +import androidx.compose.material3.SnackbarDuration +import androidx.compose.material3.SnackbarVisuals +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.unit.dp +import com.team.prezel.core.designsystem.foundation.typography.PrezelTextStyles +import com.team.prezel.core.designsystem.icon.DrawableIcon +import com.team.prezel.core.designsystem.icon.IconSource +import com.team.prezel.core.designsystem.icon.PrezelIcons +import com.team.prezel.core.designsystem.preview.ThemePreview +import com.team.prezel.core.designsystem.theme.PrezelColorScheme +import com.team.prezel.core.designsystem.theme.PrezelTheme + +@Immutable +internal object PrezelSnackbarDefaults { + val IconSize = 20.dp + + val ContentPadding = PaddingValues( + start = 16.dp, + end = 8.dp, + top = 6.dp, + bottom = 6.dp, + ) + + val Shape: Shape = RoundedCornerShape(12.dp) + + val IconMessageSpacing = 8.dp + val MessageActionSpacing = 16.dp + + val ActionTouchPadding = PaddingValues( + horizontal = 12.dp, + vertical = 8.dp, + ) +} + + +@Composable +fun PrezelSnackbar( + data: SnackbarData, + modifier: Modifier = Modifier, + leadingIcon: IconSource? = null, +) { + Surface( + modifier = modifier, + shape = PrezelSnackbarDefaults.Shape, + color = PrezelColorScheme.Dark.bgMedium, + ) { + PrezelSnackbarContent( + data = data, + leadingIcon = leadingIcon, + ) + } +} + +@Composable +fun PrezelSnackbarContent( + data: SnackbarData, + modifier: Modifier = Modifier, + leadingIcon: IconSource? = null, +) { + Row( + modifier = modifier + .fillMaxWidth() + .heightIn(min = 48.dp) + .padding(PrezelSnackbarDefaults.ContentPadding), + verticalAlignment = Alignment.CenterVertically, + ) { + leadingIcon?.let { + PrezelSnackbarLeadingIcon(icon = it) + Spacer(Modifier.width(PrezelSnackbarDefaults.IconMessageSpacing)) + } + + Text( + text = data.visuals.message, + modifier = Modifier + .padding(top = 8.dp, bottom = 8.dp, end = 8.dp) + .weight(1f), + color = PrezelColorScheme.Dark.textLarge, + style = PrezelTextStyles.Body3Regular.toTextStyle(), + ) + + data.visuals.actionLabel?.let { label -> + Spacer(Modifier.width(PrezelSnackbarDefaults.MessageActionSpacing)) + + Text( + text = label, + modifier = Modifier + .clickable(role = Role.Button, onClick = { data.performAction() }) + .padding(PrezelSnackbarDefaults.ActionTouchPadding), + color = PrezelColorScheme.Dark.interactiveRegular, + style = PrezelTextStyles.Body3Medium.toTextStyle(), + ) + } + } +} + +@Composable +private fun PrezelSnackbarLeadingIcon( + icon: IconSource, + modifier: Modifier = Modifier, +) { + Icon( + painter = icon.painter(), + contentDescription = icon.contentDescription(), + modifier = modifier.size(PrezelSnackbarDefaults.IconSize), + tint = PrezelColorScheme.Dark.iconLarge, + ) +} + +@ThemePreview +@Composable +private fun PrezelSnackBarPreview_Cases() { + PrezelTheme { + Column( + modifier = Modifier + .background(PrezelTheme.colors.bgRegular) + .padding(16.dp), + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + Text("Action O / Icon O") + PrezelSnackbar( + data = previewData(message = "Message", actionLabel = "Action"), + leadingIcon = DrawableIcon(PrezelIcons.Blank), + modifier = Modifier.fillMaxWidth(), + ) + + Text("Action O / Icon X") + PrezelSnackbar( + data = previewData(message = "Message Message Message Message Message", actionLabel = "Action"), + leadingIcon = null, + modifier = Modifier.fillMaxWidth(), + ) + + Text("Action X / Icon O") + PrezelSnackbar( + data = previewData(message = "Message", actionLabel = null), + leadingIcon = DrawableIcon(PrezelIcons.Blank), + modifier = Modifier.fillMaxWidth(), + ) + + Text("Action X / Icon X") + PrezelSnackbar( + data = previewData(message = "Message Message Message Message Message", actionLabel = null), + leadingIcon = null, + modifier = Modifier.fillMaxWidth(), + ) + } + } +} + +@Composable +private fun previewData( + message: String, + actionLabel: String?, +): SnackbarData = PreviewSnackbarData( + visuals = PreviewSnackbarVisuals( + message = message, + actionLabel = actionLabel, + ), +) + +private data class PreviewSnackbarVisuals( + override val message: String, + override val actionLabel: String? = null, + override val withDismissAction: Boolean = false, + override val duration: SnackbarDuration = SnackbarDuration.Short, +) : SnackbarVisuals + +private class PreviewSnackbarData( + override val visuals: SnackbarVisuals, +) : SnackbarData { + override fun performAction() {} + override fun dismiss() {} +} diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt new file mode 100644 index 0000000..3a3c54e --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt @@ -0,0 +1,54 @@ +package com.team.prezel.core.designsystem.component.snackbar + +import androidx.compose.material3.SnackbarDuration +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.SnackbarVisuals +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.team.prezel.core.designsystem.icon.IconSource + +data class PrezelSnackbarVisuals( + override val message: String, + override val actionLabel: String?, + override val withDismissAction: Boolean, + override val duration: SnackbarDuration, + val leadingIcon: IconSource?, +) : SnackbarVisuals + +suspend fun SnackbarHostState.showPrezelSnackbar( + message: String, + leadingIcon: IconSource?, + actionLabel: String? = null, + withDismissAction: Boolean = false, + duration: SnackbarDuration = SnackbarDuration.Short, +) { + showSnackbar( + visuals = PrezelSnackbarVisuals( + message = message, + actionLabel = actionLabel, + withDismissAction = withDismissAction, + duration = duration, + leadingIcon = leadingIcon, + ), + ) +} + +@Composable +fun PrezelSnackbarHost( + hostState: SnackbarHostState, + modifier: Modifier = Modifier, +) { + SnackbarHost( + hostState = hostState, + modifier = modifier, + ) { data -> + val visuals = data.visuals + val leadingIcon = (visuals as? PrezelSnackbarVisuals)?.leadingIcon + + PrezelSnackbar( + data = data, + leadingIcon = leadingIcon, + ) + } +} From db516c88f01c2460824fc8615c8e7feb64ec850c Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Thu, 29 Jan 2026 23:46:27 +0900 Subject: [PATCH 05/12] =?UTF-8?q?style:=20PrezelSnackbar=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=ED=8F=AC=EB=A7=B7=ED=8C=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ktlint 적용에 따른 코드 스타일 변경 사항을 반영합니다. * 불필요한 공백 제거 * `previewData` 함수 반환값 줄바꿈 수정 * `PreviewSnackbarData` 클래스 내 메서드 간 공백 추가 --- .../component/snackbar/PrezelSnackbar.kt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt index 12e1338..31cc1b5 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt @@ -56,7 +56,6 @@ internal object PrezelSnackbarDefaults { ) } - @Composable fun PrezelSnackbar( data: SnackbarData, @@ -175,12 +174,13 @@ private fun PrezelSnackBarPreview_Cases() { private fun previewData( message: String, actionLabel: String?, -): SnackbarData = PreviewSnackbarData( - visuals = PreviewSnackbarVisuals( - message = message, - actionLabel = actionLabel, - ), -) +): SnackbarData = + PreviewSnackbarData( + visuals = PreviewSnackbarVisuals( + message = message, + actionLabel = actionLabel, + ), + ) private data class PreviewSnackbarVisuals( override val message: String, @@ -193,5 +193,6 @@ private class PreviewSnackbarData( override val visuals: SnackbarVisuals, ) : SnackbarData { override fun performAction() {} + override fun dismiss() {} } From 534b6a5f818ed07fe41316a8a0435569fe867a0a Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Thu, 29 Jan 2026 23:51:41 +0900 Subject: [PATCH 06/12] =?UTF-8?q?style:=20PrezelSnackbar.kt=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EB=B0=8F=20=EA=B2=BD?= =?UTF-8?q?=EA=B3=A0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * `PreviewSnackbarData` 클래스에 `@Suppress("EmptyFunctionBlock")` 어노테이션 추가 * `SnackbarData` 인터페이스의 메서드 구현 순서 변경 (`dismiss` -> `performAction`) --- .../core/designsystem/component/snackbar/PrezelSnackbar.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt index 31cc1b5..d657c57 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt @@ -189,10 +189,11 @@ private data class PreviewSnackbarVisuals( override val duration: SnackbarDuration = SnackbarDuration.Short, ) : SnackbarVisuals +@Suppress("EmptyFunctionBlock") private class PreviewSnackbarData( override val visuals: SnackbarVisuals, ) : SnackbarData { - override fun performAction() {} - override fun dismiss() {} + + override fun performAction() {} } From 4f1884204e7430bc95ad0a389fa50f73b381607e Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Fri, 30 Jan 2026 13:19:38 +0900 Subject: [PATCH 07/12] =?UTF-8?q?refactor:=20PrezelSnackbar=20=EA=B5=AC?= =?UTF-8?q?=EC=84=B1=20=EC=9A=94=EC=86=8C=20=EB=B0=8F=20SnackbarHost=20?= =?UTF-8?q?=ED=99=95=EC=9E=A5=20=ED=95=A8=EC=88=98=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * `PrezelSnackbar`에서 하드코딩된 스타일 값들을 `PrezelTheme` 시스템(shapes, spacing)을 사용하도록 변경했습니다. * `PrezelSnackbarDefaults` 내 불필요한 상수 및 미사용 import를 제거했습니다. * `showPrezelSnackbar` 확장 함수에 `onAction`, `onDismiss` 콜백 파라미터를 추가하고 결과 처리를 구현했습니다. * `SnackbarVisuals`에서 `leadingIcon`을 추출하는 내부 유틸리티 함수 `leadingIconOrNull()`을 추가했습니다. * 미리보기 코드에 `PreviewScaffold`를 적용하여 구조를 개선했습니다. --- .../component/snackbar/PrezelSnackbar.kt | 30 +++++-------------- .../component/snackbar/SnackbarHost.kt | 19 ++++++++---- 2 files changed, 20 insertions(+), 29 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt index d657c57..362440b 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt @@ -1,9 +1,6 @@ package com.team.prezel.core.designsystem.component.snackbar -import androidx.compose.foundation.background import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -12,7 +9,6 @@ import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon import androidx.compose.material3.SnackbarData import androidx.compose.material3.SnackbarDuration @@ -23,21 +19,19 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Shape import androidx.compose.ui.semantics.Role import androidx.compose.ui.unit.dp import com.team.prezel.core.designsystem.foundation.typography.PrezelTextStyles import com.team.prezel.core.designsystem.icon.DrawableIcon import com.team.prezel.core.designsystem.icon.IconSource import com.team.prezel.core.designsystem.icon.PrezelIcons +import com.team.prezel.core.designsystem.preview.PreviewScaffold import com.team.prezel.core.designsystem.preview.ThemePreview import com.team.prezel.core.designsystem.theme.PrezelColorScheme import com.team.prezel.core.designsystem.theme.PrezelTheme @Immutable internal object PrezelSnackbarDefaults { - val IconSize = 20.dp - val ContentPadding = PaddingValues( start = 16.dp, end = 8.dp, @@ -45,11 +39,6 @@ internal object PrezelSnackbarDefaults { bottom = 6.dp, ) - val Shape: Shape = RoundedCornerShape(12.dp) - - val IconMessageSpacing = 8.dp - val MessageActionSpacing = 16.dp - val ActionTouchPadding = PaddingValues( horizontal = 12.dp, vertical = 8.dp, @@ -64,7 +53,7 @@ fun PrezelSnackbar( ) { Surface( modifier = modifier, - shape = PrezelSnackbarDefaults.Shape, + shape = PrezelTheme.shapes.V12, color = PrezelColorScheme.Dark.bgMedium, ) { PrezelSnackbarContent( @@ -89,20 +78,20 @@ fun PrezelSnackbarContent( ) { leadingIcon?.let { PrezelSnackbarLeadingIcon(icon = it) - Spacer(Modifier.width(PrezelSnackbarDefaults.IconMessageSpacing)) + Spacer(Modifier.width(PrezelTheme.spacing.V8)) } Text( text = data.visuals.message, modifier = Modifier - .padding(top = 8.dp, bottom = 8.dp, end = 8.dp) + .padding(top = PrezelTheme.spacing.V8, bottom = PrezelTheme.spacing.V8, end = PrezelTheme.spacing.V8) .weight(1f), color = PrezelColorScheme.Dark.textLarge, style = PrezelTextStyles.Body3Regular.toTextStyle(), ) data.visuals.actionLabel?.let { label -> - Spacer(Modifier.width(PrezelSnackbarDefaults.MessageActionSpacing)) + Spacer(Modifier.width(PrezelTheme.spacing.V16)) Text( text = label, @@ -124,7 +113,7 @@ private fun PrezelSnackbarLeadingIcon( Icon( painter = icon.painter(), contentDescription = icon.contentDescription(), - modifier = modifier.size(PrezelSnackbarDefaults.IconSize), + modifier = modifier.size(20.dp), tint = PrezelColorScheme.Dark.iconLarge, ) } @@ -133,12 +122,7 @@ private fun PrezelSnackbarLeadingIcon( @Composable private fun PrezelSnackBarPreview_Cases() { PrezelTheme { - Column( - modifier = Modifier - .background(PrezelTheme.colors.bgRegular) - .padding(16.dp), - verticalArrangement = Arrangement.spacedBy(12.dp), - ) { + PreviewScaffold { Text("Action O / Icon O") PrezelSnackbar( data = previewData(message = "Message", actionLabel = "Action"), diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt index 3a3c54e..3ed5b8c 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt @@ -3,6 +3,7 @@ package com.team.prezel.core.designsystem.component.snackbar import androidx.compose.material3.SnackbarDuration import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.SnackbarResult import androidx.compose.material3.SnackbarVisuals import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -18,12 +19,14 @@ data class PrezelSnackbarVisuals( suspend fun SnackbarHostState.showPrezelSnackbar( message: String, - leadingIcon: IconSource?, + leadingIcon: IconSource? = null, actionLabel: String? = null, withDismissAction: Boolean = false, duration: SnackbarDuration = SnackbarDuration.Short, + onAction: (() -> Unit)? = null, + onDismiss: (() -> Unit)? = null, ) { - showSnackbar( + val result = showSnackbar( visuals = PrezelSnackbarVisuals( message = message, actionLabel = actionLabel, @@ -32,6 +35,11 @@ suspend fun SnackbarHostState.showPrezelSnackbar( leadingIcon = leadingIcon, ), ) + + when (result) { + SnackbarResult.ActionPerformed -> onAction?.invoke() + SnackbarResult.Dismissed -> onDismiss?.invoke() + } } @Composable @@ -43,12 +51,11 @@ fun PrezelSnackbarHost( hostState = hostState, modifier = modifier, ) { data -> - val visuals = data.visuals - val leadingIcon = (visuals as? PrezelSnackbarVisuals)?.leadingIcon - PrezelSnackbar( data = data, - leadingIcon = leadingIcon, + leadingIcon = data.visuals.leadingIconOrNull(), ) } } + +internal fun SnackbarVisuals.leadingIconOrNull(): IconSource? = (this as? PrezelSnackbarVisuals)?.leadingIcon From 2db93d36f8a2151c7f9cb882c47fc0327dc62860 Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Fri, 30 Jan 2026 14:33:52 +0900 Subject: [PATCH 08/12] =?UTF-8?q?refactor:=20PrezelSnackbar=20=EA=B5=AC?= =?UTF-8?q?=EC=84=B1=20=EC=9A=94=EC=86=8C=20=EB=B0=8F=20SnackbarHost=20?= =?UTF-8?q?=ED=99=95=EC=9E=A5=20=ED=95=A8=EC=88=98=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * `PrezelSnackbar`에서 하드코딩된 스타일 값들을 `PrezelTheme` 시스템(shapes, spacing)을 사용하도록 변경했습니다. * `PrezelSnackbarDefaults` 내 불필요한 상수 및 미사용 import를 제거했습니다. * `showPrezelSnackbar` 확장 함수에 `onAction`, `onDismiss` 콜백 파라미터를 추가하고 결과 처리를 구현했습니다. * `SnackbarVisuals`에서 `leadingIcon`을 추출하는 내부 유틸리티 함수 `leadingIconOrNull()`을 추가했습니다. * 미리보기 코드에 `PreviewScaffold`를 적용하여 구조를 개선했습니다. --- .../component/snackbar/PrezelSnackbar.kt | 133 ++++++------------ .../component/snackbar/SnackbarHost.kt | 11 +- 2 files changed, 51 insertions(+), 93 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt index 362440b..119b6f7 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt @@ -1,26 +1,23 @@ package com.team.prezel.core.designsystem.component.snackbar -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.heightIn -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material3.Icon +import androidx.compose.material3.Snackbar import androidx.compose.material3.SnackbarData import androidx.compose.material3.SnackbarDuration import androidx.compose.material3.SnackbarVisuals -import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.Immutable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.semantics.Role import androidx.compose.ui.unit.dp +import com.team.prezel.core.designsystem.component.button.PrezelButton +import com.team.prezel.core.designsystem.component.button.PrezelButtonStyle +import com.team.prezel.core.designsystem.component.button.PrezelButtonType import com.team.prezel.core.designsystem.foundation.typography.PrezelTextStyles import com.team.prezel.core.designsystem.icon.DrawableIcon import com.team.prezel.core.designsystem.icon.IconSource @@ -30,76 +27,43 @@ import com.team.prezel.core.designsystem.preview.ThemePreview import com.team.prezel.core.designsystem.theme.PrezelColorScheme import com.team.prezel.core.designsystem.theme.PrezelTheme -@Immutable -internal object PrezelSnackbarDefaults { - val ContentPadding = PaddingValues( - start = 16.dp, - end = 8.dp, - top = 6.dp, - bottom = 6.dp, - ) - - val ActionTouchPadding = PaddingValues( - horizontal = 12.dp, - vertical = 8.dp, - ) -} - @Composable fun PrezelSnackbar( data: SnackbarData, modifier: Modifier = Modifier, - leadingIcon: IconSource? = null, ) { - Surface( + val visuals = data.visuals + val leadingIcon = visuals.leadingIconOrNull() + val actionLabel = visuals.actionLabel + + Snackbar( modifier = modifier, shape = PrezelTheme.shapes.V12, - color = PrezelColorScheme.Dark.bgMedium, + containerColor = PrezelColorScheme.Dark.bgMedium, + contentColor = PrezelColorScheme.Dark.textLarge, + action = actionLabel?.let { label -> + { + PrezelButton( + text = label, + onClick = { data.performAction() }, + style = PrezelButtonStyle(PrezelButtonType.GHOST), + ) + } + }, ) { - PrezelSnackbarContent( - data = data, - leadingIcon = leadingIcon, - ) - } -} - -@Composable -fun PrezelSnackbarContent( - data: SnackbarData, - modifier: Modifier = Modifier, - leadingIcon: IconSource? = null, -) { - Row( - modifier = modifier - .fillMaxWidth() - .heightIn(min = 48.dp) - .padding(PrezelSnackbarDefaults.ContentPadding), - verticalAlignment = Alignment.CenterVertically, - ) { - leadingIcon?.let { - PrezelSnackbarLeadingIcon(icon = it) - Spacer(Modifier.width(PrezelTheme.spacing.V8)) - } - - Text( - text = data.visuals.message, - modifier = Modifier - .padding(top = PrezelTheme.spacing.V8, bottom = PrezelTheme.spacing.V8, end = PrezelTheme.spacing.V8) - .weight(1f), - color = PrezelColorScheme.Dark.textLarge, - style = PrezelTextStyles.Body3Regular.toTextStyle(), - ) - - data.visuals.actionLabel?.let { label -> - Spacer(Modifier.width(PrezelTheme.spacing.V16)) + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + ) { + leadingIcon?.let { + PrezelSnackbarLeadingIcon(icon = it) + Spacer(Modifier.width(PrezelTheme.spacing.V8)) + } Text( - text = label, - modifier = Modifier - .clickable(role = Role.Button, onClick = { data.performAction() }) - .padding(PrezelSnackbarDefaults.ActionTouchPadding), - color = PrezelColorScheme.Dark.interactiveRegular, - style = PrezelTextStyles.Body3Medium.toTextStyle(), + text = visuals.message, + modifier = modifier.weight(1f), + style = PrezelTextStyles.Body3Regular.toTextStyle(), ) } } @@ -125,30 +89,26 @@ private fun PrezelSnackBarPreview_Cases() { PreviewScaffold { Text("Action O / Icon O") PrezelSnackbar( - data = previewData(message = "Message", actionLabel = "Action"), - leadingIcon = DrawableIcon(PrezelIcons.Blank), - modifier = Modifier.fillMaxWidth(), + data = previewData(message = "Message", actionLabel = "Action", leadingIcon = DrawableIcon(PrezelIcons.Blank)), ) - Text("Action O / Icon X") + Text("Action X / Icon O") PrezelSnackbar( - data = previewData(message = "Message Message Message Message Message", actionLabel = "Action"), - leadingIcon = null, - modifier = Modifier.fillMaxWidth(), + data = previewData( + message = "Message Message Message ", + actionLabel = null, + leadingIcon = DrawableIcon(PrezelIcons.Blank), + ), ) - Text("Action X / Icon O") + Text("Action O / Icon X") PrezelSnackbar( - data = previewData(message = "Message", actionLabel = null), - leadingIcon = DrawableIcon(PrezelIcons.Blank), - modifier = Modifier.fillMaxWidth(), + data = previewData(message = "Message Message Message Message Message", actionLabel = "Action"), ) Text("Action X / Icon X") PrezelSnackbar( data = previewData(message = "Message Message Message Message Message", actionLabel = null), - leadingIcon = null, - modifier = Modifier.fillMaxWidth(), ) } } @@ -158,21 +118,18 @@ private fun PrezelSnackBarPreview_Cases() { private fun previewData( message: String, actionLabel: String?, + leadingIcon: IconSource? = null, ): SnackbarData = PreviewSnackbarData( - visuals = PreviewSnackbarVisuals( + visuals = PrezelSnackbarVisuals( message = message, actionLabel = actionLabel, + withDismissAction = false, + duration = SnackbarDuration.Short, + leadingIcon = leadingIcon, ), ) -private data class PreviewSnackbarVisuals( - override val message: String, - override val actionLabel: String? = null, - override val withDismissAction: Boolean = false, - override val duration: SnackbarDuration = SnackbarDuration.Short, -) : SnackbarVisuals - @Suppress("EmptyFunctionBlock") private class PreviewSnackbarData( override val visuals: SnackbarVisuals, diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt index 3ed5b8c..ad50a13 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt @@ -9,7 +9,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.team.prezel.core.designsystem.icon.IconSource -data class PrezelSnackbarVisuals( +internal data class PrezelSnackbarVisuals( override val message: String, override val actionLabel: String?, override val withDismissAction: Boolean, @@ -26,6 +26,10 @@ suspend fun SnackbarHostState.showPrezelSnackbar( onAction: (() -> Unit)? = null, onDismiss: (() -> Unit)? = null, ) { + require((actionLabel == null) == (onAction == null)) { + "actionLabel과 onAction은 둘 다 있거나 둘 다 없어야 합니다." + } + val result = showSnackbar( visuals = PrezelSnackbarVisuals( message = message, @@ -51,10 +55,7 @@ fun PrezelSnackbarHost( hostState = hostState, modifier = modifier, ) { data -> - PrezelSnackbar( - data = data, - leadingIcon = data.visuals.leadingIconOrNull(), - ) + PrezelSnackbar(data = data) } } From 14a69f192bcad6d05b09eabd771ef206ed2996df Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Fri, 30 Jan 2026 15:03:47 +0900 Subject: [PATCH 09/12] =?UTF-8?q?refactor:=20Snackbar=20=EB=82=B4=EB=B6=80?= =?UTF-8?q?=20=EB=B2=84=ED=8A=BC=20=ED=81=AC=EA=B8=B0=20=EC=A1=B0=EC=A0=95?= =?UTF-8?q?=20=EB=B0=8F=20=EA=B4=80=EB=A0=A8=20=ED=99=95=EC=9E=A5=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=9C=84=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `PrezelSnackbar` 내 액션 버튼의 크기를 `SMALL`로 지정하도록 수정했습니다. - `leadingIconOrNull` 확장 함수의 위치를 `SnackbarHost.kt`에서 `PrezelSnackbar.kt`로 이동하고 가시성을 `private`으로 변경했습니다. --- .../core/designsystem/component/snackbar/PrezelSnackbar.kt | 5 ++++- .../core/designsystem/component/snackbar/SnackbarHost.kt | 2 -- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt index 119b6f7..3e4ea25 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt @@ -16,6 +16,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.team.prezel.core.designsystem.component.button.PrezelButton +import com.team.prezel.core.designsystem.component.button.PrezelButtonSize import com.team.prezel.core.designsystem.component.button.PrezelButtonStyle import com.team.prezel.core.designsystem.component.button.PrezelButtonType import com.team.prezel.core.designsystem.foundation.typography.PrezelTextStyles @@ -46,7 +47,7 @@ fun PrezelSnackbar( PrezelButton( text = label, onClick = { data.performAction() }, - style = PrezelButtonStyle(PrezelButtonType.GHOST), + style = PrezelButtonStyle(buttonType = PrezelButtonType.GHOST, buttonSize = PrezelButtonSize.SMALL), ) } }, @@ -82,6 +83,8 @@ private fun PrezelSnackbarLeadingIcon( ) } +private fun SnackbarVisuals.leadingIconOrNull(): IconSource? = (this as? PrezelSnackbarVisuals)?.leadingIcon + @ThemePreview @Composable private fun PrezelSnackBarPreview_Cases() { diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt index ad50a13..1f5eaab 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt @@ -58,5 +58,3 @@ fun PrezelSnackbarHost( PrezelSnackbar(data = data) } } - -internal fun SnackbarVisuals.leadingIconOrNull(): IconSource? = (this as? PrezelSnackbarVisuals)?.leadingIcon From f0c9d91b73c4f0627680af96c06d941fa243b7eb Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Fri, 30 Jan 2026 15:21:31 +0900 Subject: [PATCH 10/12] =?UTF-8?q?fix:=20PrezelSnackbar=20=EB=82=B4=20Modif?= =?UTF-8?q?ier=20=EC=B0=B8=EC=A1=B0=20=EC=98=A4=EB=A5=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PrezelSnackbar 컴포넌트 내 Text의 modifier 설정을 매개변수 `modifier` 대신 `Modifier`를 직접 사용하도록 수정했습니다. --- .../core/designsystem/component/snackbar/PrezelSnackbar.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt index 3e4ea25..b7e14a0 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt @@ -63,7 +63,7 @@ fun PrezelSnackbar( Text( text = visuals.message, - modifier = modifier.weight(1f), + modifier = Modifier.weight(1f), style = PrezelTextStyles.Body3Regular.toTextStyle(), ) } From d8674018ddedbd2ee8de8a94c4477fc9f49410f8 Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Fri, 30 Jan 2026 15:22:44 +0900 Subject: [PATCH 11/12] =?UTF-8?q?chore:=20PrezelSnackbar=20=ED=85=8D?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PrezelSnackbar의 메시지 Text 컴포넌트에서 `Modifier.weight(1f)` 속성을 제거했습니다. --- .../core/designsystem/component/snackbar/PrezelSnackbar.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt index b7e14a0..51d087e 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/PrezelSnackbar.kt @@ -63,7 +63,6 @@ fun PrezelSnackbar( Text( text = visuals.message, - modifier = Modifier.weight(1f), style = PrezelTextStyles.Body3Regular.toTextStyle(), ) } From 1af4cb95bcbe0201c4a14bbe0ef8cc3a64fbed01 Mon Sep 17 00:00:00 2001 From: Ham BeomJoon Date: Fri, 30 Jan 2026 21:28:21 +0900 Subject: [PATCH 12/12] =?UTF-8?q?refactor:=20PrezelSnackbarVisuals=20?= =?UTF-8?q?=EB=82=B4=EB=B6=80=EC=9D=98=20withDismissAction=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `PrezelSnackbarVisuals`의 `withDismissAction` 필드에 기본값을 추가하고, 이를 호출하는 `SnackbarHostState.showSnackbar` 함수에서 중복되는 파라미터를 제거했습니다. --- .../core/designsystem/component/snackbar/SnackbarHost.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt index 1f5eaab..3a9dfc9 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/snackbar/SnackbarHost.kt @@ -12,7 +12,7 @@ import com.team.prezel.core.designsystem.icon.IconSource internal data class PrezelSnackbarVisuals( override val message: String, override val actionLabel: String?, - override val withDismissAction: Boolean, + override val withDismissAction: Boolean = false, override val duration: SnackbarDuration, val leadingIcon: IconSource?, ) : SnackbarVisuals @@ -21,7 +21,6 @@ suspend fun SnackbarHostState.showPrezelSnackbar( message: String, leadingIcon: IconSource? = null, actionLabel: String? = null, - withDismissAction: Boolean = false, duration: SnackbarDuration = SnackbarDuration.Short, onAction: (() -> Unit)? = null, onDismiss: (() -> Unit)? = null, @@ -34,7 +33,6 @@ suspend fun SnackbarHostState.showPrezelSnackbar( visuals = PrezelSnackbarVisuals( message = message, actionLabel = actionLabel, - withDismissAction = withDismissAction, duration = duration, leadingIcon = leadingIcon, ),