From c16ff36cfd4a81cdfe7cedc8807f0660dc228f66 Mon Sep 17 00:00:00 2001 From: moondev03 Date: Thu, 7 May 2026 04:24:51 +0900 Subject: [PATCH 01/11] =?UTF-8?q?feat:=20LargeDevicePreview=20=EC=96=B4?= =?UTF-8?q?=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * **feat: 디자인 시스템 내 LargeDevicePreview 어노테이션 정의** * 대화면 기기 환경에서의 UI 구성을 미리 확인하기 위해 가로 1080dp, 세로 1400dp 규격의 `@Preview` 설정을 포함하는 `LargeDevicePreview` 어노테이션을 추가했습니다. * 기본 배경색(흰색) 및 라이트 모드 설정을 포함하여 대형 디바이스 레이아웃 검증에 활용할 수 있도록 했습니다. --- .../team/prezel/core/designsystem/preview/BasicPreview.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/preview/BasicPreview.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/preview/BasicPreview.kt index b1ca96e3..81468700 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/preview/BasicPreview.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/preview/BasicPreview.kt @@ -9,3 +9,11 @@ import androidx.compose.ui.tooling.preview.Preview uiMode = Configuration.UI_MODE_NIGHT_NO, ) annotation class BasicPreview + +@Preview( + showBackground = true, + backgroundColor = 0xFFFFFFFF, + uiMode = Configuration.UI_MODE_NIGHT_NO, + device = "spec:width=1080dp,height=1400dp", +) +annotation class LargeDevicePreview From 8facb7682083f99f48cd7b88a4e2f0e70ded55a5 Mon Sep 17 00:00:00 2001 From: moondev03 Date: Thu, 7 May 2026 05:55:32 +0900 Subject: [PATCH 02/11] =?UTF-8?q?refactor:=20=EB=94=94=EC=9E=90=EC=9D=B8?= =?UTF-8?q?=20=EC=8B=9C=EC=8A=A4=ED=85=9C=20=EC=BB=AC=EB=9F=AC=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../foundation/color/ColorTokens.kt | 70 +++++++++---------- .../foundation/color/PrezelColors.kt | 5 +- .../designsystem/theme/PrezelColorScheme.kt | 28 +++++--- 3 files changed, 59 insertions(+), 44 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/color/ColorTokens.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/color/ColorTokens.kt index 6dac620d..f8cb3e19 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/color/ColorTokens.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/color/ColorTokens.kt @@ -33,17 +33,17 @@ internal object ColorTokens { val Blue950 = Color(0xFF000C40) val Coral10 = Color(0xFFFFF0F0) - val Coral50 = Color(0xFFFFC7C7) - val Coral100 = Color(0xFFFFA3A3) - val Coral200 = Color(0xFFFF8084) - val Coral300 = Color(0xFFFF5C67) - val Coral400 = Color(0xFFFF384C) - val Coral500 = Color(0xFFFF1A38) - val Coral600 = Color(0xFFD90D28) - val Coral700 = Color(0xFFB20528) - val Coral800 = Color(0xFF8C001C) - val Coral900 = Color(0xFF660018) - val Coral950 = Color(0xFF400011) + val Coral50 = Color(0xFFFFD9D9) + val Coral100 = Color(0xFFFFC2C2) + val Coral200 = Color(0xFFFF9E9E) + val Coral300 = Color(0xFFFF7A7A) + val Coral400 = Color(0xFFFF5252) + val Coral500 = Color(0xFFE12D2D) + val Coral600 = Color(0xFFC21A1A) + val Coral700 = Color(0xFFA11010) + val Coral800 = Color(0xFF7D0808) + val Coral900 = Color(0xFF5C0000) + val Coral950 = Color(0xFF3D0000) val Orange10 = Color(0xFFFEF6EA) val Orange50 = Color(0xFFFEE4C1) @@ -58,31 +58,31 @@ internal object ColorTokens { val Orange900 = Color(0xFF661B00) val Orange950 = Color(0xFF400F00) - val Teal10 = Color(0xFFDBFFF6) - val Teal50 = Color(0xFFC2FFF0) - val Teal100 = Color(0xFF8FFFE3) - val Teal200 = Color(0xFF5CFFD6) - val Teal300 = Color(0xFF38F0C2) - val Teal400 = Color(0xFF25D0A5) - val Teal500 = Color(0xFF19B38C) - val Teal600 = Color(0xFF00A37A) - val Teal700 = Color(0xFF008F6B) - val Teal800 = Color(0xFF007A5C) - val Teal900 = Color(0xFF005C45) - val Teal950 = Color(0xFF08352A) + val Teal10 = Color(0xFFE9FBFB) + val Teal50 = Color(0xFFDAF9F8) + val Teal100 = Color(0xFFB6F2F0) + val Teal200 = Color(0xFF88E5E2) + val Teal300 = Color(0xFF5DD5D2) + val Teal400 = Color(0xFF3AC4C1) + val Teal500 = Color(0xFF19B3B0) + val Teal600 = Color(0xFF009B9E) + val Teal700 = Color(0xFF00838A) + val Teal800 = Color(0xFF006973) + val Teal900 = Color(0xFF00515C) + val Teal950 = Color(0xFF082E35) - val Purple10 = Color(0xFFFCF0FF) - val Purple50 = Color(0xFFF2CCFF) - val Purple100 = Color(0xFFE6A8FF) - val Purple200 = Color(0xFFD987FF) - val Purple300 = Color(0xFFC966FF) - val Purple400 = Color(0xFFB845FF) - val Purple500 = Color(0xFFA324FF) - val Purple600 = Color(0xFF9717FF) - val Purple700 = Color(0xFF6109B3) - val Purple800 = Color(0xFF45018C) - val Purple900 = Color(0xFF2E0066) - val Purple950 = Color(0xFF1B0040) + val Purple10 = Color(0xFFF1F0FF) + val Purple50 = Color(0xFFDCD6FF) + val Purple100 = Color(0xFFC1B5FF) + val Purple200 = Color(0xFFA791FF) + val Purple300 = Color(0xFF9170FF) + val Purple400 = Color(0xFF8052FF) + val Purple500 = Color(0xFF6929FF) + val Purple600 = Color(0xFF5514D9) + val Purple700 = Color(0xFF4709B3) + val Purple800 = Color(0xFF39018C) + val Purple900 = Color(0xFF2C0066) + val Purple950 = Color(0xFF1E0040) val Magenta10 = Color(0xFFFFF0F5) val Magenta50 = Color(0xFFFFC7DB) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/color/PrezelColors.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/color/PrezelColors.kt index ca6a9d01..25121276 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/color/PrezelColors.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/color/PrezelColors.kt @@ -15,7 +15,6 @@ data class PrezelColors( val bgRegular: Color, val bgMedium: Color, val bgLarge: Color, - val bgScrim: Color, val bgDisabled: Color, // Text // 정보와 콘텐츠를 명확하게 전달하기 위해 사용하는 색상입니다. @@ -57,4 +56,8 @@ data class PrezelColors( // 흰색과 검정색을 제공하여 시각적 대비, 보조, 구분 등에 활용되는 절대값 색상입니다. val solidWhite: Color, val solidBlack: Color, + // Component + // 컴포넌트를 위한 색상입니다. + val chipContainerSecondaryFilledDefault: Color, + val scrimContainer: Color, ) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelColorScheme.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelColorScheme.kt index 80dfc477..a51e235f 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelColorScheme.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelColorScheme.kt @@ -28,7 +28,6 @@ internal object PrezelColorScheme { bgRegular = ColorTokens.Common0, bgMedium = ColorTokens.CoolGray10, bgLarge = ColorTokens.CoolGray100, - bgScrim = ColorTokens.Common1000.copy(alpha = 0.32f), bgDisabled = ColorTokens.CoolGray50, textSmall = ColorTokens.CoolGray300, textRegular = ColorTokens.CoolGray500, @@ -53,11 +52,13 @@ internal object PrezelColorScheme { accentPurpleSmall = ColorTokens.Purple10, accentPurpleRegular = ColorTokens.Purple500, accentTealSmall = ColorTokens.Teal10, - accentTealRegular = ColorTokens.Teal500, + accentTealRegular = ColorTokens.Teal600, accentMagentaSmall = ColorTokens.Magenta10, accentMagentaRegular = ColorTokens.Magenta500, solidWhite = ColorTokens.Common0, solidBlack = ColorTokens.Common1000, + chipContainerSecondaryFilledDefault = ColorTokens.CoolGray50, + scrimContainer = ColorTokens.Common1000.copy(alpha = 0.32f), ) val Dark = PrezelColors( @@ -67,7 +68,6 @@ internal object PrezelColorScheme { bgRegular = ColorTokens.CoolGray950, bgMedium = ColorTokens.CoolGray900, bgLarge = ColorTokens.CoolGray800, - bgScrim = ColorTokens.Common1000.copy(alpha = 0.32f), bgDisabled = ColorTokens.CoolGray700, textSmall = ColorTokens.CoolGray600, textRegular = ColorTokens.CoolGray400, @@ -86,17 +86,19 @@ internal object PrezelColorScheme { feedbackGoodSmall = ColorTokens.Blue10, feedbackGoodRegular = ColorTokens.Blue500, feedbackBadSmall = ColorTokens.Coral10, - feedbackBadRegular = ColorTokens.Coral600, + feedbackBadRegular = ColorTokens.Coral500, feedbackWarningSmall = ColorTokens.Orange10, feedbackWarningRegular = ColorTokens.Orange500, accentPurpleSmall = ColorTokens.Purple10, accentPurpleRegular = ColorTokens.Purple500, accentTealSmall = ColorTokens.Teal10, - accentTealRegular = ColorTokens.Teal500, + accentTealRegular = ColorTokens.Teal600, accentMagentaSmall = ColorTokens.Magenta10, accentMagentaRegular = ColorTokens.Magenta500, solidWhite = ColorTokens.Common0, solidBlack = ColorTokens.Common1000, + chipContainerSecondaryFilledDefault = ColorTokens.CoolGray50, + scrimContainer = ColorTokens.Common1000.copy(alpha = 0.32f), ) } @@ -124,7 +126,6 @@ private fun PrezelColorSchemeBackgroundPreview() { "Regular" to PrezelColorScheme.Light.bgRegular, "Medium" to PrezelColorScheme.Light.bgMedium, "Large" to PrezelColorScheme.Light.bgLarge, - "Scrim" to PrezelColorScheme.Light.bgScrim, "Disabled" to PrezelColorScheme.Light.bgDisabled, ), ) @@ -204,8 +205,6 @@ private fun PrezelColorSchemeAccentPreview() { "PurpleRegular" to PrezelColorScheme.Light.accentPurpleRegular, "TealSmall" to PrezelColorScheme.Light.accentTealSmall, "TealRegular" to PrezelColorScheme.Light.accentTealRegular, - "MagentaSmall" to PrezelColorScheme.Light.accentMagentaSmall, - "MagentaRegular" to PrezelColorScheme.Light.accentMagentaRegular, ), ) } @@ -223,6 +222,19 @@ private fun PrezelColorSchemeSolidPreview() { ) } +@BasicPreview +@Composable +private fun PrezelColorSchemeComponentPreview() { + PrezelColorsPreviewSection( + title = "Component", + description = "컴포넌트를 위한 색상입니다.", + items = persistentListOf( + "Chip_Container_Secondary_Filled_Default" to PrezelColorScheme.Light.chipContainerSecondaryFilledDefault, + "Scrim_Container" to PrezelColorScheme.Light.scrimContainer, + ), + ) +} + @Composable private fun PrezelColorsPreviewSection( title: String, From 45488a18ba83a304a06cacb604bb10e0fd8a4684 Mon Sep 17 00:00:00 2001 From: moondev03 Date: Thu, 7 May 2026 05:58:31 +0900 Subject: [PATCH 03/11] =?UTF-8?q?refactor:=20PrezelButton=20=ED=94=84?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4?= =?UTF-8?q?=EC=85=98=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * **refactor: 커스텀 프리뷰 어노테이션 `@LargeDevicePreview` 적용** * `PrezelButtonPreview`에서 하드코딩된 디바이스 사양(`spec:width=1080dp...`)을 포함한 `@Preview` 대신, 공통으로 정의된 `@LargeDevicePreview` 커스텀 어노테이션을 사용하도록 변경했습니다. * 불필요해진 기본 `Preview` 임포트를 제거하고 관련 패키지 경로를 업데이트했습니다. --- .../designsystem/component/actions/button/PrezelButton.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/actions/button/PrezelButton.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/actions/button/PrezelButton.kt index 6370c2cb..eda9fb9c 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/actions/button/PrezelButton.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/actions/button/PrezelButton.kt @@ -3,7 +3,6 @@ package com.team.prezel.core.designsystem.component.actions.button import androidx.annotation.DrawableRes import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview import com.team.prezel.core.designsystem.component.actions.button.config.ButtonHierarchy import com.team.prezel.core.designsystem.component.actions.button.config.ButtonSize import com.team.prezel.core.designsystem.component.actions.button.config.ButtonType @@ -13,6 +12,7 @@ import com.team.prezel.core.designsystem.component.actions.button.config.PrezelB import com.team.prezel.core.designsystem.component.actions.button.config.PrezelButtonPreviewContent import com.team.prezel.core.designsystem.component.actions.button.config.previewGhostBorder import com.team.prezel.core.designsystem.icon.PrezelIcons +import com.team.prezel.core.designsystem.preview.LargeDevicePreview /** * 아이콘과 텍스트를 함께 표시할 수 있는 기본 버튼입니다. @@ -46,7 +46,7 @@ fun PrezelButton( ) } -@Preview(device = "spec:width=1080dp,height=1400dp") +@LargeDevicePreview @Composable private fun PrezelButtonPreview() { PrezelButtonPreviewContent(title = "Button/Icon + Text") { type, hierarchy, size, enabled, isRounded -> From 9bf2b6c8ec50f64b87963db5adf340c079fa237a Mon Sep 17 00:00:00 2001 From: moondev03 Date: Fri, 8 May 2026 14:42:24 +0900 Subject: [PATCH 04/11] =?UTF-8?q?feat:=20=EB=94=94=EC=9E=90=EC=9D=B8=20?= =?UTF-8?q?=EC=8B=9C=EC=8A=A4=ED=85=9C=20Preview=EB=A5=BC=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20Matrix=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * **feat: `PreviewMatrix` 컴포넌트 및 관련 데이터 모델 추가** * 디자인 시스템의 다양한 상태나 속성을 격자 형태로 한눈에 비교할 수 있는 `PreviewMatrix` 컴포넌트를 구현했습니다. * 매트릭스 구성을 위한 `PreviewMatrixColumn`, `PreviewMatrixRow`, `PreviewMatrixDefaults` 데이터 클래스를 추가했습니다. * **feat: 매트릭스 레이아웃 및 스타일 구현** * `IntrinsicSize.Min`과 `fillMaxHeight`를 활용하여 동일한 행(Row)에 있는 셀들이 콘텐츠 길이에 상관없이 일정한 높이를 유지하도록 레이아웃을 설계했습니다. * 헤더 셀(`PreviewMatrixHeaderCell`)과 일반 데이터 셀(`PreviewMatrixCell`)의 배경색 및 텍스트 스타일을 분리하여 시각적 구분을 명확히 했습니다. * 사용자 정의 콘텐츠 주입을 위해 `headerCellContent`, `rowLabelContent`, `cellContent` 슬롯을 제공합니다. --- .../designsystem/preview/PreviewComponent.kt | 205 ++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/preview/PreviewComponent.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/preview/PreviewComponent.kt index 9c5cb150..b66903e9 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/preview/PreviewComponent.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/preview/PreviewComponent.kt @@ -1,16 +1,20 @@ package com.team.prezel.core.designsystem.preview import androidx.compose.foundation.background +import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll @@ -22,6 +26,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.team.prezel.core.designsystem.theme.PrezelTheme @@ -36,6 +41,28 @@ internal data class PreviewDefaults( val itemSpacing: Dp = 12.dp, ) +@Immutable +internal data class PreviewMatrixColumn( + val header: String, + val weight: Float = 1f, +) + +@Immutable +internal data class PreviewMatrixRow( + val label: String, + val values: List, + val labelWeight: Float = 1f, +) + +@Immutable +internal data class PreviewMatrixDefaults( + val titleSpacing: Dp = 12.dp, + val headerHorizontalPadding: Dp = 8.dp, + val headerVerticalPadding: Dp = 10.dp, + val cellHorizontalPadding: Dp = 8.dp, + val cellVerticalPadding: Dp = 14.dp, +) + /** * 디자인시스템 Preview의 기본 배경, 패딩, 테마를 제공합니다. * @@ -194,6 +221,184 @@ internal fun PreviewValueRow( } } +@Composable +internal fun PreviewMatrix( + title: String, + columns: List, + rows: List>, + modifier: Modifier = Modifier, + leadingHeaderText: String = "Case", + leadingColumnWeight: Float = 1f, + defaults: PreviewMatrixDefaults = PreviewMatrixDefaults(), + headerCellContent: (@Composable (PreviewMatrixColumn) -> Unit)? = null, + rowLabelContent: (@Composable (PreviewMatrixRow) -> Unit)? = null, + cellContent: @Composable (T) -> Unit, +) { + rows.forEach { row -> + require(row.values.size == columns.size) { + "PreviewMatrix row '${row.label}' has ${row.values.size} values, expected ${columns.size}." + } + } + + Column( + modifier = modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(defaults.titleSpacing), + ) { + Text( + text = title, + style = PrezelTheme.typography.body3Bold, + color = PrezelTheme.colors.textLarge, + ) + + Column( + modifier = Modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(0.dp), + ) { + PreviewMatrixHeaderRow( + leadingHeaderText = leadingHeaderText, + leadingColumnWeight = leadingColumnWeight, + columns = columns, + defaults = defaults, + headerCellContent = headerCellContent, + ) + + rows.forEach { row -> + PreviewMatrixRow( + row = row, + columns = columns, + defaults = defaults, + rowLabelContent = rowLabelContent, + cellContent = cellContent, + ) + } + } + } +} + +@Composable +private fun PreviewMatrixHeaderRow( + leadingHeaderText: String, + leadingColumnWeight: Float, + columns: List, + defaults: PreviewMatrixDefaults, + headerCellContent: (@Composable (PreviewMatrixColumn) -> Unit)?, +) { + Row( + modifier = Modifier.height(IntrinsicSize.Min), + horizontalArrangement = Arrangement.spacedBy(0.dp), + ) { + PreviewMatrixHeaderCell( + modifier = Modifier.weight(leadingColumnWeight), + defaults = defaults, + ) { + Text( + text = leadingHeaderText, + style = PrezelTheme.typography.caption2Regular, + color = PrezelTheme.colors.textMedium, + textAlign = TextAlign.Center, + ) + } + + columns.forEach { column -> + PreviewMatrixHeaderCell( + modifier = Modifier.weight(column.weight), + defaults = defaults, + ) { + if (headerCellContent == null) { + Text( + text = column.header, + style = PrezelTheme.typography.caption2Regular, + color = PrezelTheme.colors.textMedium, + textAlign = TextAlign.Center, + ) + } else { + headerCellContent(column) + } + } + } + } +} + +@Composable +private fun PreviewMatrixRow( + row: PreviewMatrixRow, + columns: List, + defaults: PreviewMatrixDefaults, + rowLabelContent: (@Composable (PreviewMatrixRow) -> Unit)?, + cellContent: @Composable (T) -> Unit, +) { + Row( + modifier = Modifier.height(IntrinsicSize.Min), + horizontalArrangement = Arrangement.spacedBy(0.dp), + ) { + PreviewMatrixCell( + modifier = Modifier.weight(row.labelWeight), + defaults = defaults, + ) { + if (rowLabelContent == null) { + Text( + text = row.label, + style = PrezelTheme.typography.body3Medium, + color = PrezelTheme.colors.textLarge, + textAlign = TextAlign.Center, + ) + } else { + rowLabelContent(row) + } + } + + row.values.forEachIndexed { index, value -> + PreviewMatrixCell( + modifier = Modifier.weight(columns[index].weight), + defaults = defaults, + ) { + cellContent(value) + } + } + } +} + +@Composable +private fun PreviewMatrixHeaderCell( + modifier: Modifier = Modifier, + defaults: PreviewMatrixDefaults, + content: @Composable () -> Unit, +) { + Box( + modifier = modifier + .fillMaxHeight() + .border(width = PrezelTheme.stroke.V1, color = PrezelTheme.colors.borderRegular) + .background(PrezelTheme.colors.bgMedium) + .padding( + horizontal = defaults.headerHorizontalPadding, + vertical = defaults.headerVerticalPadding, + ), + contentAlignment = Alignment.Center, + ) { + content() + } +} + +@Composable +private fun PreviewMatrixCell( + modifier: Modifier = Modifier, + defaults: PreviewMatrixDefaults, + content: @Composable () -> Unit, +) { + Box( + modifier = modifier + .fillMaxHeight() + .border(width = PrezelTheme.stroke.V1, color = PrezelTheme.colors.borderRegular) + .padding( + horizontal = defaults.cellHorizontalPadding, + vertical = defaults.cellVerticalPadding, + ), + contentAlignment = Alignment.Center, + ) { + content() + } +} + /** * TopBar, BottomBar, Snackbar 등 Scaffold 문맥이 필요한 Preview를 위한 래퍼입니다. */ From 488c92f774db7ccb9f4c69ae8323834c594f96c7 Mon Sep 17 00:00:00 2001 From: moondev03 Date: Fri, 8 May 2026 14:45:00 +0900 Subject: [PATCH 05/11] =?UTF-8?q?refactor:=20Chip=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EA=B5=AC=EC=A1=B0=20=EA=B0=9C=EC=84=A0=20?= =?UTF-8?q?=EB=B0=8F=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EC=8B=9C=EC=8A=A4?= =?UTF-8?q?=ED=85=9C=20=EA=B3=A0=EB=8F=84=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * **refactor: Chip 상태 및 스타일 모델 재정의** * `PrezelChipInteraction`을 `PrezelChipState`(Default, Active, Disabled)로, `PrezelChipFeedback`을 `PrezelChipStatus`(Default, Bad, Warning)로 명칭과 역할을 변경했습니다. * 시각적 우선순위를 위한 `PrezelChipHierarchy`와 컬러 강조를 위한 `PrezelChipAccent` 모델을 추가했습니다. * 내부 스타일 구조를 `PrezelChipStyle`과 `PrezelChipColors`로 분리하여 관리 효율성을 높였습니다. * **refactor: `PrezelChip` 및 `PrezelIconChip` API 단순화** * 외부에서 `config` 객체를 직접 생성하던 방식을 제거하고, 상태 기반 파라미터(`state`, `status`, `hierarchy`, `accent`)를 통해 스타일이 결정되도록 수정했습니다. * `PrezelChipDefaults`에 상태별 색상 및 레이아웃 해소(Resolve) 로직을 집중시켜 컴포넌트 가독성을 개선했습니다. * **refactor: Feature 모듈 내 Chip 호출부 리팩터링** * `home` 및 `history` 모듈에서 하드코딩되어 있던 Chip 색상 및 구성 로직을 제거하고, 의미 중심의 상태 파라미터를 사용하도록 업데이트했습니다. * **test: 디자인 시스템 프리뷰 강화** * `PreviewMatrix`를 도입하여 `PrezelChip`과 `PrezelIconChip`의 모든 타입, 크기, 상태 조합을 한눈에 비교할 수 있도록 프리뷰 코드를 재작성했습니다. --- .../designsystem/component/chip/PrezelChip.kt | 233 ++++----- .../component/chip/PrezelIconChip.kt | 195 +++----- .../chip/config/PrezelChipDefaults.kt | 446 ++++++++++++------ .../component/chip/config/PrezelChipLayout.kt | 22 +- .../component/chip/config/PrezelChipModels.kt | 50 +- .../impl/component/HistoryPresentationCard.kt | 17 +- .../impl/component/title/PresentationHero.kt | 10 +- 7 files changed, 540 insertions(+), 433 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/PrezelChip.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/PrezelChip.kt index 3d1db98f..63978bbb 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/PrezelChip.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/PrezelChip.kt @@ -1,24 +1,22 @@ package com.team.prezel.core.designsystem.component.chip import androidx.annotation.DrawableRes -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipDefault +import com.team.prezel.core.designsystem.component.chip.config.PrezelChipAccent import com.team.prezel.core.designsystem.component.chip.config.PrezelChipDefaults -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipFeedback -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipInteraction +import com.team.prezel.core.designsystem.component.chip.config.PrezelChipHierarchy import com.team.prezel.core.designsystem.component.chip.config.PrezelChipLayout import com.team.prezel.core.designsystem.component.chip.config.PrezelChipSize +import com.team.prezel.core.designsystem.component.chip.config.PrezelChipState +import com.team.prezel.core.designsystem.component.chip.config.PrezelChipStatus import com.team.prezel.core.designsystem.component.chip.config.PrezelChipType import com.team.prezel.core.designsystem.icon.PrezelIcons -import com.team.prezel.core.designsystem.preview.BasicPreview -import com.team.prezel.core.designsystem.preview.PreviewRow +import com.team.prezel.core.designsystem.preview.LargeDevicePreview +import com.team.prezel.core.designsystem.preview.PreviewMatrix +import com.team.prezel.core.designsystem.preview.PreviewMatrixColumn +import com.team.prezel.core.designsystem.preview.PreviewMatrixRow import com.team.prezel.core.designsystem.preview.PreviewSection -import com.team.prezel.core.designsystem.preview.PreviewValueRow -import com.team.prezel.core.designsystem.theme.PrezelTheme @Composable fun PrezelChip( @@ -27,143 +25,116 @@ fun PrezelChip( @DrawableRes iconResId: Int? = null, type: PrezelChipType = PrezelChipType.FILLED, size: PrezelChipSize = PrezelChipSize.REGULAR, - interaction: PrezelChipInteraction = PrezelChipInteraction.DEFAULT, - feedback: PrezelChipFeedback = PrezelChipFeedback.DEFAULT, - config: PrezelChipDefault = PrezelChipDefaults.getDefault( - iconOnly = false, - type = type, - size = size, - interaction = interaction, - feedback = feedback, - ), + state: PrezelChipState = PrezelChipState.DEFAULT, + status: PrezelChipStatus = PrezelChipStatus.DEFAULT, + hierarchy: PrezelChipHierarchy = PrezelChipHierarchy.PRIMARY, + accent: PrezelChipAccent = PrezelChipAccent.DEFAULT, ) { PrezelChipLayout( modifier = modifier, text = text, iconResId = iconResId, - config = config, + style = PrezelChipDefaults.chipStyle( + type = type, + size = size, + state = state, + status = status, + hierarchy = hierarchy, + accent = accent, + ), ) } -private class PrezelChipTypeProvider : PreviewParameterProvider { - override val values: Sequence = PrezelChipType.entries.asSequence() -} +private data class ChipPreviewCase( + val type: PrezelChipType, + val size: PrezelChipSize = PrezelChipSize.REGULAR, + val state: PrezelChipState = PrezelChipState.DEFAULT, + val status: PrezelChipStatus = PrezelChipStatus.DEFAULT, + val hierarchy: PrezelChipHierarchy = PrezelChipHierarchy.PRIMARY, + val accent: PrezelChipAccent = PrezelChipAccent.DEFAULT, + val showLeadingIcon: Boolean = true, +) -@BasicPreview -@Composable -private fun PrezelChipPreview( - @PreviewParameter(PrezelChipTypeProvider::class) type: PrezelChipType, -) { - PreviewSection(title = "Chip - $type") { - Text(text = "Size", style = PrezelTheme.typography.title2Medium, color = PrezelTheme.colors.textLarge) - PreviewValueRow(name = "Regular") { - PrezelChip( - text = "Label", - iconResId = PrezelIcons.Blank, - type = type, - size = PrezelChipSize.REGULAR, - ) - } - PreviewValueRow(name = "Small") { - PrezelChip( - text = "Label", - iconResId = PrezelIcons.Blank, - type = type, - size = PrezelChipSize.SMALL, - ) - } +private val chipPreviewColumns = listOf( + PrezelChipSize.SMALL to PrezelChipType.FILLED, + PrezelChipSize.SMALL to PrezelChipType.OUTLINED, + PrezelChipSize.REGULAR to PrezelChipType.FILLED, + PrezelChipSize.REGULAR to PrezelChipType.OUTLINED, +) - Text(text = "Interaction", style = PrezelTheme.typography.title2Medium, color = PrezelTheme.colors.textLarge) - PreviewValueRow(name = "Default") { - PrezelChip( - text = "Label", - iconResId = PrezelIcons.Blank, - type = type, - interaction = PrezelChipInteraction.DEFAULT, - ) - } - PreviewValueRow(name = "Active") { - PrezelChip( - text = "Label", - iconResId = PrezelIcons.Blank, - type = type, - interaction = PrezelChipInteraction.ACTIVE, - ) - } - PreviewValueRow(name = "Disabled") { - PrezelChip( - text = "Label", - iconResId = PrezelIcons.Blank, - type = type, - interaction = PrezelChipInteraction.DISABLED, - ) - } - - Text(text = "Feedback", style = PrezelTheme.typography.title2Medium, color = PrezelTheme.colors.textLarge) - PreviewValueRow(name = "Default") { - PrezelChip( - text = "Label", - iconResId = PrezelIcons.Blank, - type = type, - feedback = PrezelChipFeedback.DEFAULT, - ) - } - PreviewValueRow(name = "Bad") { - PrezelChip( - text = "Label", - iconResId = PrezelIcons.Blank, - type = type, - feedback = PrezelChipFeedback.BAD, - ) - } +private fun previewCases(transform: ChipPreviewCase.() -> ChipPreviewCase = { this }) = + chipPreviewColumns.map { (size, type) -> + ChipPreviewCase(type = type, size = size).transform() } -} -@BasicPreview +@LargeDevicePreview @Composable -private fun PrezelChipCustomPreview( - @PreviewParameter(PrezelChipTypeProvider::class) type: PrezelChipType, -) { - PreviewSection(title = "Custom Chip - $type") { - PreviewRow { - PrezelChip( - text = "Label", - iconResId = PrezelIcons.Blank, - config = PrezelChipDefaults.getDefault( - iconOnly = false, - type = type, - containerColor = PrezelTheme.colors.accentPurpleSmall, - iconColor = PrezelTheme.colors.accentPurpleRegular, - textColor = PrezelTheme.colors.accentPurpleRegular, - borderColor = PrezelTheme.colors.accentPurpleRegular, +private fun PrezelChipPreview() { + PreviewSection( + title = "Chip", + description = "모든 상태를 하나의 표로 비교합니다. 행은 시나리오, 열은 size/type 조합입니다.", + ) { + PreviewMatrix( + title = "Overview", + columns = chipPreviewColumns.map { (size, type) -> + PreviewMatrixColumn( + header = "${size.name.lowercase().replaceFirstChar(Char::uppercase)}\n${type.name.lowercase().replaceFirstChar(Char::uppercase)}", + ) + }, + rows = listOf( + PreviewMatrixRow( + label = "Hierarchy / Primary", + values = previewCases(), ), - ) - - PrezelChip( - text = "Label", - iconResId = PrezelIcons.Blank, - config = PrezelChipDefaults.getDefault( - iconOnly = false, - type = type, - containerColor = PrezelTheme.colors.accentTealSmall, - iconColor = PrezelTheme.colors.accentTealRegular, - textColor = PrezelTheme.colors.accentTealRegular, - borderColor = PrezelTheme.colors.accentTealRegular, + PreviewMatrixRow( + label = "Hierarchy / Secondary", + values = previewCases { copy(hierarchy = PrezelChipHierarchy.SECONDARY) }, ), - ) - - PrezelChip( - text = "Label", - iconResId = PrezelIcons.Blank, - config = PrezelChipDefaults.getDefault( - iconOnly = false, - type = type, - containerColor = PrezelTheme.colors.accentMagentaSmall, - iconColor = PrezelTheme.colors.accentMagentaRegular, - textColor = PrezelTheme.colors.accentMagentaRegular, - borderColor = PrezelTheme.colors.accentMagentaRegular, + PreviewMatrixRow( + label = "State / Active", + values = previewCases { copy(state = PrezelChipState.ACTIVE) }, + ), + PreviewMatrixRow( + label = "Status / Bad", + values = previewCases { copy(status = PrezelChipStatus.BAD) }, + ), + PreviewMatrixRow( + label = "Status / Warning", + values = previewCases { copy(status = PrezelChipStatus.WARNING) }, + ), + PreviewMatrixRow( + label = "Accent / Purple", + values = previewCases { copy(accent = PrezelChipAccent.PURPLE) }, + ), + PreviewMatrixRow( + label = "Accent / Teal", + values = previewCases { copy(accent = PrezelChipAccent.TEAL) }, ), - ) + PreviewMatrixRow( + label = "Leading Icon / Off", + values = previewCases { copy(showLeadingIcon = false) }, + ), + PreviewMatrixRow( + label = "Leading Icon / On", + values = previewCases(), + ), + ), + ) { previewCase -> + PreviewChip(previewCase) } } } + +@Composable +private fun PreviewChip(previewCase: ChipPreviewCase) { + PrezelChip( + text = "Label", + iconResId = if (previewCase.showLeadingIcon) PrezelIcons.Blank else null, + type = previewCase.type, + size = previewCase.size, + state = previewCase.state, + status = previewCase.status, + hierarchy = previewCase.hierarchy, + accent = previewCase.accent, + ) +} diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/PrezelIconChip.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/PrezelIconChip.kt index 368dac74..38603910 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/PrezelIconChip.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/PrezelIconChip.kt @@ -1,24 +1,20 @@ package com.team.prezel.core.designsystem.component.chip import androidx.annotation.DrawableRes -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipDefault import com.team.prezel.core.designsystem.component.chip.config.PrezelChipDefaults -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipFeedback -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipInteraction import com.team.prezel.core.designsystem.component.chip.config.PrezelChipLayout import com.team.prezel.core.designsystem.component.chip.config.PrezelChipSize +import com.team.prezel.core.designsystem.component.chip.config.PrezelChipState +import com.team.prezel.core.designsystem.component.chip.config.PrezelChipStatus import com.team.prezel.core.designsystem.component.chip.config.PrezelChipType import com.team.prezel.core.designsystem.icon.PrezelIcons -import com.team.prezel.core.designsystem.preview.BasicPreview -import com.team.prezel.core.designsystem.preview.PreviewRow +import com.team.prezel.core.designsystem.preview.LargeDevicePreview +import com.team.prezel.core.designsystem.preview.PreviewMatrix +import com.team.prezel.core.designsystem.preview.PreviewMatrixColumn +import com.team.prezel.core.designsystem.preview.PreviewMatrixRow import com.team.prezel.core.designsystem.preview.PreviewSection -import com.team.prezel.core.designsystem.preview.PreviewValueRow -import com.team.prezel.core.designsystem.theme.PrezelTheme @Composable fun PrezelIconChip( @@ -26,133 +22,90 @@ fun PrezelIconChip( modifier: Modifier = Modifier, type: PrezelChipType = PrezelChipType.FILLED, size: PrezelChipSize = PrezelChipSize.REGULAR, - interaction: PrezelChipInteraction = PrezelChipInteraction.DEFAULT, - feedback: PrezelChipFeedback = PrezelChipFeedback.DEFAULT, - config: PrezelChipDefault = PrezelChipDefaults.getDefault( - iconOnly = true, - type = type, - size = size, - interaction = interaction, - feedback = feedback, - ), + state: PrezelChipState = PrezelChipState.DEFAULT, + status: PrezelChipStatus = PrezelChipStatus.DEFAULT, ) { PrezelChipLayout( modifier = modifier, text = null, iconResId = iconResId, - config = config, + style = PrezelChipDefaults.iconChipStyle( + type = type, + size = size, + state = state, + status = status, + ), ) } -private class PrezelIconChipTypeProvider : PreviewParameterProvider { - override val values: Sequence = PrezelChipType.entries.asSequence() -} +private data class IconChipPreviewCase( + val type: PrezelChipType, + val size: PrezelChipSize = PrezelChipSize.REGULAR, + val state: PrezelChipState = PrezelChipState.DEFAULT, + val status: PrezelChipStatus = PrezelChipStatus.DEFAULT, +) -@BasicPreview -@Composable -private fun PrezelChipPreview( - @PreviewParameter(PrezelIconChipTypeProvider::class) type: PrezelChipType, -) { - PreviewSection(title = "Chip - $type") { - Text(text = "Size", style = PrezelTheme.typography.title2Medium, color = PrezelTheme.colors.textLarge) - PreviewValueRow(name = "Regular") { - PrezelIconChip( - iconResId = PrezelIcons.Blank, - type = type, - size = PrezelChipSize.REGULAR, - ) - } - PreviewValueRow(name = "Small") { - PrezelIconChip( - iconResId = PrezelIcons.Blank, - type = type, - size = PrezelChipSize.SMALL, - ) - } +private val iconChipPreviewColumns = listOf( + PrezelChipSize.SMALL to PrezelChipType.FILLED, + PrezelChipSize.SMALL to PrezelChipType.OUTLINED, + PrezelChipSize.REGULAR to PrezelChipType.FILLED, + PrezelChipSize.REGULAR to PrezelChipType.OUTLINED, +) - Text(text = "Interaction", style = PrezelTheme.typography.title2Medium, color = PrezelTheme.colors.textLarge) - PreviewValueRow(name = "Default") { - PrezelIconChip( - iconResId = PrezelIcons.Blank, - type = type, - interaction = PrezelChipInteraction.DEFAULT, - ) - } - PreviewValueRow(name = "Active") { - PrezelIconChip( - iconResId = PrezelIcons.Blank, - type = type, - interaction = PrezelChipInteraction.ACTIVE, - ) - } - PreviewValueRow(name = "Disabled") { - PrezelIconChip( - iconResId = PrezelIcons.Blank, - type = type, - interaction = PrezelChipInteraction.DISABLED, - ) - } - - Text(text = "Feedback", style = PrezelTheme.typography.title2Medium, color = PrezelTheme.colors.textLarge) - PreviewValueRow(name = "Default") { - PrezelIconChip( - iconResId = PrezelIcons.Blank, - type = type, - feedback = PrezelChipFeedback.DEFAULT, - ) - } - PreviewValueRow(name = "Bad") { - PrezelIconChip( - iconResId = PrezelIcons.Blank, - type = type, - feedback = PrezelChipFeedback.BAD, - ) - } +private fun iconPreviewCases(transform: IconChipPreviewCase.() -> IconChipPreviewCase = { this }) = + iconChipPreviewColumns.map { (size, type) -> + IconChipPreviewCase(type = type, size = size).transform() } -} -@BasicPreview +@LargeDevicePreview @Composable -private fun PrezelChipCustomPreview( - @PreviewParameter(PrezelIconChipTypeProvider::class) type: PrezelChipType, -) { - PreviewSection(title = "Custom Chip - $type") { - PreviewRow { - PrezelIconChip( - iconResId = PrezelIcons.Blank, - config = PrezelChipDefaults.getDefault( - iconOnly = true, - type = type, - containerColor = PrezelTheme.colors.accentPurpleSmall, - iconColor = PrezelTheme.colors.accentPurpleRegular, - textColor = PrezelTheme.colors.accentPurpleRegular, - borderColor = PrezelTheme.colors.accentPurpleRegular, +private fun PrezelIconChipPreview() { + PreviewSection( + title = "Icon Chip", + description = "icon-only 케이스를 하나의 표로 비교합니다. 행은 시나리오, 열은 size/type 조합입니다.", + ) { + PreviewMatrix( + title = "Overview", + columns = iconChipPreviewColumns.map { (size, type) -> + PreviewMatrixColumn( + header = "${size.name.lowercase().replaceFirstChar(Char::uppercase)}\n${type.name.lowercase().replaceFirstChar(Char::uppercase)}", + ) + }, + rows = listOf( + PreviewMatrixRow( + label = "Default", + values = iconPreviewCases(), ), - ) - - PrezelIconChip( - iconResId = PrezelIcons.Blank, - config = PrezelChipDefaults.getDefault( - iconOnly = true, - type = type, - containerColor = PrezelTheme.colors.accentTealSmall, - iconColor = PrezelTheme.colors.accentTealRegular, - textColor = PrezelTheme.colors.accentTealRegular, - borderColor = PrezelTheme.colors.accentTealRegular, + PreviewMatrixRow( + label = "State / Active", + values = iconPreviewCases { copy(state = PrezelChipState.ACTIVE) }, ), - ) - - PrezelIconChip( - iconResId = PrezelIcons.Blank, - config = PrezelChipDefaults.getDefault( - iconOnly = true, - type = type, - containerColor = PrezelTheme.colors.accentMagentaSmall, - iconColor = PrezelTheme.colors.accentMagentaRegular, - textColor = PrezelTheme.colors.accentMagentaRegular, - borderColor = PrezelTheme.colors.accentMagentaRegular, + PreviewMatrixRow( + label = "State / Disabled", + values = iconPreviewCases { copy(state = PrezelChipState.DISABLED) }, + ), + PreviewMatrixRow( + label = "Status / Bad", + values = iconPreviewCases { copy(status = PrezelChipStatus.BAD) }, ), - ) + PreviewMatrixRow( + label = "Status / Warning", + values = iconPreviewCases { copy(status = PrezelChipStatus.WARNING) }, + ), + ), + ) { previewCase -> + PreviewIconChip(previewCase) } } } + +@Composable +private fun PreviewIconChip(previewCase: IconChipPreviewCase) { + PrezelIconChip( + iconResId = PrezelIcons.Blank, + type = previewCase.type, + size = previewCase.size, + state = previewCase.state, + status = previewCase.status, + ) +} diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipDefaults.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipDefaults.kt index c839bbef..0f427218 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipDefaults.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipDefaults.kt @@ -11,13 +11,18 @@ import androidx.compose.ui.unit.dp import com.team.prezel.core.designsystem.theme.PrezelTheme @Immutable -data class PrezelChipDefault( - val shape: Shape, - val textStyle: TextStyle, +internal data class PrezelChipColors( val containerColor: Color, val iconColor: Color, val textColor: Color, val borderColor: Color?, +) + +@Immutable +internal data class PrezelChipStyle( + val shape: Shape, + val textStyle: TextStyle, + val colors: PrezelChipColors, val contentPadding: PaddingValues, val iconTextSpacing: Dp, val iconSize: Dp, @@ -25,176 +30,349 @@ data class PrezelChipDefault( object PrezelChipDefaults { @Composable - fun getDefault( - iconOnly: Boolean, - type: PrezelChipType = PrezelChipType.FILLED, - size: PrezelChipSize = PrezelChipSize.REGULAR, - interaction: PrezelChipInteraction = PrezelChipInteraction.DEFAULT, - feedback: PrezelChipFeedback = PrezelChipFeedback.DEFAULT, - shape: Shape = getShape(size = size), - textStyle: TextStyle = getTextStyle(size = size), - containerColor: Color = getContainerColor( - iconOnly = iconOnly, - type = type, - interaction = interaction, - feedback = feedback, - ), - iconColor: Color = getIconColor( - type = type, - interaction = interaction, - feedback = feedback, - ), - textColor: Color = getTextColor( - type = type, - interaction = interaction, - feedback = feedback, - ), - borderColor: Color? = getBorderColor( + internal fun chipStyle( + type: PrezelChipType, + size: PrezelChipSize, + state: PrezelChipState, + status: PrezelChipStatus, + hierarchy: PrezelChipHierarchy, + accent: PrezelChipAccent, + ): PrezelChipStyle = + PrezelChipStyle( + shape = shape(size = size), + textStyle = textStyle(size = size), + colors = chipColors( + type = type, + state = normalizeChipState(state), + status = status, + hierarchy = hierarchy, + accent = accent, + ), + contentPadding = contentPadding(size = size), + iconTextSpacing = iconTextSpacing(size = size), + iconSize = chipIconSize(size = size), + ) + + @Composable + internal fun iconChipStyle( + type: PrezelChipType, + size: PrezelChipSize, + state: PrezelChipState, + status: PrezelChipStatus, + ): PrezelChipStyle = + PrezelChipStyle( + shape = shape(size = size), + textStyle = textStyle(size = size), + colors = iconChipColors(type = type, state = state, status = status), + contentPadding = iconContentPadding(size = size), + iconTextSpacing = 0.dp, + iconSize = iconChipIconSize(size = size), + ) + + @Composable + private fun chipColors( + type: PrezelChipType, + state: PrezelChipState, + status: PrezelChipStatus, + hierarchy: PrezelChipHierarchy, + accent: PrezelChipAccent, + ): PrezelChipColors { + val contentAccentColor = resolveContentAccent(status = status, accent = accent) + val usesDefaultHierarchyStyle = usesHierarchyDefaultStyle( + state = state, + status = status, + accent = accent, + ) + + return PrezelChipColors( + containerColor = resolveChipContainerColor( + type = type, + state = state, + status = status, + hierarchy = hierarchy, + accent = accent, + ), + iconColor = resolveChipIconColor( + type = type, + state = state, + hierarchy = hierarchy, + contentAccentColor = contentAccentColor, + usesDefaultHierarchyStyle = usesDefaultHierarchyStyle, + ), + textColor = resolveChipTextColor( + type = type, + state = state, + hierarchy = hierarchy, + contentAccentColor = contentAccentColor, + usesDefaultHierarchyStyle = usesDefaultHierarchyStyle, + ), + borderColor = resolveOutlinedBorderColor( + type = type, + color = resolveChipBorderColor( + state = state, + hierarchy = hierarchy, + contentAccentColor = contentAccentColor, + ), + ), + ) + } + + @Composable + private fun iconChipColors( + type: PrezelChipType, + state: PrezelChipState, + status: PrezelChipStatus, + ): PrezelChipColors { + val contentAccentColor = resolveContentAccent( + status = status, + accent = PrezelChipAccent.DEFAULT, + ) + val iconColor = resolveIconChipContentColor( type = type, - interaction = interaction, - feedback = feedback, - ), - contentPadding: PaddingValues = getContentPadding(size = size, iconOnly = iconOnly), - iconTextSpacing: Dp = getIconTextSpacing(size = size), - iconSize: Dp = getIconSize(size = size), - ) = PrezelChipDefault( - shape = shape, - textStyle = textStyle, - containerColor = containerColor, - iconColor = iconColor, - textColor = textColor, - borderColor = if (type == PrezelChipType.OUTLINED) borderColor else null, - contentPadding = contentPadding, - iconTextSpacing = iconTextSpacing, - iconSize = iconSize, - ) - - @Composable - private fun getShape(size: PrezelChipSize): Shape = + state = state, + contentAccentColor = contentAccentColor, + ) + + return PrezelChipColors( + containerColor = resolveIconChipContainerColor( + type = type, + state = state, + status = status, + ), + iconColor = iconColor, + textColor = iconColor, + borderColor = resolveOutlinedBorderColor( + type = type, + color = resolveIconChipBorderColor( + state = state, + contentAccentColor = contentAccentColor, + ), + ), + ) + } + + @Composable + private fun shape(size: PrezelChipSize): Shape = when (size) { PrezelChipSize.SMALL -> PrezelTheme.shapes.V4 PrezelChipSize.REGULAR -> PrezelTheme.shapes.V8 } @Composable - private fun getBorderColor( - type: PrezelChipType, - interaction: PrezelChipInteraction, - feedback: PrezelChipFeedback, - ): Color? { - if (type == PrezelChipType.FILLED) return null + private fun textStyle(size: PrezelChipSize): TextStyle = + when (size) { + PrezelChipSize.SMALL -> PrezelTheme.typography.caption2Regular + PrezelChipSize.REGULAR -> PrezelTheme.typography.caption1Regular + } + + @Composable + private fun contentPadding(size: PrezelChipSize): PaddingValues { + val horizontal = when (size) { + PrezelChipSize.SMALL -> PrezelTheme.spacing.V6 + PrezelChipSize.REGULAR -> PrezelTheme.spacing.V8 + } + + val vertical = when (size) { + PrezelChipSize.SMALL -> PrezelTheme.spacing.V4 + PrezelChipSize.REGULAR -> PrezelTheme.spacing.V6 + } + + return PaddingValues(horizontal = horizontal, vertical = vertical) + } - return when { - feedback == PrezelChipFeedback.BAD -> PrezelTheme.colors.feedbackBadRegular - interaction == PrezelChipInteraction.ACTIVE -> PrezelTheme.colors.interactiveRegular - interaction == PrezelChipInteraction.DISABLED -> PrezelTheme.colors.borderRegular - else -> PrezelTheme.colors.borderMedium + @Composable + private fun iconContentPadding(size: PrezelChipSize): PaddingValues { + val all = when (size) { + PrezelChipSize.SMALL -> PrezelTheme.spacing.V6 + PrezelChipSize.REGULAR -> PrezelTheme.spacing.V8 } + + return PaddingValues(all = all) } @Composable - private fun getTextStyle(size: PrezelChipSize): TextStyle = + private fun iconTextSpacing(size: PrezelChipSize): Dp = when (size) { - PrezelChipSize.SMALL -> PrezelTheme.typography.caption2Regular - PrezelChipSize.REGULAR -> PrezelTheme.typography.caption1Regular + PrezelChipSize.SMALL -> PrezelTheme.spacing.V2 + PrezelChipSize.REGULAR -> PrezelTheme.spacing.V4 } + private fun chipIconSize(size: PrezelChipSize): Dp = + when (size) { + PrezelChipSize.SMALL -> 14.dp + PrezelChipSize.REGULAR -> 16.dp + } + + private fun iconChipIconSize(size: PrezelChipSize): Dp = + when (size) { + PrezelChipSize.SMALL -> 12.dp + PrezelChipSize.REGULAR -> 14.dp + } + + @Composable + private fun resolveChipBorderColor( + state: PrezelChipState, + hierarchy: PrezelChipHierarchy, + contentAccentColor: Color?, + ): Color { + if (contentAccentColor != null) return contentAccentColor + if (state == PrezelChipState.ACTIVE) return PrezelTheme.colors.interactiveRegular + + return when (hierarchy) { + PrezelChipHierarchy.PRIMARY -> PrezelTheme.colors.borderMedium + PrezelChipHierarchy.SECONDARY -> PrezelTheme.colors.borderRegular + } + } + @Composable - private fun getContainerColor( - iconOnly: Boolean, + private fun resolveChipContainerColor( type: PrezelChipType, - interaction: PrezelChipInteraction, - feedback: PrezelChipFeedback, + state: PrezelChipState, + status: PrezelChipStatus, + hierarchy: PrezelChipHierarchy, + accent: PrezelChipAccent, ): Color { - if (type == PrezelChipType.OUTLINED && iconOnly) { - return Color.Transparent - } - - return when { - feedback == PrezelChipFeedback.BAD -> PrezelTheme.colors.feedbackBadSmall - interaction == PrezelChipInteraction.ACTIVE -> PrezelTheme.colors.interactiveXSmall - interaction == PrezelChipInteraction.DISABLED -> PrezelTheme.colors.bgDisabled - else -> { - when (type) { - PrezelChipType.FILLED -> PrezelTheme.colors.bgLarge - PrezelChipType.OUTLINED -> PrezelTheme.colors.bgRegular - } - } + val containerAccentColor = resolveContainerAccent(status = status, accent = accent) + if (containerAccentColor != null) return containerAccentColor + + if (state == PrezelChipState.ACTIVE) return PrezelTheme.colors.interactiveXSmall + if (type == PrezelChipType.OUTLINED) return PrezelTheme.colors.bgRegular + if (!usesHierarchyDefaultStyle(state = state, status = status, accent = accent)) { + return PrezelTheme.colors.bgLarge + } + + return when (hierarchy) { + PrezelChipHierarchy.PRIMARY -> PrezelTheme.colors.bgLarge + PrezelChipHierarchy.SECONDARY -> PrezelTheme.colors.chipContainerSecondaryFilledDefault } } @Composable - private fun getIconColor( + private fun resolveChipIconColor( type: PrezelChipType, - interaction: PrezelChipInteraction, - feedback: PrezelChipFeedback, - ): Color = - when { - feedback == PrezelChipFeedback.BAD -> PrezelTheme.colors.feedbackBadRegular - interaction == PrezelChipInteraction.ACTIVE -> PrezelTheme.colors.interactiveRegular - interaction == PrezelChipInteraction.DISABLED -> PrezelTheme.colors.iconDisabled - else -> { - when (type) { - PrezelChipType.FILLED -> PrezelTheme.colors.iconMedium - PrezelChipType.OUTLINED -> PrezelTheme.colors.iconRegular - } - } + state: PrezelChipState, + hierarchy: PrezelChipHierarchy, + contentAccentColor: Color?, + usesDefaultHierarchyStyle: Boolean, + ): Color { + if (contentAccentColor != null) return contentAccentColor + if (state == PrezelChipState.ACTIVE) return PrezelTheme.colors.interactiveRegular + if (type == PrezelChipType.FILLED && usesDefaultHierarchyStyle && hierarchy == PrezelChipHierarchy.PRIMARY) { + return PrezelTheme.colors.iconMedium } + return PrezelTheme.colors.iconRegular + } + @Composable - private fun getTextColor( + private fun resolveChipTextColor( type: PrezelChipType, - interaction: PrezelChipInteraction, - feedback: PrezelChipFeedback, - ): Color = - when { - feedback == PrezelChipFeedback.BAD -> PrezelTheme.colors.feedbackBadRegular - interaction == PrezelChipInteraction.ACTIVE -> PrezelTheme.colors.interactiveRegular - interaction == PrezelChipInteraction.DISABLED -> PrezelTheme.colors.textDisabled - else -> { - when (type) { - PrezelChipType.FILLED -> PrezelTheme.colors.textMedium - PrezelChipType.OUTLINED -> PrezelTheme.colors.textRegular - } - } + state: PrezelChipState, + hierarchy: PrezelChipHierarchy, + contentAccentColor: Color?, + usesDefaultHierarchyStyle: Boolean, + ): Color { + if (contentAccentColor != null) return contentAccentColor + if (state == PrezelChipState.ACTIVE) return PrezelTheme.colors.interactiveRegular + if (type == PrezelChipType.FILLED && usesDefaultHierarchyStyle && hierarchy == PrezelChipHierarchy.PRIMARY) { + return PrezelTheme.colors.textMedium } + return PrezelTheme.colors.textRegular + } + + private fun usesHierarchyDefaultStyle( + state: PrezelChipState, + status: PrezelChipStatus, + accent: PrezelChipAccent, + ): Boolean = state == PrezelChipState.DEFAULT && status == PrezelChipStatus.DEFAULT && accent == PrezelChipAccent.DEFAULT + @Composable - private fun getContentPadding( - size: PrezelChipSize, - iconOnly: Boolean, - ): PaddingValues { - if (iconOnly) { - val all = when (size) { - PrezelChipSize.SMALL -> PrezelTheme.spacing.V6 - PrezelChipSize.REGULAR -> PrezelTheme.spacing.V8 + private fun resolveIconChipContainerColor( + type: PrezelChipType, + state: PrezelChipState, + status: PrezelChipStatus, + ): Color { + if (type == PrezelChipType.OUTLINED) return Color.Transparent + + return when (state) { + PrezelChipState.DISABLED -> PrezelTheme.colors.bgMedium + PrezelChipState.ACTIVE -> PrezelTheme.colors.interactiveXSmall + PrezelChipState.DEFAULT -> { + when (status) { + PrezelChipStatus.DEFAULT -> PrezelTheme.colors.bgLarge + PrezelChipStatus.BAD -> PrezelTheme.colors.feedbackBadSmall + PrezelChipStatus.WARNING -> PrezelTheme.colors.feedbackWarningSmall + } } - return PaddingValues(all = all) } + } - val horizontal = when (size) { - PrezelChipSize.SMALL -> PrezelTheme.spacing.V6 - PrezelChipSize.REGULAR -> PrezelTheme.spacing.V8 - } + @Composable + private fun resolveIconChipContentColor( + type: PrezelChipType, + state: PrezelChipState, + contentAccentColor: Color?, + ): Color { + if (state == PrezelChipState.DISABLED) return PrezelTheme.colors.iconDisabled + if (contentAccentColor != null) return contentAccentColor + if (state == PrezelChipState.ACTIVE) return PrezelTheme.colors.interactiveRegular + if (type == PrezelChipType.FILLED) return PrezelTheme.colors.iconMedium - val vertical = when (size) { - PrezelChipSize.SMALL -> PrezelTheme.spacing.V4 - PrezelChipSize.REGULAR -> PrezelTheme.spacing.V6 - } + return PrezelTheme.colors.iconRegular + } - return PaddingValues(horizontal = horizontal, vertical = vertical) + @Composable + private fun resolveIconChipBorderColor( + state: PrezelChipState, + contentAccentColor: Color?, + ): Color { + if (state == PrezelChipState.DISABLED) return PrezelTheme.colors.borderRegular + if (contentAccentColor != null) return contentAccentColor + if (state == PrezelChipState.ACTIVE) return PrezelTheme.colors.interactiveRegular + + return PrezelTheme.colors.borderMedium } + private fun normalizeChipState(state: PrezelChipState): PrezelChipState = + if (state == PrezelChipState.DISABLED) PrezelChipState.DEFAULT else state + + private fun resolveOutlinedBorderColor( + type: PrezelChipType, + color: Color, + ): Color? = if (type == PrezelChipType.OUTLINED) color else null + @Composable - private fun getIconTextSpacing(size: PrezelChipSize): Dp = - when (size) { - PrezelChipSize.REGULAR -> PrezelTheme.spacing.V4 - PrezelChipSize.SMALL -> PrezelTheme.spacing.V2 + private fun resolveContainerAccent( + status: PrezelChipStatus, + accent: PrezelChipAccent, + ): Color? = + when (accent) { + PrezelChipAccent.PURPLE -> PrezelTheme.colors.accentPurpleSmall + PrezelChipAccent.TEAL -> PrezelTheme.colors.accentTealSmall + PrezelChipAccent.DEFAULT -> { + when (status) { + PrezelChipStatus.DEFAULT -> null + PrezelChipStatus.BAD -> PrezelTheme.colors.feedbackBadSmall + PrezelChipStatus.WARNING -> PrezelTheme.colors.feedbackWarningSmall + } + } } - private fun getIconSize(size: PrezelChipSize): Dp = - when (size) { - PrezelChipSize.SMALL -> 14.dp - PrezelChipSize.REGULAR -> 16.dp + @Composable + private fun resolveContentAccent( + status: PrezelChipStatus, + accent: PrezelChipAccent, + ): Color? = + when (accent) { + PrezelChipAccent.PURPLE -> PrezelTheme.colors.accentPurpleRegular + PrezelChipAccent.TEAL -> PrezelTheme.colors.accentTealRegular + PrezelChipAccent.DEFAULT -> { + when (status) { + PrezelChipStatus.DEFAULT -> null + PrezelChipStatus.BAD -> PrezelTheme.colors.feedbackBadRegular + PrezelChipStatus.WARNING -> PrezelTheme.colors.feedbackWarningRegular + } + } } } diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipLayout.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipLayout.kt index 1bfbb4d6..9512bf22 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipLayout.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipLayout.kt @@ -24,39 +24,37 @@ internal fun PrezelChipLayout( modifier: Modifier = Modifier, text: String?, @DrawableRes iconResId: Int?, - config: PrezelChipDefault, + style: PrezelChipStyle, ) { require(text != null || iconResId != null) { "Chip은 text 또는 icon 중 하나는 반드시 필요합니다." } Surface( modifier = modifier, - shape = config.shape, - color = config.containerColor, - border = config.borderColor?.let { color -> + shape = style.shape, + color = style.colors.containerColor, + border = style.colors.borderColor?.let { color -> BorderStroke(width = PrezelTheme.stroke.V1, color = color) }, ) { Row( - modifier = Modifier.padding(config.contentPadding), + modifier = Modifier.padding(style.contentPadding), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically, ) { iconResId?.let { resId -> PrezelChipIcon( iconResId = resId, - iconSize = config.iconSize, - tint = config.iconColor, + iconSize = style.iconSize, + tint = style.colors.iconColor, ) } if (text != null) { - if (iconResId != null) { - Spacer(modifier = Modifier.width(config.iconTextSpacing)) - } + if (iconResId != null) Spacer(modifier = Modifier.width(style.iconTextSpacing)) Text( text = text, - color = config.textColor, - style = config.textStyle, + color = style.colors.textColor, + style = style.textStyle, ) } } diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipModels.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipModels.kt index 7f150a8b..5dbd787e 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipModels.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipModels.kt @@ -9,10 +9,7 @@ import androidx.compose.runtime.Immutable */ @Immutable enum class PrezelChipType { - /** 배경이 채워진 칩입니다. */ FILLED, - - /** 테두리가 있는 칩입니다. */ OUTLINED, } @@ -23,40 +20,53 @@ enum class PrezelChipType { */ @Immutable enum class PrezelChipSize { - /** 작은 크기의 칩입니다. */ SMALL, - - /** 기본 크기의 칩입니다. */ REGULAR, } /** - * 칩의 상호작용 상태를 정의합니다. + * 칩의 시각 상태를 정의합니다. * - * 선택 여부나 비활성 상태에 따라 칩의 강조 수준을 표현할 때 사용합니다. + * 기본, 강조, 비활성 상태에 따라 칩의 강조 수준을 표현할 때 사용합니다. */ @Immutable -enum class PrezelChipInteraction { - /** 기본 상태의 칩입니다. */ +enum class PrezelChipState { DEFAULT, - - /** 활성화되어 강조된 상태의 칩입니다. */ ACTIVE, - - /** 비활성화된 상태의 칩입니다. */ DISABLED, } /** - * 칩의 피드백 상태를 정의합니다. + * 칩의 의미 상태를 정의합니다. * - * 일반 상태 외에 경고성 의미를 함께 전달해야 할 때 사용합니다. + * 일반 상태 외에 부정/경고 의미를 함께 전달해야 할 때 사용합니다. */ @Immutable -enum class PrezelChipFeedback { - /** 일반 상태의 칩입니다. */ +enum class PrezelChipStatus { DEFAULT, - - /** 부정적 피드백을 표현하는 칩입니다. */ BAD, + WARNING, +} + +/** + * 일반 칩의 시각적 계층을 정의합니다. + * + * 동일한 타입 안에서 정보의 우선순위를 표현할 때 사용합니다. + */ +@Immutable +enum class PrezelChipHierarchy { + PRIMARY, + SECONDARY, +} + +/** + * 일반 칩의 강조 색상을 정의합니다. + * + * 특정 의미를 컬러로 강조해야 할 때 사용합니다. + */ +@Immutable +enum class PrezelChipAccent { + DEFAULT, + PURPLE, + TEAL, } diff --git a/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryPresentationCard.kt b/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryPresentationCard.kt index 0259057b..c3ad38b6 100644 --- a/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryPresentationCard.kt +++ b/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryPresentationCard.kt @@ -19,8 +19,10 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.team.prezel.core.designsystem.component.base.PrezelTouchArea import com.team.prezel.core.designsystem.component.chip.PrezelChip -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipDefaults +import com.team.prezel.core.designsystem.component.chip.config.PrezelChipHierarchy import com.team.prezel.core.designsystem.component.chip.config.PrezelChipSize +import com.team.prezel.core.designsystem.component.chip.config.PrezelChipState +import com.team.prezel.core.designsystem.component.chip.config.PrezelChipStatus import com.team.prezel.core.designsystem.component.chip.config.PrezelChipType import com.team.prezel.core.designsystem.icon.PrezelIcons import com.team.prezel.core.designsystem.preview.BasicPreview @@ -127,14 +129,10 @@ private fun HistoryCategoryChip( text = text, modifier = modifier, iconResId = PrezelIcons.Blank, - config = PrezelChipDefaults.getDefault( - iconOnly = false, - type = PrezelChipType.FILLED, - size = PrezelChipSize.SMALL, - containerColor = PrezelTheme.colors.interactiveXSmall, - iconColor = PrezelTheme.colors.interactiveRegular, - textColor = PrezelTheme.colors.interactiveRegular, - ), + type = PrezelChipType.FILLED, + size = PrezelChipSize.SMALL, + state = PrezelChipState.ACTIVE, + hierarchy = PrezelChipHierarchy.PRIMARY, ) } @@ -148,6 +146,7 @@ private fun HistoryMetaChip( modifier = modifier, type = PrezelChipType.OUTLINED, size = PrezelChipSize.SMALL, + status = PrezelChipStatus.DEFAULT, ) } diff --git a/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/component/title/PresentationHero.kt b/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/component/title/PresentationHero.kt index ce8d5ade..984ede8c 100644 --- a/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/component/title/PresentationHero.kt +++ b/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/component/title/PresentationHero.kt @@ -11,7 +11,8 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import com.team.prezel.core.designsystem.component.chip.PrezelChip -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipDefaults +import com.team.prezel.core.designsystem.component.chip.config.PrezelChipSize +import com.team.prezel.core.designsystem.component.chip.config.PrezelChipType import com.team.prezel.core.designsystem.preview.BasicPreview import com.team.prezel.core.designsystem.theme.PrezelTheme import com.team.prezel.core.model.presentation.Category @@ -33,11 +34,8 @@ internal fun PresentationHero( ) { PrezelChip( text = stringResource(id = presentation.category.labelResId()), - config = PrezelChipDefaults.getDefault( - iconOnly = false, - containerColor = PrezelTheme.colors.bgRegular, - textColor = PrezelTheme.colors.interactiveRegular, - ), + type = PrezelChipType.OUTLINED, + size = PrezelChipSize.SMALL, ) Spacer(modifier = Modifier.weight(1f)) From 00f4953da09b69488afb0e1388c21660a617e425 Mon Sep 17 00:00:00 2001 From: moondev03 Date: Fri, 8 May 2026 14:49:30 +0900 Subject: [PATCH 06/11] =?UTF-8?q?refactor:=20=EB=94=94=EC=9E=90=EC=9D=B8?= =?UTF-8?q?=20=EC=8B=9C=EC=8A=A4=ED=85=9C=20=EC=83=89=EC=83=81=20=EC=B2=B4?= =?UTF-8?q?=EA=B3=84=20=EC=A0=95=EB=A6=AC=20=EB=B0=8F=20Magenta=20?= =?UTF-8?q?=EC=83=89=EC=83=81=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * **refactor: Magenta 컬러 토큰 및 테마 속성 삭제** * `ColorTokens`에서 사용하지 않는 Magenta 계열 색상 팔레트(`Magenta10` ~ `Magenta950`)를 모두 제거했습니다. * `PrezelColors` 클래스 및 `PrezelColorScheme` 설정에서 `accentMagentaSmall`, `accentMagentaRegular` 속성을 삭제했습니다. * **style: DatePicker 내 휴일 표시 색상 변경** * `DatePickerDefaults`에서 휴일 텍스트 색상(`holidayDayTextColor`)을 기존 `accentMagentaRegular`에서 `feedbackWarningRegular`로 변경하여 테마 일관성을 확보했습니다. --- .../datepicker/config/DatePickerDefaults.kt | 2 +- .../designsystem/foundation/color/ColorTokens.kt | 13 ------------- .../designsystem/foundation/color/PrezelColors.kt | 2 -- .../core/designsystem/theme/PrezelColorScheme.kt | 4 ---- 4 files changed, 1 insertion(+), 20 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/config/DatePickerDefaults.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/config/DatePickerDefaults.kt index 86701a04..0c6f2c83 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/config/DatePickerDefaults.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/datepicker/config/DatePickerDefaults.kt @@ -50,6 +50,6 @@ internal object DatePickerDefaults { dayTextColor = PrezelTheme.colors.textMedium, pastDayTextColor = Color.Transparent, todayDayTextColor = PrezelTheme.colors.interactiveRegular, - holidayDayTextColor = PrezelTheme.colors.accentMagentaRegular, + holidayDayTextColor = PrezelTheme.colors.feedbackWarningRegular, ) } diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/color/ColorTokens.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/color/ColorTokens.kt index f8cb3e19..28c2b124 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/color/ColorTokens.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/color/ColorTokens.kt @@ -83,17 +83,4 @@ internal object ColorTokens { val Purple800 = Color(0xFF39018C) val Purple900 = Color(0xFF2C0066) val Purple950 = Color(0xFF1E0040) - - val Magenta10 = Color(0xFFFFF0F5) - val Magenta50 = Color(0xFFFFC7DB) - val Magenta100 = Color(0xFFFF9EC5) - val Magenta200 = Color(0xFFFF7AB4) - val Magenta300 = Color(0xFFFF57A5) - val Magenta400 = Color(0xFFFF57A5) - val Magenta500 = Color(0xFFFF1091) - val Magenta600 = Color(0xFFD90681) - val Magenta700 = Color(0xFFB2006B) - val Magenta800 = Color(0xFF8B0058) - val Magenta900 = Color(0xFF660044) - val Magenta950 = Color(0xFF40002D) } diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/color/PrezelColors.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/color/PrezelColors.kt index 25121276..3203c720 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/color/PrezelColors.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/foundation/color/PrezelColors.kt @@ -50,8 +50,6 @@ data class PrezelColors( val accentPurpleRegular: Color, val accentTealSmall: Color, val accentTealRegular: Color, - val accentMagentaSmall: Color, - val accentMagentaRegular: Color, // Solid // 흰색과 검정색을 제공하여 시각적 대비, 보조, 구분 등에 활용되는 절대값 색상입니다. val solidWhite: Color, diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelColorScheme.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelColorScheme.kt index a51e235f..0b08170c 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelColorScheme.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelColorScheme.kt @@ -53,8 +53,6 @@ internal object PrezelColorScheme { accentPurpleRegular = ColorTokens.Purple500, accentTealSmall = ColorTokens.Teal10, accentTealRegular = ColorTokens.Teal600, - accentMagentaSmall = ColorTokens.Magenta10, - accentMagentaRegular = ColorTokens.Magenta500, solidWhite = ColorTokens.Common0, solidBlack = ColorTokens.Common1000, chipContainerSecondaryFilledDefault = ColorTokens.CoolGray50, @@ -93,8 +91,6 @@ internal object PrezelColorScheme { accentPurpleRegular = ColorTokens.Purple500, accentTealSmall = ColorTokens.Teal10, accentTealRegular = ColorTokens.Teal600, - accentMagentaSmall = ColorTokens.Magenta10, - accentMagentaRegular = ColorTokens.Magenta500, solidWhite = ColorTokens.Common0, solidBlack = ColorTokens.Common1000, chipContainerSecondaryFilledDefault = ColorTokens.CoolGray50, From ab73ab098b4d04b1690a35843b8a14c17f517d24 Mon Sep 17 00:00:00 2001 From: moondev03 Date: Fri, 8 May 2026 14:54:52 +0900 Subject: [PATCH 07/11] =?UTF-8?q?refactor:=20PrezelBadge=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=B0=B0=EA=B2=BD=20=EC=83=89?= =?UTF-8?q?=EC=83=81=20=ED=85=8C=EB=A7=88=20=ED=94=84=EB=A1=9C=ED=8D=BC?= =?UTF-8?q?=ED=8B=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * **style: PrezelBadge 내 배경 색상 참조 변경** * `PrezelBadge` 내부 `Box`의 배경 색상을 `PrezelTheme.colors.bgScrim`에서 `PrezelTheme.colors.scrimContainer`로 업데이트했습니다. --- .../main/java/com/team/prezel/core/ui/component/PrezelBadge.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/component/PrezelBadge.kt b/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/component/PrezelBadge.kt index 2da8d070..7f46dc55 100644 --- a/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/component/PrezelBadge.kt +++ b/Prezel/core/ui/src/main/java/com/team/prezel/core/ui/component/PrezelBadge.kt @@ -97,7 +97,7 @@ private fun BadgeImage( Box( modifier = Modifier .fillMaxSize() - .background(color = PrezelTheme.colors.bgScrim), + .background(color = PrezelTheme.colors.scrimContainer), contentAlignment = Alignment.Center, ) { Icon( From b4137b661482227f59110dc55b4c3de20d97b777 Mon Sep 17 00:00:00 2001 From: moondev03 Date: Fri, 8 May 2026 14:57:20 +0900 Subject: [PATCH 08/11] =?UTF-8?q?refactor:=20=EB=94=94=EC=9E=90=EC=9D=B8?= =?UTF-8?q?=20=EC=8B=9C=EC=8A=A4=ED=85=9C=20=ED=94=84=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9=20=EB=B0=8F=20Detekt=20=EC=84=A4=EC=A0=95=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * **refactor: 로컬 프리뷰 어노테이션을 공통 `LargeDevicePreview`로 교체** * `PrezelTypographyScheme.kt` 내부에서만 정의해 사용하던 `@TypographyPreview`를 삭제하고, 공통 모듈의 `@LargeDevicePreview`를 사용하도록 변경했습니다. * 이에 따라 관련 Typography 프리뷰 함수(`PrezelTypographyTitlePreview`, `PrezelTypographyBodyPreview` 등)의 어노테이션을 일괄 업데이트했습니다. * **refactor: Detekt 정적 분석 예외 규칙 수정** * `detekt-config.yml` 내 `LongMethod` 등 복잡도 검사 제외 대상에서 기존 `@TypographyPreview`를 제거하고 `@LargeDevicePreview`를 추가했습니다. * Compose 프리뷰 함수들이 긴 메서드 길이 제한 등에 걸리지 않도록 예외 처리 설정을 최신화했습니다. --- .../designsystem/theme/PrezelTypographyScheme.kt | 14 ++++---------- Prezel/detekt-config.yml | 3 ++- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelTypographyScheme.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelTypographyScheme.kt index 01627660..a9ac948a 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelTypographyScheme.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/theme/PrezelTypographyScheme.kt @@ -3,9 +3,9 @@ package com.team.prezel.core.designsystem.theme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.tooling.preview.Preview import com.team.prezel.core.designsystem.foundation.typography.PrezelTextStyles import com.team.prezel.core.designsystem.foundation.typography.PrezelTypography +import com.team.prezel.core.designsystem.preview.LargeDevicePreview import com.team.prezel.core.designsystem.preview.PreviewSection import com.team.prezel.core.designsystem.preview.PreviewValueRow import kotlinx.collections.immutable.ImmutableList @@ -37,13 +37,7 @@ internal object PrezelTypographyScheme { ) } -@Preview( - showBackground = true, - device = "spec:width=850dp,height=600dp", -) -private annotation class TypographyPreview - -@TypographyPreview +@LargeDevicePreview @Composable private fun PrezelTypographyTitlePreview() { val typography = PrezelTypographyScheme.Default() @@ -61,7 +55,7 @@ private fun PrezelTypographyTitlePreview() { ) } -@TypographyPreview +@LargeDevicePreview @Composable private fun PrezelTypographyBodyPreview() { val typography = PrezelTypographyScheme.Default() @@ -82,7 +76,7 @@ private fun PrezelTypographyBodyPreview() { ) } -@TypographyPreview +@LargeDevicePreview @Composable private fun PrezelTypographyCaptionPreview() { val typography = PrezelTypographyScheme.Default() diff --git a/Prezel/detekt-config.yml b/Prezel/detekt-config.yml index d0af157f..ac58f0dd 100644 --- a/Prezel/detekt-config.yml +++ b/Prezel/detekt-config.yml @@ -16,7 +16,7 @@ style: ignoreAnnotated: - Preview - BasicPreview - - TypographyPreview + - LargeDevicePreview complexity: LongMethod: @@ -24,6 +24,7 @@ complexity: ignoreAnnotated: - Preview - BasicPreview + - LargeDevicePreview NestedBlockDepth: threshold: 4 LongParameterList: From 1b332c13bd220a1ee97767ae31532b711c2ea022 Mon Sep 17 00:00:00 2001 From: moondev03 Date: Fri, 8 May 2026 15:44:51 +0900 Subject: [PATCH 09/11] =?UTF-8?q?refactor:=20Chip=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EA=B5=AC=EC=A1=B0=20=EA=B0=9C=EC=84=A0=20?= =?UTF-8?q?=EB=B0=8F=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * **refactor: Chip 컴포넌트 베이스 구조 구축 및 패키지 재구성** * `component.chip.base` 패키지를 신설하고 공통 레이아웃(`PrezelChipLayout`)과 스타일 클래스(`PrezelChipStyle`, `PrezelChipColors`)를 이동했습니다. * 칩의 공통 형상(Shape) 및 텍스트 스타일 정의, 그리고 상태별 액센트 컬러 결정 로직을 베이스 함수로 추출하여 중복을 제거했습니다. * **refactor: 일반 칩 및 아이콘 칩 로직 분리 및 고도화** * 기존에 혼재되어 있던 일반 칩(`PrezelChip`)과 아이콘 칩(`PrezelIconChip`)의 구현을 각각 `component.chip.chip`과 `component.chip.iconChip` 패키지로 분리했습니다. * `PrezelChipSize`, `PrezelChipType` 등의 열거형 명칭을 `ChipSize`, `ChipType` (일반 칩) 및 `IconChipSize`, `IconChipType` (아이콘 칩)으로 간소화하고 각 타입에 최적화된 상태값을 갖도록 수정했습니다. * 각 칩 타입별로 전용 `Defaults` 클래스를 제공하여 스타일 설정 로직의 가독성을 높였습니다. * **refactor: Feature 모듈 내 변경된 칩 참조 수정** * `home`, `history` 등 기능 모듈에서 변경된 칩 컴포넌트의 패키지 경로 및 간소화된 enum 명칭(예: `PrezelChipSize.SMALL` -> `ChipSize.SMALL`)을 일괄 반영했습니다. * **cleanup: 불필요한 코드 및 설정 정리** * `PrezelChipModels.kt` 등 기존의 범용 설정 파일을 삭제하고 각 패키지 내부에 맞게 재정의했습니다. * 칩 내부 로직에서 사용되지 않는 상태 처리 및 잘못된 예외 처리 구문을 정리했습니다. --- .../chip/{config => base}/PrezelChipLayout.kt | 2 +- .../component/chip/base/PrezelChipStyle.kt | 94 +++++ .../component/chip/{ => chip}/PrezelChip.kt | 102 +++-- .../component/chip/chip/PrezelChipDefaults.kt | 192 +++++++++ .../chip/config/PrezelChipDefaults.kt | 378 ------------------ .../component/chip/config/PrezelChipModels.kt | 72 ---- .../chip/{ => iconChip}/PrezelIconChip.kt | 71 ++-- .../chip/iconChip/PrezelIconChipDefaults.kt | 134 +++++++ .../impl/component/HistoryPresentationCard.kt | 26 +- .../impl/component/title/PresentationHero.kt | 10 +- 10 files changed, 550 insertions(+), 531 deletions(-) rename Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/{config => base}/PrezelChipLayout.kt (97%) create mode 100644 Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/base/PrezelChipStyle.kt rename Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/{ => chip}/PrezelChip.kt (60%) create mode 100644 Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/chip/PrezelChipDefaults.kt delete mode 100644 Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipDefaults.kt delete mode 100644 Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipModels.kt rename Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/{ => iconChip}/PrezelIconChip.kt (60%) create mode 100644 Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/iconChip/PrezelIconChipDefaults.kt diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipLayout.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/base/PrezelChipLayout.kt similarity index 97% rename from Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipLayout.kt rename to Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/base/PrezelChipLayout.kt index 9512bf22..5b4e4fc8 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipLayout.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/base/PrezelChipLayout.kt @@ -1,4 +1,4 @@ -package com.team.prezel.core.designsystem.component.chip.config +package com.team.prezel.core.designsystem.component.chip.base import androidx.annotation.DrawableRes import androidx.compose.foundation.BorderStroke diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/base/PrezelChipStyle.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/base/PrezelChipStyle.kt new file mode 100644 index 00000000..0e450ec4 --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/base/PrezelChipStyle.kt @@ -0,0 +1,94 @@ +package com.team.prezel.core.designsystem.component.chip.base + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.Dp +import com.team.prezel.core.designsystem.component.chip.chip.ChipAccent +import com.team.prezel.core.designsystem.component.chip.chip.ChipSize +import com.team.prezel.core.designsystem.component.chip.chip.ChipStatus +import com.team.prezel.core.designsystem.component.chip.iconChip.IconChipSize +import com.team.prezel.core.designsystem.theme.PrezelTheme + +@Immutable +internal data class PrezelChipColors( + val containerColor: Color, + val iconColor: Color, + val textColor: Color, + val borderColor: Color?, +) + +@Immutable +internal data class PrezelChipStyle( + val shape: Shape, + val textStyle: TextStyle, + val colors: PrezelChipColors, + val contentPadding: PaddingValues, + val iconTextSpacing: Dp, + val iconSize: Dp, +) + +@Composable +internal fun chipShape(size: ChipSize): Shape = + when (size) { + ChipSize.SMALL -> PrezelTheme.shapes.V4 + ChipSize.REGULAR -> PrezelTheme.shapes.V8 + } + +@Composable +internal fun chipTextStyle(size: ChipSize): TextStyle = + when (size) { + ChipSize.SMALL -> PrezelTheme.typography.caption2Regular + ChipSize.REGULAR -> PrezelTheme.typography.caption1Regular + } + +@Composable +internal fun iconChipShape(size: IconChipSize): Shape = + when (size) { + IconChipSize.SMALL -> PrezelTheme.shapes.V4 + IconChipSize.REGULAR -> PrezelTheme.shapes.V8 + } + +@Composable +internal fun iconChipTextStyle(size: IconChipSize): TextStyle = + when (size) { + IconChipSize.SMALL -> PrezelTheme.typography.caption2Regular + IconChipSize.REGULAR -> PrezelTheme.typography.caption1Regular + } + +@Composable +internal fun resolveContainerAccent( + status: ChipStatus, + accent: ChipAccent, +): Color? = + when (accent) { + ChipAccent.WARNING -> PrezelTheme.colors.feedbackWarningSmall + ChipAccent.PURPLE -> PrezelTheme.colors.accentPurpleSmall + ChipAccent.TEAL -> PrezelTheme.colors.accentTealSmall + ChipAccent.DEFAULT -> { + when (status) { + ChipStatus.DEFAULT -> null + ChipStatus.BAD -> PrezelTheme.colors.feedbackBadSmall + } + } + } + +@Composable +internal fun resolveContentAccent( + status: ChipStatus, + accent: ChipAccent, +): Color? = + when (accent) { + ChipAccent.WARNING -> PrezelTheme.colors.feedbackWarningRegular + ChipAccent.PURPLE -> PrezelTheme.colors.accentPurpleRegular + ChipAccent.TEAL -> PrezelTheme.colors.accentTealRegular + ChipAccent.DEFAULT -> { + when (status) { + ChipStatus.DEFAULT -> null + ChipStatus.BAD -> PrezelTheme.colors.feedbackBadRegular + } + } + } diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/PrezelChip.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/chip/PrezelChip.kt similarity index 60% rename from Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/PrezelChip.kt rename to Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/chip/PrezelChip.kt index 63978bbb..91403ca4 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/PrezelChip.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/chip/PrezelChip.kt @@ -1,16 +1,10 @@ -package com.team.prezel.core.designsystem.component.chip +package com.team.prezel.core.designsystem.component.chip.chip import androidx.annotation.DrawableRes import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable import androidx.compose.ui.Modifier -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipAccent -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipDefaults -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipHierarchy -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipLayout -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipSize -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipState -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipStatus -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipType +import com.team.prezel.core.designsystem.component.chip.base.PrezelChipLayout import com.team.prezel.core.designsystem.icon.PrezelIcons import com.team.prezel.core.designsystem.preview.LargeDevicePreview import com.team.prezel.core.designsystem.preview.PreviewMatrix @@ -18,23 +12,61 @@ import com.team.prezel.core.designsystem.preview.PreviewMatrixColumn import com.team.prezel.core.designsystem.preview.PreviewMatrixRow import com.team.prezel.core.designsystem.preview.PreviewSection +@Immutable +enum class ChipType { + FILLED, + OUTLINED, +} + +@Immutable +enum class ChipSize { + SMALL, + REGULAR, +} + +@Immutable +enum class ChipState { + DEFAULT, + ACTIVE, +} + +@Immutable +enum class ChipStatus { + DEFAULT, + BAD, +} + +@Immutable +enum class ChipHierarchy { + PRIMARY, + SECONDARY, +} + +@Immutable +enum class ChipAccent { + DEFAULT, + WARNING, + PURPLE, + TEAL, +} + @Composable fun PrezelChip( text: String, modifier: Modifier = Modifier, @DrawableRes iconResId: Int? = null, - type: PrezelChipType = PrezelChipType.FILLED, - size: PrezelChipSize = PrezelChipSize.REGULAR, - state: PrezelChipState = PrezelChipState.DEFAULT, - status: PrezelChipStatus = PrezelChipStatus.DEFAULT, - hierarchy: PrezelChipHierarchy = PrezelChipHierarchy.PRIMARY, - accent: PrezelChipAccent = PrezelChipAccent.DEFAULT, + type: ChipType = ChipType.FILLED, + size: ChipSize = ChipSize.REGULAR, + state: ChipState = ChipState.DEFAULT, + status: ChipStatus = ChipStatus.DEFAULT, + hierarchy: ChipHierarchy = ChipHierarchy.PRIMARY, + accent: ChipAccent = ChipAccent.DEFAULT, ) { PrezelChipLayout( modifier = modifier, text = text, iconResId = iconResId, - style = PrezelChipDefaults.chipStyle( + style = PrezelChipDefaults.getDefault( type = type, size = size, state = state, @@ -46,20 +78,20 @@ fun PrezelChip( } private data class ChipPreviewCase( - val type: PrezelChipType, - val size: PrezelChipSize = PrezelChipSize.REGULAR, - val state: PrezelChipState = PrezelChipState.DEFAULT, - val status: PrezelChipStatus = PrezelChipStatus.DEFAULT, - val hierarchy: PrezelChipHierarchy = PrezelChipHierarchy.PRIMARY, - val accent: PrezelChipAccent = PrezelChipAccent.DEFAULT, + val type: ChipType, + val size: ChipSize = ChipSize.REGULAR, + val state: ChipState = ChipState.DEFAULT, + val status: ChipStatus = ChipStatus.DEFAULT, + val hierarchy: ChipHierarchy = ChipHierarchy.PRIMARY, + val accent: ChipAccent = ChipAccent.DEFAULT, val showLeadingIcon: Boolean = true, ) private val chipPreviewColumns = listOf( - PrezelChipSize.SMALL to PrezelChipType.FILLED, - PrezelChipSize.SMALL to PrezelChipType.OUTLINED, - PrezelChipSize.REGULAR to PrezelChipType.FILLED, - PrezelChipSize.REGULAR to PrezelChipType.OUTLINED, + ChipSize.SMALL to ChipType.FILLED, + ChipSize.SMALL to ChipType.OUTLINED, + ChipSize.REGULAR to ChipType.FILLED, + ChipSize.REGULAR to ChipType.OUTLINED, ) private fun previewCases(transform: ChipPreviewCase.() -> ChipPreviewCase = { this }) = @@ -88,27 +120,27 @@ private fun PrezelChipPreview() { ), PreviewMatrixRow( label = "Hierarchy / Secondary", - values = previewCases { copy(hierarchy = PrezelChipHierarchy.SECONDARY) }, + values = previewCases { copy(hierarchy = ChipHierarchy.SECONDARY) }, ), PreviewMatrixRow( label = "State / Active", - values = previewCases { copy(state = PrezelChipState.ACTIVE) }, + values = previewCases { copy(state = ChipState.ACTIVE) }, ), PreviewMatrixRow( label = "Status / Bad", - values = previewCases { copy(status = PrezelChipStatus.BAD) }, - ), - PreviewMatrixRow( - label = "Status / Warning", - values = previewCases { copy(status = PrezelChipStatus.WARNING) }, + values = previewCases { copy(status = ChipStatus.BAD) }, ), PreviewMatrixRow( label = "Accent / Purple", - values = previewCases { copy(accent = PrezelChipAccent.PURPLE) }, + values = previewCases { copy(accent = ChipAccent.PURPLE) }, ), PreviewMatrixRow( label = "Accent / Teal", - values = previewCases { copy(accent = PrezelChipAccent.TEAL) }, + values = previewCases { copy(accent = ChipAccent.TEAL) }, + ), + PreviewMatrixRow( + label = "Accent / Warning", + values = previewCases { copy(accent = ChipAccent.WARNING) }, ), PreviewMatrixRow( label = "Leading Icon / Off", diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/chip/PrezelChipDefaults.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/chip/PrezelChipDefaults.kt new file mode 100644 index 00000000..26c60641 --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/chip/PrezelChipDefaults.kt @@ -0,0 +1,192 @@ +package com.team.prezel.core.designsystem.component.chip.chip + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.team.prezel.core.designsystem.component.chip.base.PrezelChipColors +import com.team.prezel.core.designsystem.component.chip.base.PrezelChipStyle +import com.team.prezel.core.designsystem.component.chip.base.chipShape +import com.team.prezel.core.designsystem.component.chip.base.chipTextStyle +import com.team.prezel.core.designsystem.component.chip.base.resolveContainerAccent +import com.team.prezel.core.designsystem.component.chip.base.resolveContentAccent +import com.team.prezel.core.designsystem.theme.PrezelTheme + +object PrezelChipDefaults { + @Composable + internal fun getDefault( + type: ChipType, + size: ChipSize, + state: ChipState, + status: ChipStatus, + hierarchy: ChipHierarchy, + accent: ChipAccent, + ): PrezelChipStyle = + PrezelChipStyle( + shape = chipShape(size = size), + textStyle = chipTextStyle(size = size), + colors = chipColors( + type = type, + state = state, + status = status, + hierarchy = hierarchy, + accent = accent, + ), + contentPadding = contentPadding(size = size), + iconTextSpacing = iconTextSpacing(size = size), + iconSize = iconSize(size = size), + ) + + @Composable + private fun iconSize(size: ChipSize): Dp = + when (size) { + ChipSize.SMALL -> 14.dp + ChipSize.REGULAR -> 16.dp + } + + @Composable + private fun chipColors( + type: ChipType, + state: ChipState, + status: ChipStatus, + hierarchy: ChipHierarchy, + accent: ChipAccent, + ): PrezelChipColors { + val contentAccentColor = resolveContentAccent(status = status, accent = accent) + val usesDefaultHierarchyStyle = state == ChipState.DEFAULT && + status == ChipStatus.DEFAULT && + accent == ChipAccent.DEFAULT + + return PrezelChipColors( + containerColor = resolveChipContainerColor( + type = type, + state = state, + status = status, + hierarchy = hierarchy, + accent = accent, + ), + iconColor = resolveChipIconColor( + type = type, + state = state, + hierarchy = hierarchy, + contentAccentColor = contentAccentColor, + usesDefaultHierarchyStyle = usesDefaultHierarchyStyle, + ), + textColor = resolveChipTextColor( + type = type, + state = state, + hierarchy = hierarchy, + contentAccentColor = contentAccentColor, + usesDefaultHierarchyStyle = usesDefaultHierarchyStyle, + ), + borderColor = if (type == ChipType.OUTLINED) { + resolveChipBorderColor( + state = state, + hierarchy = hierarchy, + contentAccentColor = contentAccentColor, + ) + } else { + null + }, + ) + } + + @Composable + private fun contentPadding(size: ChipSize): PaddingValues { + val horizontal = when (size) { + ChipSize.SMALL -> PrezelTheme.spacing.V6 + ChipSize.REGULAR -> PrezelTheme.spacing.V8 + } + + val vertical = when (size) { + ChipSize.SMALL -> PrezelTheme.spacing.V4 + ChipSize.REGULAR -> PrezelTheme.spacing.V6 + } + + return PaddingValues(horizontal = horizontal, vertical = vertical) + } + + @Composable + private fun iconTextSpacing(size: ChipSize): Dp = + when (size) { + ChipSize.SMALL -> PrezelTheme.spacing.V2 + ChipSize.REGULAR -> PrezelTheme.spacing.V4 + } + + @Composable + private fun resolveChipBorderColor( + state: ChipState, + hierarchy: ChipHierarchy, + contentAccentColor: Color?, + ): Color { + if (contentAccentColor != null) return contentAccentColor + if (state == ChipState.ACTIVE) return PrezelTheme.colors.interactiveRegular + + return when (hierarchy) { + ChipHierarchy.PRIMARY -> PrezelTheme.colors.borderMedium + ChipHierarchy.SECONDARY -> PrezelTheme.colors.borderRegular + } + } + + @Composable + private fun resolveChipContainerColor( + type: ChipType, + state: ChipState, + status: ChipStatus, + hierarchy: ChipHierarchy, + accent: ChipAccent, + ): Color { + val containerAccentColor = resolveContainerAccent(status = status, accent = accent) + if (containerAccentColor != null) return containerAccentColor + + if (state == ChipState.ACTIVE) return PrezelTheme.colors.interactiveXSmall + if (type == ChipType.OUTLINED) return PrezelTheme.colors.bgRegular + if ( + state != ChipState.DEFAULT || + status != ChipStatus.DEFAULT || + accent != ChipAccent.DEFAULT + ) { + return PrezelTheme.colors.bgLarge + } + + return when (hierarchy) { + ChipHierarchy.PRIMARY -> PrezelTheme.colors.bgLarge + ChipHierarchy.SECONDARY -> PrezelTheme.colors.chipContainerSecondaryFilledDefault + } + } + + @Composable + private fun resolveChipIconColor( + type: ChipType, + state: ChipState, + hierarchy: ChipHierarchy, + contentAccentColor: Color?, + usesDefaultHierarchyStyle: Boolean, + ): Color { + if (contentAccentColor != null) return contentAccentColor + if (state == ChipState.ACTIVE) return PrezelTheme.colors.interactiveRegular + if (type == ChipType.FILLED && usesDefaultHierarchyStyle && hierarchy == ChipHierarchy.PRIMARY) { + return PrezelTheme.colors.iconMedium + } + + return PrezelTheme.colors.iconRegular + } + + @Composable + private fun resolveChipTextColor( + type: ChipType, + state: ChipState, + hierarchy: ChipHierarchy, + contentAccentColor: Color?, + usesDefaultHierarchyStyle: Boolean, + ): Color { + if (contentAccentColor != null) return contentAccentColor + if (state == ChipState.ACTIVE) return PrezelTheme.colors.interactiveRegular + if (type == ChipType.FILLED && usesDefaultHierarchyStyle && hierarchy == ChipHierarchy.PRIMARY) { + return PrezelTheme.colors.textMedium + } + + return PrezelTheme.colors.textRegular + } +} diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipDefaults.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipDefaults.kt deleted file mode 100644 index 0f427218..00000000 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipDefaults.kt +++ /dev/null @@ -1,378 +0,0 @@ -package com.team.prezel.core.designsystem.component.chip.config - -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.runtime.Composable -import androidx.compose.runtime.Immutable -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.Shape -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp -import com.team.prezel.core.designsystem.theme.PrezelTheme - -@Immutable -internal data class PrezelChipColors( - val containerColor: Color, - val iconColor: Color, - val textColor: Color, - val borderColor: Color?, -) - -@Immutable -internal data class PrezelChipStyle( - val shape: Shape, - val textStyle: TextStyle, - val colors: PrezelChipColors, - val contentPadding: PaddingValues, - val iconTextSpacing: Dp, - val iconSize: Dp, -) - -object PrezelChipDefaults { - @Composable - internal fun chipStyle( - type: PrezelChipType, - size: PrezelChipSize, - state: PrezelChipState, - status: PrezelChipStatus, - hierarchy: PrezelChipHierarchy, - accent: PrezelChipAccent, - ): PrezelChipStyle = - PrezelChipStyle( - shape = shape(size = size), - textStyle = textStyle(size = size), - colors = chipColors( - type = type, - state = normalizeChipState(state), - status = status, - hierarchy = hierarchy, - accent = accent, - ), - contentPadding = contentPadding(size = size), - iconTextSpacing = iconTextSpacing(size = size), - iconSize = chipIconSize(size = size), - ) - - @Composable - internal fun iconChipStyle( - type: PrezelChipType, - size: PrezelChipSize, - state: PrezelChipState, - status: PrezelChipStatus, - ): PrezelChipStyle = - PrezelChipStyle( - shape = shape(size = size), - textStyle = textStyle(size = size), - colors = iconChipColors(type = type, state = state, status = status), - contentPadding = iconContentPadding(size = size), - iconTextSpacing = 0.dp, - iconSize = iconChipIconSize(size = size), - ) - - @Composable - private fun chipColors( - type: PrezelChipType, - state: PrezelChipState, - status: PrezelChipStatus, - hierarchy: PrezelChipHierarchy, - accent: PrezelChipAccent, - ): PrezelChipColors { - val contentAccentColor = resolveContentAccent(status = status, accent = accent) - val usesDefaultHierarchyStyle = usesHierarchyDefaultStyle( - state = state, - status = status, - accent = accent, - ) - - return PrezelChipColors( - containerColor = resolveChipContainerColor( - type = type, - state = state, - status = status, - hierarchy = hierarchy, - accent = accent, - ), - iconColor = resolveChipIconColor( - type = type, - state = state, - hierarchy = hierarchy, - contentAccentColor = contentAccentColor, - usesDefaultHierarchyStyle = usesDefaultHierarchyStyle, - ), - textColor = resolveChipTextColor( - type = type, - state = state, - hierarchy = hierarchy, - contentAccentColor = contentAccentColor, - usesDefaultHierarchyStyle = usesDefaultHierarchyStyle, - ), - borderColor = resolveOutlinedBorderColor( - type = type, - color = resolveChipBorderColor( - state = state, - hierarchy = hierarchy, - contentAccentColor = contentAccentColor, - ), - ), - ) - } - - @Composable - private fun iconChipColors( - type: PrezelChipType, - state: PrezelChipState, - status: PrezelChipStatus, - ): PrezelChipColors { - val contentAccentColor = resolveContentAccent( - status = status, - accent = PrezelChipAccent.DEFAULT, - ) - val iconColor = resolveIconChipContentColor( - type = type, - state = state, - contentAccentColor = contentAccentColor, - ) - - return PrezelChipColors( - containerColor = resolveIconChipContainerColor( - type = type, - state = state, - status = status, - ), - iconColor = iconColor, - textColor = iconColor, - borderColor = resolveOutlinedBorderColor( - type = type, - color = resolveIconChipBorderColor( - state = state, - contentAccentColor = contentAccentColor, - ), - ), - ) - } - - @Composable - private fun shape(size: PrezelChipSize): Shape = - when (size) { - PrezelChipSize.SMALL -> PrezelTheme.shapes.V4 - PrezelChipSize.REGULAR -> PrezelTheme.shapes.V8 - } - - @Composable - private fun textStyle(size: PrezelChipSize): TextStyle = - when (size) { - PrezelChipSize.SMALL -> PrezelTheme.typography.caption2Regular - PrezelChipSize.REGULAR -> PrezelTheme.typography.caption1Regular - } - - @Composable - private fun contentPadding(size: PrezelChipSize): PaddingValues { - val horizontal = when (size) { - PrezelChipSize.SMALL -> PrezelTheme.spacing.V6 - PrezelChipSize.REGULAR -> PrezelTheme.spacing.V8 - } - - val vertical = when (size) { - PrezelChipSize.SMALL -> PrezelTheme.spacing.V4 - PrezelChipSize.REGULAR -> PrezelTheme.spacing.V6 - } - - return PaddingValues(horizontal = horizontal, vertical = vertical) - } - - @Composable - private fun iconContentPadding(size: PrezelChipSize): PaddingValues { - val all = when (size) { - PrezelChipSize.SMALL -> PrezelTheme.spacing.V6 - PrezelChipSize.REGULAR -> PrezelTheme.spacing.V8 - } - - return PaddingValues(all = all) - } - - @Composable - private fun iconTextSpacing(size: PrezelChipSize): Dp = - when (size) { - PrezelChipSize.SMALL -> PrezelTheme.spacing.V2 - PrezelChipSize.REGULAR -> PrezelTheme.spacing.V4 - } - - private fun chipIconSize(size: PrezelChipSize): Dp = - when (size) { - PrezelChipSize.SMALL -> 14.dp - PrezelChipSize.REGULAR -> 16.dp - } - - private fun iconChipIconSize(size: PrezelChipSize): Dp = - when (size) { - PrezelChipSize.SMALL -> 12.dp - PrezelChipSize.REGULAR -> 14.dp - } - - @Composable - private fun resolveChipBorderColor( - state: PrezelChipState, - hierarchy: PrezelChipHierarchy, - contentAccentColor: Color?, - ): Color { - if (contentAccentColor != null) return contentAccentColor - if (state == PrezelChipState.ACTIVE) return PrezelTheme.colors.interactiveRegular - - return when (hierarchy) { - PrezelChipHierarchy.PRIMARY -> PrezelTheme.colors.borderMedium - PrezelChipHierarchy.SECONDARY -> PrezelTheme.colors.borderRegular - } - } - - @Composable - private fun resolveChipContainerColor( - type: PrezelChipType, - state: PrezelChipState, - status: PrezelChipStatus, - hierarchy: PrezelChipHierarchy, - accent: PrezelChipAccent, - ): Color { - val containerAccentColor = resolveContainerAccent(status = status, accent = accent) - if (containerAccentColor != null) return containerAccentColor - - if (state == PrezelChipState.ACTIVE) return PrezelTheme.colors.interactiveXSmall - if (type == PrezelChipType.OUTLINED) return PrezelTheme.colors.bgRegular - if (!usesHierarchyDefaultStyle(state = state, status = status, accent = accent)) { - return PrezelTheme.colors.bgLarge - } - - return when (hierarchy) { - PrezelChipHierarchy.PRIMARY -> PrezelTheme.colors.bgLarge - PrezelChipHierarchy.SECONDARY -> PrezelTheme.colors.chipContainerSecondaryFilledDefault - } - } - - @Composable - private fun resolveChipIconColor( - type: PrezelChipType, - state: PrezelChipState, - hierarchy: PrezelChipHierarchy, - contentAccentColor: Color?, - usesDefaultHierarchyStyle: Boolean, - ): Color { - if (contentAccentColor != null) return contentAccentColor - if (state == PrezelChipState.ACTIVE) return PrezelTheme.colors.interactiveRegular - if (type == PrezelChipType.FILLED && usesDefaultHierarchyStyle && hierarchy == PrezelChipHierarchy.PRIMARY) { - return PrezelTheme.colors.iconMedium - } - - return PrezelTheme.colors.iconRegular - } - - @Composable - private fun resolveChipTextColor( - type: PrezelChipType, - state: PrezelChipState, - hierarchy: PrezelChipHierarchy, - contentAccentColor: Color?, - usesDefaultHierarchyStyle: Boolean, - ): Color { - if (contentAccentColor != null) return contentAccentColor - if (state == PrezelChipState.ACTIVE) return PrezelTheme.colors.interactiveRegular - if (type == PrezelChipType.FILLED && usesDefaultHierarchyStyle && hierarchy == PrezelChipHierarchy.PRIMARY) { - return PrezelTheme.colors.textMedium - } - - return PrezelTheme.colors.textRegular - } - - private fun usesHierarchyDefaultStyle( - state: PrezelChipState, - status: PrezelChipStatus, - accent: PrezelChipAccent, - ): Boolean = state == PrezelChipState.DEFAULT && status == PrezelChipStatus.DEFAULT && accent == PrezelChipAccent.DEFAULT - - @Composable - private fun resolveIconChipContainerColor( - type: PrezelChipType, - state: PrezelChipState, - status: PrezelChipStatus, - ): Color { - if (type == PrezelChipType.OUTLINED) return Color.Transparent - - return when (state) { - PrezelChipState.DISABLED -> PrezelTheme.colors.bgMedium - PrezelChipState.ACTIVE -> PrezelTheme.colors.interactiveXSmall - PrezelChipState.DEFAULT -> { - when (status) { - PrezelChipStatus.DEFAULT -> PrezelTheme.colors.bgLarge - PrezelChipStatus.BAD -> PrezelTheme.colors.feedbackBadSmall - PrezelChipStatus.WARNING -> PrezelTheme.colors.feedbackWarningSmall - } - } - } - } - - @Composable - private fun resolveIconChipContentColor( - type: PrezelChipType, - state: PrezelChipState, - contentAccentColor: Color?, - ): Color { - if (state == PrezelChipState.DISABLED) return PrezelTheme.colors.iconDisabled - if (contentAccentColor != null) return contentAccentColor - if (state == PrezelChipState.ACTIVE) return PrezelTheme.colors.interactiveRegular - if (type == PrezelChipType.FILLED) return PrezelTheme.colors.iconMedium - - return PrezelTheme.colors.iconRegular - } - - @Composable - private fun resolveIconChipBorderColor( - state: PrezelChipState, - contentAccentColor: Color?, - ): Color { - if (state == PrezelChipState.DISABLED) return PrezelTheme.colors.borderRegular - if (contentAccentColor != null) return contentAccentColor - if (state == PrezelChipState.ACTIVE) return PrezelTheme.colors.interactiveRegular - - return PrezelTheme.colors.borderMedium - } - - private fun normalizeChipState(state: PrezelChipState): PrezelChipState = - if (state == PrezelChipState.DISABLED) PrezelChipState.DEFAULT else state - - private fun resolveOutlinedBorderColor( - type: PrezelChipType, - color: Color, - ): Color? = if (type == PrezelChipType.OUTLINED) color else null - - @Composable - private fun resolveContainerAccent( - status: PrezelChipStatus, - accent: PrezelChipAccent, - ): Color? = - when (accent) { - PrezelChipAccent.PURPLE -> PrezelTheme.colors.accentPurpleSmall - PrezelChipAccent.TEAL -> PrezelTheme.colors.accentTealSmall - PrezelChipAccent.DEFAULT -> { - when (status) { - PrezelChipStatus.DEFAULT -> null - PrezelChipStatus.BAD -> PrezelTheme.colors.feedbackBadSmall - PrezelChipStatus.WARNING -> PrezelTheme.colors.feedbackWarningSmall - } - } - } - - @Composable - private fun resolveContentAccent( - status: PrezelChipStatus, - accent: PrezelChipAccent, - ): Color? = - when (accent) { - PrezelChipAccent.PURPLE -> PrezelTheme.colors.accentPurpleRegular - PrezelChipAccent.TEAL -> PrezelTheme.colors.accentTealRegular - PrezelChipAccent.DEFAULT -> { - when (status) { - PrezelChipStatus.DEFAULT -> null - PrezelChipStatus.BAD -> PrezelTheme.colors.feedbackBadRegular - PrezelChipStatus.WARNING -> PrezelTheme.colors.feedbackWarningRegular - } - } - } -} diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipModels.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipModels.kt deleted file mode 100644 index 5dbd787e..00000000 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/config/PrezelChipModels.kt +++ /dev/null @@ -1,72 +0,0 @@ -package com.team.prezel.core.designsystem.component.chip.config - -import androidx.compose.runtime.Immutable - -/** - * 칩의 시각적 타입을 정의합니다. - * - * Chip의 배경, 테두리 표현 방식을 구분할 때 사용합니다. - */ -@Immutable -enum class PrezelChipType { - FILLED, - OUTLINED, -} - -/** - * 칩의 크기를 정의합니다. - * - * 칩의 높이, 패딩, 아이콘 크기, 텍스트 스타일의 기준으로 사용합니다. - */ -@Immutable -enum class PrezelChipSize { - SMALL, - REGULAR, -} - -/** - * 칩의 시각 상태를 정의합니다. - * - * 기본, 강조, 비활성 상태에 따라 칩의 강조 수준을 표현할 때 사용합니다. - */ -@Immutable -enum class PrezelChipState { - DEFAULT, - ACTIVE, - DISABLED, -} - -/** - * 칩의 의미 상태를 정의합니다. - * - * 일반 상태 외에 부정/경고 의미를 함께 전달해야 할 때 사용합니다. - */ -@Immutable -enum class PrezelChipStatus { - DEFAULT, - BAD, - WARNING, -} - -/** - * 일반 칩의 시각적 계층을 정의합니다. - * - * 동일한 타입 안에서 정보의 우선순위를 표현할 때 사용합니다. - */ -@Immutable -enum class PrezelChipHierarchy { - PRIMARY, - SECONDARY, -} - -/** - * 일반 칩의 강조 색상을 정의합니다. - * - * 특정 의미를 컬러로 강조해야 할 때 사용합니다. - */ -@Immutable -enum class PrezelChipAccent { - DEFAULT, - PURPLE, - TEAL, -} diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/PrezelIconChip.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/iconChip/PrezelIconChip.kt similarity index 60% rename from Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/PrezelIconChip.kt rename to Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/iconChip/PrezelIconChip.kt index 38603910..34b1f0a3 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/PrezelIconChip.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/iconChip/PrezelIconChip.kt @@ -1,14 +1,10 @@ -package com.team.prezel.core.designsystem.component.chip +package com.team.prezel.core.designsystem.component.chip.iconChip import androidx.annotation.DrawableRes import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable import androidx.compose.ui.Modifier -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipDefaults -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipLayout -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipSize -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipState -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipStatus -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipType +import com.team.prezel.core.designsystem.component.chip.base.PrezelChipLayout import com.team.prezel.core.designsystem.icon.PrezelIcons import com.team.prezel.core.designsystem.preview.LargeDevicePreview import com.team.prezel.core.designsystem.preview.PreviewMatrix @@ -16,20 +12,45 @@ import com.team.prezel.core.designsystem.preview.PreviewMatrixColumn import com.team.prezel.core.designsystem.preview.PreviewMatrixRow import com.team.prezel.core.designsystem.preview.PreviewSection +@Immutable +enum class IconChipType { + FILLED, + OUTLINED, +} + +@Immutable +enum class IconChipSize { + SMALL, + REGULAR, +} + +@Immutable +enum class IconChipState { + DEFAULT, + ACTIVE, + DISABLED, +} + +@Immutable +enum class IconChipStatus { + DEFAULT, + BAD, +} + @Composable fun PrezelIconChip( @DrawableRes iconResId: Int, modifier: Modifier = Modifier, - type: PrezelChipType = PrezelChipType.FILLED, - size: PrezelChipSize = PrezelChipSize.REGULAR, - state: PrezelChipState = PrezelChipState.DEFAULT, - status: PrezelChipStatus = PrezelChipStatus.DEFAULT, + type: IconChipType = IconChipType.FILLED, + size: IconChipSize = IconChipSize.REGULAR, + state: IconChipState = IconChipState.DEFAULT, + status: IconChipStatus = IconChipStatus.DEFAULT, ) { PrezelChipLayout( modifier = modifier, text = null, iconResId = iconResId, - style = PrezelChipDefaults.iconChipStyle( + style = PrezelIconChipDefaults.getDefault( type = type, size = size, state = state, @@ -39,17 +60,17 @@ fun PrezelIconChip( } private data class IconChipPreviewCase( - val type: PrezelChipType, - val size: PrezelChipSize = PrezelChipSize.REGULAR, - val state: PrezelChipState = PrezelChipState.DEFAULT, - val status: PrezelChipStatus = PrezelChipStatus.DEFAULT, + val type: IconChipType, + val size: IconChipSize = IconChipSize.REGULAR, + val state: IconChipState = IconChipState.DEFAULT, + val status: IconChipStatus = IconChipStatus.DEFAULT, ) private val iconChipPreviewColumns = listOf( - PrezelChipSize.SMALL to PrezelChipType.FILLED, - PrezelChipSize.SMALL to PrezelChipType.OUTLINED, - PrezelChipSize.REGULAR to PrezelChipType.FILLED, - PrezelChipSize.REGULAR to PrezelChipType.OUTLINED, + IconChipSize.SMALL to IconChipType.FILLED, + IconChipSize.SMALL to IconChipType.OUTLINED, + IconChipSize.REGULAR to IconChipType.FILLED, + IconChipSize.REGULAR to IconChipType.OUTLINED, ) private fun iconPreviewCases(transform: IconChipPreviewCase.() -> IconChipPreviewCase = { this }) = @@ -78,19 +99,15 @@ private fun PrezelIconChipPreview() { ), PreviewMatrixRow( label = "State / Active", - values = iconPreviewCases { copy(state = PrezelChipState.ACTIVE) }, + values = iconPreviewCases { copy(state = IconChipState.ACTIVE) }, ), PreviewMatrixRow( label = "State / Disabled", - values = iconPreviewCases { copy(state = PrezelChipState.DISABLED) }, + values = iconPreviewCases { copy(state = IconChipState.DISABLED) }, ), PreviewMatrixRow( label = "Status / Bad", - values = iconPreviewCases { copy(status = PrezelChipStatus.BAD) }, - ), - PreviewMatrixRow( - label = "Status / Warning", - values = iconPreviewCases { copy(status = PrezelChipStatus.WARNING) }, + values = iconPreviewCases { copy(status = IconChipStatus.BAD) }, ), ), ) { previewCase -> diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/iconChip/PrezelIconChipDefaults.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/iconChip/PrezelIconChipDefaults.kt new file mode 100644 index 00000000..ff461aa4 --- /dev/null +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/iconChip/PrezelIconChipDefaults.kt @@ -0,0 +1,134 @@ +package com.team.prezel.core.designsystem.component.chip.iconChip + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.team.prezel.core.designsystem.component.chip.base.PrezelChipColors +import com.team.prezel.core.designsystem.component.chip.base.PrezelChipStyle +import com.team.prezel.core.designsystem.component.chip.base.iconChipShape +import com.team.prezel.core.designsystem.component.chip.base.iconChipTextStyle +import com.team.prezel.core.designsystem.theme.PrezelTheme + +object PrezelIconChipDefaults { + @Composable + internal fun getDefault( + type: IconChipType, + size: IconChipSize, + state: IconChipState, + status: IconChipStatus, + ): PrezelChipStyle = + PrezelChipStyle( + shape = iconChipShape(size = size), + textStyle = iconChipTextStyle(size = size), + colors = iconChipColors(type = type, state = state, status = status), + contentPadding = iconContentPadding(size = size), + iconTextSpacing = 0.dp, + iconSize = iconSize(size = size), + ) + + @Composable + private fun iconSize(size: IconChipSize): Dp = + when (size) { + IconChipSize.SMALL -> 12.dp + IconChipSize.REGULAR -> 14.dp + } + + @Composable + private fun iconChipColors( + type: IconChipType, + state: IconChipState, + status: IconChipStatus, + ): PrezelChipColors { + val contentAccentColor = resolveIconChipStatusContentColor(status = status) + val iconColor = resolveIconChipContentColor( + type = type, + state = state, + contentAccentColor = contentAccentColor, + ) + + return PrezelChipColors( + containerColor = resolveIconChipContainerColor( + type = type, + state = state, + status = status, + ), + iconColor = iconColor, + textColor = iconColor, + borderColor = if (type == IconChipType.OUTLINED) { + resolveIconChipBorderColor( + state = state, + contentAccentColor = contentAccentColor, + ) + } else { + null + }, + ) + } + + @Composable + private fun iconContentPadding(size: IconChipSize): PaddingValues { + val all = when (size) { + IconChipSize.SMALL -> PrezelTheme.spacing.V6 + IconChipSize.REGULAR -> PrezelTheme.spacing.V8 + } + + return PaddingValues(all = all) + } + + @Composable + private fun resolveIconChipContainerColor( + type: IconChipType, + state: IconChipState, + status: IconChipStatus, + ): Color { + if (state == IconChipState.DISABLED) return PrezelTheme.colors.bgMedium + if (type == IconChipType.OUTLINED) return Color.Transparent + + return when (state) { + IconChipState.ACTIVE -> PrezelTheme.colors.interactiveXSmall + IconChipState.DEFAULT -> { + when (status) { + IconChipStatus.DEFAULT -> PrezelTheme.colors.bgLarge + IconChipStatus.BAD -> PrezelTheme.colors.feedbackBadSmall + } + } + + IconChipState.DISABLED -> error("Handled above") + } + } + + @Composable + private fun resolveIconChipContentColor( + type: IconChipType, + state: IconChipState, + contentAccentColor: Color?, + ): Color { + if (state == IconChipState.DISABLED) return PrezelTheme.colors.iconDisabled + if (contentAccentColor != null) return contentAccentColor + if (state == IconChipState.ACTIVE) return PrezelTheme.colors.interactiveRegular + if (type == IconChipType.FILLED) return PrezelTheme.colors.iconMedium + + return PrezelTheme.colors.iconRegular + } + + @Composable + private fun resolveIconChipBorderColor( + state: IconChipState, + contentAccentColor: Color?, + ): Color { + if (state == IconChipState.DISABLED) return PrezelTheme.colors.borderRegular + if (contentAccentColor != null) return contentAccentColor + if (state == IconChipState.ACTIVE) return PrezelTheme.colors.interactiveRegular + + return PrezelTheme.colors.borderMedium + } + + @Composable + private fun resolveIconChipStatusContentColor(status: IconChipStatus): Color? = + when (status) { + IconChipStatus.DEFAULT -> null + IconChipStatus.BAD -> PrezelTheme.colors.feedbackBadRegular + } +} diff --git a/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryPresentationCard.kt b/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryPresentationCard.kt index c3ad38b6..4122a3f7 100644 --- a/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryPresentationCard.kt +++ b/Prezel/feature/history/impl/src/main/java/com/team/prezel/feature/history/impl/component/HistoryPresentationCard.kt @@ -18,12 +18,12 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.team.prezel.core.designsystem.component.base.PrezelTouchArea -import com.team.prezel.core.designsystem.component.chip.PrezelChip -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipHierarchy -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipSize -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipState -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipStatus -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipType +import com.team.prezel.core.designsystem.component.chip.chip.ChipHierarchy +import com.team.prezel.core.designsystem.component.chip.chip.ChipSize +import com.team.prezel.core.designsystem.component.chip.chip.ChipState +import com.team.prezel.core.designsystem.component.chip.chip.ChipStatus +import com.team.prezel.core.designsystem.component.chip.chip.ChipType +import com.team.prezel.core.designsystem.component.chip.chip.PrezelChip import com.team.prezel.core.designsystem.icon.PrezelIcons import com.team.prezel.core.designsystem.preview.BasicPreview import com.team.prezel.core.designsystem.theme.PrezelTheme @@ -129,10 +129,10 @@ private fun HistoryCategoryChip( text = text, modifier = modifier, iconResId = PrezelIcons.Blank, - type = PrezelChipType.FILLED, - size = PrezelChipSize.SMALL, - state = PrezelChipState.ACTIVE, - hierarchy = PrezelChipHierarchy.PRIMARY, + type = ChipType.FILLED, + size = ChipSize.SMALL, + state = ChipState.ACTIVE, + hierarchy = ChipHierarchy.PRIMARY, ) } @@ -144,9 +144,9 @@ private fun HistoryMetaChip( PrezelChip( text = text, modifier = modifier, - type = PrezelChipType.OUTLINED, - size = PrezelChipSize.SMALL, - status = PrezelChipStatus.DEFAULT, + type = ChipType.OUTLINED, + size = ChipSize.SMALL, + status = ChipStatus.DEFAULT, ) } diff --git a/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/component/title/PresentationHero.kt b/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/component/title/PresentationHero.kt index 984ede8c..f0be1bdc 100644 --- a/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/component/title/PresentationHero.kt +++ b/Prezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/component/title/PresentationHero.kt @@ -10,9 +10,9 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import com.team.prezel.core.designsystem.component.chip.PrezelChip -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipSize -import com.team.prezel.core.designsystem.component.chip.config.PrezelChipType +import com.team.prezel.core.designsystem.component.chip.chip.ChipSize +import com.team.prezel.core.designsystem.component.chip.chip.ChipType +import com.team.prezel.core.designsystem.component.chip.chip.PrezelChip import com.team.prezel.core.designsystem.preview.BasicPreview import com.team.prezel.core.designsystem.theme.PrezelTheme import com.team.prezel.core.model.presentation.Category @@ -34,8 +34,8 @@ internal fun PresentationHero( ) { PrezelChip( text = stringResource(id = presentation.category.labelResId()), - type = PrezelChipType.OUTLINED, - size = PrezelChipSize.SMALL, + type = ChipType.OUTLINED, + size = ChipSize.SMALL, ) Spacer(modifier = Modifier.weight(1f)) From 905df15714364f6c9295f5458daaa0f62a7338d0 Mon Sep 17 00:00:00 2001 From: moondev03 Date: Sun, 10 May 2026 01:20:34 +0900 Subject: [PATCH 10/11] =?UTF-8?q?refactor:=20Chip=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EB=B0=B0=EA=B2=BD=EC=83=89=20=EA=B2=B0?= =?UTF-8?q?=EC=A0=95=20=EB=A1=9C=EC=A7=81=20=EB=8B=A8=EC=88=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * **refactor: PrezelChip 배경색 중복 조건문 제거** * `PrezelChipDefaults`에서 state, status, accent가 기본값이 아닐 경우 일괄적으로 `bgLarge` 색상을 반환하던 조건 블록을 제거했습니다. * 특정 상태값에 의존하는 대신 hierarchy(PRIMARY, SECONDARY 등) 설정에 따라 적절한 배경색이 적용되도록 로직을 개선했습니다. --- .../designsystem/component/chip/chip/PrezelChipDefaults.kt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/chip/PrezelChipDefaults.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/chip/PrezelChipDefaults.kt index 26c60641..30f5cfb4 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/chip/PrezelChipDefaults.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/chip/PrezelChipDefaults.kt @@ -142,13 +142,6 @@ object PrezelChipDefaults { if (state == ChipState.ACTIVE) return PrezelTheme.colors.interactiveXSmall if (type == ChipType.OUTLINED) return PrezelTheme.colors.bgRegular - if ( - state != ChipState.DEFAULT || - status != ChipStatus.DEFAULT || - accent != ChipAccent.DEFAULT - ) { - return PrezelTheme.colors.bgLarge - } return when (hierarchy) { ChipHierarchy.PRIMARY -> PrezelTheme.colors.bgLarge From ec0845f3a9648cd8861a14667dde3536e507d6b5 Mon Sep 17 00:00:00 2001 From: moondev03 Date: Sun, 10 May 2026 01:22:01 +0900 Subject: [PATCH 11/11] =?UTF-8?q?feat:=20PrezelIconChip=20=EB=82=B4=20cont?= =?UTF-8?q?entDescription=20=EC=A7=80=EC=9B=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * **feat: `PrezelIconChip` 컴포저블에 접근성 설명을 위한 파라미터 추가** * `contentDescription: String?` 파라미터를 추가하여 아이콘 칩에 대한 접근성 설명을 제공할 수 있도록 개선했습니다. * 전달된 `contentDescription`이 있는 경우 `Modifier.semantics`를 통해 세맨틱 정보를 설정하도록 로직을 수정했습니다. --- .../component/chip/iconChip/PrezelIconChip.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/iconChip/PrezelIconChip.kt b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/iconChip/PrezelIconChip.kt index 34b1f0a3..1d71c068 100644 --- a/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/iconChip/PrezelIconChip.kt +++ b/Prezel/core/designsystem/src/main/java/com/team/prezel/core/designsystem/component/chip/iconChip/PrezelIconChip.kt @@ -4,6 +4,8 @@ import androidx.annotation.DrawableRes import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.ui.Modifier +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics import com.team.prezel.core.designsystem.component.chip.base.PrezelChipLayout import com.team.prezel.core.designsystem.icon.PrezelIcons import com.team.prezel.core.designsystem.preview.LargeDevicePreview @@ -41,13 +43,18 @@ enum class IconChipStatus { fun PrezelIconChip( @DrawableRes iconResId: Int, modifier: Modifier = Modifier, + contentDescription: String? = null, type: IconChipType = IconChipType.FILLED, size: IconChipSize = IconChipSize.REGULAR, state: IconChipState = IconChipState.DEFAULT, status: IconChipStatus = IconChipStatus.DEFAULT, ) { PrezelChipLayout( - modifier = modifier, + modifier = if (contentDescription != null) { + modifier.semantics { this.contentDescription = contentDescription } + } else { + modifier + }, text = null, iconResId = iconResId, style = PrezelIconChipDefaults.getDefault(