diff --git a/Projects/Shared/DesignSystem/Example/Sources/Component/ButtonDetailView.swift b/Projects/Shared/DesignSystem/Example/Sources/Component/ButtonDetailView.swift index ca91c33..d6ba72d 100644 --- a/Projects/Shared/DesignSystem/Example/Sources/Component/ButtonDetailView.swift +++ b/Projects/Shared/DesignSystem/Example/Sources/Component/ButtonDetailView.swift @@ -255,6 +255,67 @@ struct ButtonDetailView: View { .buttonStyle(.round(level: .secondary)) } } + + VStack(spacing: 40) { + Text("Select") + .font(.title) + HStack { + Button( + title: "Title", + subtitle: "subTitle", + leftIcon: Image(systemName: "left"), + rightIcon: Image(systemName: "right"), + action: { + /*action*/ + } + ) + .buttonStyle(.select(isSelected: true)) + Button( + title: "Title", + subtitle: "subTitle", + leftIcon: Image(systemName: "left"), + rightIcon: Image(systemName: "right"), + action: { /*action*/ } + ) + .buttonStyle(.select(isSelected: false)) + Button( + title: "Title", + subtitle: "subTitle", + leftIcon: Image(systemName: "left"), + rightIcon: Image(systemName: "right"), + action: { /*action*/ } + ) + .buttonStyle(.select(isSelected: false)) + .disabled(true) + } + } + .padding(.horizontal, 20) + + VStack(spacing: 40) { + Text("Select List") + .font(.title) + VStack { + Button( + title: "Title", + subtitle: "subTitle", + leftIcon: Image(systemName: "left"), + rightIcon: Image(systemName: "right"), + action: { + /*action*/ + } + ) + .buttonStyle(.selectList(isSelected: true)) + Button( + title: "Title", + subtitle: "subTitle", + leftIcon: Image(systemName: "left"), + rightIcon: Image(systemName: "right"), + action: { /*action*/ } + ) + .buttonStyle(.selectList(isSelected: false)) + } + } + .padding(.horizontal, 20) } } } diff --git a/Projects/Shared/DesignSystem/Sources/Component/Button/Box/BoxButtonStyle.swift b/Projects/Shared/DesignSystem/Sources/Component/Button/Box/BoxButtonStyle.swift index 4f109b8..51a6e8d 100644 --- a/Projects/Shared/DesignSystem/Sources/Component/Button/Box/BoxButtonStyle.swift +++ b/Projects/Shared/DesignSystem/Sources/Component/Button/Box/BoxButtonStyle.swift @@ -37,7 +37,6 @@ public struct BoxButtonStyle: ButtonStyle { .foregroundStyle( getForegroundColor(isPressed: configuration.isPressed) ) - .labelStyle(DefaultBarButtonLabelStyle()) .barButtonDetailStyle(DefaultBarButtonDetailStyle()) } diff --git a/Projects/Shared/DesignSystem/Sources/Component/Button/BarButtonDetail.swift b/Projects/Shared/DesignSystem/Sources/Component/Button/Detail/BarButtonDetail.swift similarity index 95% rename from Projects/Shared/DesignSystem/Sources/Component/Button/BarButtonDetail.swift rename to Projects/Shared/DesignSystem/Sources/Component/Button/Detail/BarButtonDetail.swift index 5ac3389..a0a7cb0 100644 --- a/Projects/Shared/DesignSystem/Sources/Component/Button/BarButtonDetail.swift +++ b/Projects/Shared/DesignSystem/Sources/Component/Button/Detail/BarButtonDetail.swift @@ -125,9 +125,3 @@ struct DefaultBarButtonDetailStyle: BarButtonDetailStyle { } } } - -struct DefaultBarButtonLabelStyle: LabelStyle { - func makeBody(configuration: Configuration) -> some View { - configuration.title - } -} diff --git a/Projects/Shared/DesignSystem/Sources/Component/Button/ButtonHuggingPriorityHorizontal.swift b/Projects/Shared/DesignSystem/Sources/Component/Button/Detail/ButtonHuggingPriorityHorizontal.swift similarity index 100% rename from Projects/Shared/DesignSystem/Sources/Component/Button/ButtonHuggingPriorityHorizontal.swift rename to Projects/Shared/DesignSystem/Sources/Component/Button/Detail/ButtonHuggingPriorityHorizontal.swift diff --git a/Projects/Shared/DesignSystem/Sources/Component/Button/Detail/SelectButtonDetail.swift b/Projects/Shared/DesignSystem/Sources/Component/Button/Detail/SelectButtonDetail.swift new file mode 100644 index 0000000..7e0f6a3 --- /dev/null +++ b/Projects/Shared/DesignSystem/Sources/Component/Button/Detail/SelectButtonDetail.swift @@ -0,0 +1,146 @@ +// +// SelectButtonDetail.swift +// DesignSystem +// +// Created by devMinseok on 8/13/24. +// Copyright © 2024 PomoNyang. All rights reserved. +// + +import SwiftUI + +extension Button where Label == SelectButtonDetail { + public init( + title: LocalizedStringKey, + subtitle: LocalizedStringKey, + leftIcon: Image? = nil, + rightIcon: Image? = nil, + action: @escaping () -> Void + ) { + self.init(action: action) { + SelectButtonDetail { + Text(title) + } subtitle: { + Text(subtitle) + } leftIcon: { + leftIcon + } rightIcon: { + rightIcon + } + } + } +} + +public struct SelectButtonDetail: View { + @Environment(\.selectButtonDetailStyle) private var style + private let title: Title + private let subtitle: Subtitle + private let leftIcon: LeftIcon + private let rightIcon: RightIcon + + init( + @ViewBuilder title: () -> Title, + @ViewBuilder subtitle: () -> Subtitle, + @ViewBuilder leftIcon: () -> LeftIcon, + @ViewBuilder rightIcon: () -> RightIcon + ) { + self.title = title() + self.subtitle = subtitle() + self.leftIcon = leftIcon() + self.rightIcon = rightIcon() + } + + public var body: some View { + let configuration = SelectButtonDetailConfiguration( + title: title, + subtitle: subtitle, + leftIcon: leftIcon, + rightIcon: rightIcon + ) + AnyView(style.resolve(configuration: configuration)) + } +} + +struct SelectButtonDetailConfiguration { + struct Title: View { + let body: AnyView + } + + struct Subtitle: View { + let body: AnyView + } + + struct LeftIcon: View { + let body: AnyView + } + + struct RightIcon: View { + let body: AnyView + } + + let title: Title + let subtitle: Subtitle + let leftIcon: LeftIcon + let rightIcon: RightIcon + + fileprivate init( + title: some View, + subtitle: some View, + leftIcon: some View, + rightIcon: some View + ) { + self.title = Title(body: AnyView(title)) + self.subtitle = Subtitle(body: AnyView(subtitle)) + self.leftIcon = LeftIcon(body: AnyView(leftIcon)) + self.rightIcon = RightIcon(body: AnyView(rightIcon)) + } +} + +protocol SelectButtonDetailStyle: DynamicProperty { + typealias Configuration = SelectButtonDetailConfiguration + associatedtype Body: View + + @ViewBuilder func makeBody(configuration: Configuration) -> Body +} + +extension SelectButtonDetailStyle { + fileprivate func resolve(configuration: Configuration) -> some View { + SelectButtonResolvedDetailStyle(style: self, configuration: configuration) + } +} + +private struct SelectButtonResolvedDetailStyle: View { + let style: Style + let configuration: Style.Configuration + + var body: some View { + style.makeBody(configuration: configuration) + } +} + +struct SelectButtonDetailStyleKey: EnvironmentKey { + static var defaultValue: any SelectButtonDetailStyle = DefaultSelectButtonDetailStyle() +} + +extension EnvironmentValues { + fileprivate var selectButtonDetailStyle: any SelectButtonDetailStyle { + get { self[SelectButtonDetailStyleKey.self] } + set { self[SelectButtonDetailStyleKey.self] = newValue } + } +} + +extension View { + func selectButtonDetailStyle(_ style: some SelectButtonDetailStyle) -> some View { + environment(\.selectButtonDetailStyle, style) + } +} + +struct DefaultSelectButtonDetailStyle: SelectButtonDetailStyle { + func makeBody(configuration: Configuration) -> some View { + HStack { + configuration.title + configuration.subtitle + configuration.leftIcon + configuration.rightIcon + } + } +} diff --git a/Projects/Shared/DesignSystem/Sources/Component/Button/SingleIconButtonDetail.swift b/Projects/Shared/DesignSystem/Sources/Component/Button/Detail/SingleIconButtonDetail.swift similarity index 94% rename from Projects/Shared/DesignSystem/Sources/Component/Button/SingleIconButtonDetail.swift rename to Projects/Shared/DesignSystem/Sources/Component/Button/Detail/SingleIconButtonDetail.swift index 5b1d175..a573c7c 100644 --- a/Projects/Shared/DesignSystem/Sources/Component/Button/SingleIconButtonDetail.swift +++ b/Projects/Shared/DesignSystem/Sources/Component/Button/Detail/SingleIconButtonDetail.swift @@ -93,9 +93,3 @@ struct DefaultSingleIconButtonDetailStyle: SingleIconButtonDetailStyle { configuration.icon } } - -struct SingleIconButtonLabelStyle: LabelStyle { - func makeBody(configuration: Configuration) -> some View { - configuration.title - } -} diff --git a/Projects/Shared/DesignSystem/Sources/Component/Button/Icon/IconButtonStyle.swift b/Projects/Shared/DesignSystem/Sources/Component/Button/Icon/IconButtonStyle.swift index 2f91275..aee5a50 100644 --- a/Projects/Shared/DesignSystem/Sources/Component/Button/Icon/IconButtonStyle.swift +++ b/Projects/Shared/DesignSystem/Sources/Component/Button/Icon/IconButtonStyle.swift @@ -31,7 +31,6 @@ public struct IconButtonStyle: ButtonStyle { .foregroundColor( getForegroundColor(isFilled: isFilled) ) - .labelStyle(SingleIconButtonLabelStyle()) .singleIconButtonDetailStyle(DefaultSingleIconButtonDetailStyle()) .opacity(isEnabled ? 1 : 0.6) } diff --git a/Projects/Shared/DesignSystem/Sources/Component/Button/Round/RoundButtonStyle.swift b/Projects/Shared/DesignSystem/Sources/Component/Button/Round/RoundButtonStyle.swift index cca4731..f7af0b3 100644 --- a/Projects/Shared/DesignSystem/Sources/Component/Button/Round/RoundButtonStyle.swift +++ b/Projects/Shared/DesignSystem/Sources/Component/Button/Round/RoundButtonStyle.swift @@ -23,7 +23,6 @@ public struct RoundButtonStyle: ButtonStyle { in: RoundedRectangle(cornerRadius: 44) ) .foregroundColor(Global.Color.white) - .labelStyle(SingleIconButtonLabelStyle()) .singleIconButtonDetailStyle(DefaultSingleIconButtonDetailStyle()) } diff --git a/Projects/Shared/DesignSystem/Sources/Component/Button/Select/SelectButtonStyle.swift b/Projects/Shared/DesignSystem/Sources/Component/Button/Select/SelectButtonStyle.swift new file mode 100644 index 0000000..68e88e5 --- /dev/null +++ b/Projects/Shared/DesignSystem/Sources/Component/Button/Select/SelectButtonStyle.swift @@ -0,0 +1,91 @@ +// +// SelectButtonStyle.swift +// DesignSystem +// +// Created by devMinseok on 8/13/24. +// Copyright © 2024 PomoNyang. All rights reserved. +// + +import SwiftUI + +public struct SelectButtonStyle: ButtonStyle { + @Environment(\.isEnabled) var isEnabled + let isSelected: Bool + + public init(isSelected: Bool) { + self.isSelected = isSelected + } + + public func makeBody(configuration: Configuration) -> some View { + configuration.label + .selectButtonDetailStyle( + SelectButtonDetailStyleImpl( + isSelected: isSelected, + isDisabled: !isEnabled + ) + ) + } +} + +extension ButtonStyle where Self == SelectButtonStyle { + public static func select( + isSelected: Bool + ) -> Self { + return SelectButtonStyle(isSelected: isSelected) + } +} + +struct SelectButtonDetailStyleImpl: SelectButtonDetailStyle { + let isSelected: Bool + let isDisabled: Bool + + func makeBody(configuration: Configuration) -> some View { + VStack(spacing: Alias.Spacing.xSmall) { + HStack(spacing: Alias.Spacing.xSmall) { + configuration.leftIcon + configuration.subtitle + .font(Typography.subBodyR) + .foregroundStyle(getSubtitleForegourndColor()) + configuration.rightIcon + } + configuration.title + .font(Typography.header5) + .foregroundStyle(getTitleForegourndColor()) + } + .padding(.vertical, 16) + .frame(maxWidth: .infinity) + .background( + RoundedRectangle(cornerRadius: Alias.BorderRadius.small) + .fill(getBackgroundColor()) + .strokeBorder(isSelected ? Alias.Color.Background.accent1 : .clear, lineWidth: 1) + ) + } + + func getTitleForegourndColor() -> Color { + if isDisabled { + return Alias.Color.Text.disabled + } else { + if isSelected { + return Alias.Color.Text.primary + } else { + return Alias.Color.Text.secondary + } + } + } + + func getSubtitleForegourndColor() -> Color { + if isDisabled { + return Alias.Color.Text.disabled + } else { + return Alias.Color.Text.tertiary + } + } + + func getBackgroundColor() -> Color { + if isSelected { + return Alias.Color.Background.accent2 + } else { + return Alias.Color.Background.secondary + } + } +} diff --git a/Projects/Shared/DesignSystem/Sources/Component/Button/Select/SelectListButtonStyle.swift b/Projects/Shared/DesignSystem/Sources/Component/Button/Select/SelectListButtonStyle.swift new file mode 100644 index 0000000..2ef7787 --- /dev/null +++ b/Projects/Shared/DesignSystem/Sources/Component/Button/Select/SelectListButtonStyle.swift @@ -0,0 +1,63 @@ +// +// SelectListButtonStyle.swift +// DesignSystem +// +// Created by devMinseok on 8/13/24. +// Copyright © 2024 PomoNyang. All rights reserved. +// + +import SwiftUI + +public struct SelectListButtonStyle: ButtonStyle { + let isSelected: Bool + + public init(isSelected: Bool) { + self.isSelected = isSelected + } + + public func makeBody(configuration: Configuration) -> some View { + configuration.label + .selectButtonDetailStyle(SelectListButtonDetailStyleImpl(isSelected: isSelected)) + } +} + +extension ButtonStyle where Self == SelectListButtonStyle { + public static func selectList( + isSelected: Bool + ) -> Self { + return SelectListButtonStyle(isSelected: isSelected) + } +} + +struct SelectListButtonDetailStyleImpl: SelectButtonDetailStyle { + let isSelected: Bool + + func makeBody(configuration: Configuration) -> some View { + HStack(spacing: Alias.Spacing.medium) { + HStack(spacing: Alias.Spacing.small) { + configuration.leftIcon + configuration.title + .font(Typography.bodySB) + .foregroundStyle(Alias.Color.Text.primary) + } + configuration.subtitle + .font(Typography.subBodyR) + .foregroundStyle(Alias.Color.Text.tertiary) + } + .frame(maxWidth: .infinity, alignment: .leading) + .padding(Alias.Spacing.xLarge) + .background( + RoundedRectangle(cornerRadius: Alias.BorderRadius.small) + .fill(getBackgroundColor()) + .strokeBorder(isSelected ? Alias.Color.Background.accent1 : .clear, lineWidth: 1) + ) + } + + func getBackgroundColor() -> Color { + if isSelected { + return Alias.Color.Background.accent2 + } else { + return Alias.Color.Background.primary + } + } +} diff --git a/Projects/Shared/DesignSystem/Sources/Component/Button/Text/TextButtonStyle.swift b/Projects/Shared/DesignSystem/Sources/Component/Button/Text/TextButtonStyle.swift index 4befd52..8577f3f 100644 --- a/Projects/Shared/DesignSystem/Sources/Component/Button/Text/TextButtonStyle.swift +++ b/Projects/Shared/DesignSystem/Sources/Component/Button/Text/TextButtonStyle.swift @@ -33,7 +33,6 @@ public struct TextButtonStyle: ButtonStyle { .foregroundStyle( getForegroundColor(isPressed: configuration.isPressed) ) - .labelStyle(DefaultBarButtonLabelStyle()) .barButtonDetailStyle(DefaultBarButtonDetailStyle()) }