From 82b147d1bafe74554c08023e1e7acd579c0608cb Mon Sep 17 00:00:00 2001 From: Vladimir Kaltyrin Date: Tue, 14 Jan 2025 20:28:02 +0300 Subject: [PATCH] feat: unified indicator API for textfield --- .swiftlint.yml | 2 + .../SDDSTextArea/SDDSTextArea+Preview.swift | 10 +- .../SDDSTextAreaAppearance+Extensions.swift | 9 +- .../SDDSTextArea/SDDSTextAreaSize.swift | 175 ++++++++++++------ .../ChipAppearance+SDDSTextField.swift | 8 +- .../SDDSTextField/SDDSTextField+Preview.swift | 14 +- .../SDDSTextField/TextFieldDefaultSize.swift | 173 +++++++++++------ .../SDDSTextArea/SDDSTextArea.swift | 84 ++++----- .../TextAreaSizeConfiguration.swift | 4 +- .../SDDSTextField/SDDSTextField.swift | 93 ++++------ .../TextFieldSizeConfiguration.swift | 4 +- ...ButtonSize+ButtonSizeConfiguration.stencil | 2 +- ...ButtonSize+ButtonSizeConfiguration.stencil | 2 +- 13 files changed, 323 insertions(+), 257 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index bbe3d4426..153b37f64 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -9,6 +9,8 @@ disabled_rules: # rule identifiers turned on by default to exclude from running - file_length - empty_count - type_body_length + - function_body_length + - cyclomatic_complexity opt_in_rules: # some rules are turned off by default, so you need to opt-in - empty_count # find all the available rules by running: `swiftlint rules` diff --git a/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextArea/SDDSTextArea+Preview.swift b/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextArea/SDDSTextArea+Preview.swift index 806507231..49b23266c 100644 --- a/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextArea/SDDSTextArea+Preview.swift +++ b/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextArea/SDDSTextArea+Preview.swift @@ -9,7 +9,7 @@ struct SDDSTextAreaPreview: PreviewProvider { static var previews: some View { let chips = (1...12).map { index in ChipData( - title: "Label", + title: "ChipTitle", isEnabled: true, iconImage: nil, buttonImage: Image.image("textFieldChipIcon"), @@ -21,7 +21,7 @@ struct SDDSTextAreaPreview: PreviewProvider { return Group { SDDSTextArea( - value: .constant(.single("hi")), + value: .constant(.single("Value")), title: "Title", optionalTitle: "optional", placeholder: "Placeholder", @@ -29,13 +29,13 @@ struct SDDSTextAreaPreview: PreviewProvider { counter: "counter", disabled: false, readOnly: false, - style: .default, + style: .warning, labelPlacement: .inner, - required: true, + required: false, requiredPlacement: .left, dynamicHeight: true, appearance: .defaultAppearance, - size: SDDSTextAreaSize.large, + size: SDDSTextAreaSize.medium, chipGroupSize: SDDSTextAreaSize.large.chipGroupSize, layout: .clear, iconActionViewProvider: ViewProvider(iconActionView) diff --git a/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextArea/SDDSTextAreaAppearance+Extensions.swift b/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextArea/SDDSTextAreaAppearance+Extensions.swift index 8503d2830..4aa1d9ba8 100644 --- a/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextArea/SDDSTextAreaAppearance+Extensions.swift +++ b/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextArea/SDDSTextAreaAppearance+Extensions.swift @@ -124,11 +124,10 @@ extension TextAreaTypography { public extension ChipAppearance { static var textArea: ChipAppearance { ChipAppearance( - size: ZeroChipSize(), - titleColor: .surfaceInverseSolidPrimary.withOpacity(0.96), - titleTypography: ChipTextAreaTypography.text, - imageTintColor: Color.clear.token, - buttonTintColor: Color.clear.token, + titleColor: .textDefaultPrimary, + titleTypography: ChipTextFieldTypography.text, + imageTintColor: .textDefaultPrimary, + buttonTintColor: .textDefaultPrimary, backgroundColor: .surfaceDefaultTransparentSecondary, disabledAlpha: 0.5 ) diff --git a/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextArea/SDDSTextAreaSize.swift b/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextArea/SDDSTextAreaSize.swift index fadbdb7f3..7e72205d7 100644 --- a/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextArea/SDDSTextAreaSize.swift +++ b/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextArea/SDDSTextAreaSize.swift @@ -101,6 +101,10 @@ public enum SDDSTextAreaSize: String, TextAreaSizeConfiguration { public var captionBottomPadding: CGFloat { 4 } + + public var optionalPadding: CGFloat { + 4 + } public var textInputPaddings: EdgeInsets { switch self { @@ -162,65 +166,122 @@ public enum SDDSTextAreaSize: String, TextAreaSizeConfiguration { } } - public func indicatorYOffset(labelPlacement: TextAreaLabelPlacement, requiredPlacement: TextAreaRequiredPlacement, layout: TextAreaLayout) -> CGFloat { - switch (self, labelPlacement, requiredPlacement, layout) { - case (.large, .outer, .left, _): - return 7 - case (.medium, .outer, .left, _): - return 6 - case (.small, .outer, .left, _): - return 5 - case (.extraSmall, .outer, .left, _): - return 4 - case (.large, .inner, .right, .clear), (.large, .inner, .left, .clear): - return 25 - case (.medium, .inner, .right, .clear), (.medium, .inner, .left, .clear): - return 22 - case (.small, .inner, .right, .clear), (.small, .inner, .left, .clear): - return 19 - case (.extraSmall, .inner, .right, .clear), (.extraSmall, .inner, .left, .clear): - return 12 - case (.large, .none, .left, .clear), (.large, .none, .right, .clear): - return 20 - case (.medium, .none, .left, .clear), (.medium, .none, .right, .clear): - return 19 - case (.small, .none, .left, .clear), (.small, .none, .right, .clear): - return 18 - case (.extraSmall, .none, .left, .clear), (.extraSmall, .none, .right, .clear): - return 17 - case (.large, .outer, .right, _), (.medium, .outer, .right, _), (.small, .outer, .right, _): - return -2 - case (.extraSmall, .outer, .right, _): - return 0 - default: - break - } - - return 0 - } - - public func indicatorPadding(labelPlacement: TextAreaLabelPlacement, requiredPlacement: TextAreaRequiredPlacement, layout: TextAreaLayout) -> CGFloat { - switch (self, labelPlacement, requiredPlacement, layout) { - case (.large, .outer, .left, _), (.medium, .outer, .left, _): - return 6 - case (.small, .outer, .left, _), (.extraSmall, .outer, .left, _): - return 4 - case (.large, .outer, .right, _), (.medium, .outer, .right, .default), (.small, .outer, .right, _), (.extraSmall, .outer, .right, _): - return 4 - case (.large, .inner, .left, .clear), (.medium, .inner, .left, .clear): - return 6 - case (.small, .inner, .left, .clear), (.extraSmall, .inner, .left, .clear): - return 4 - case (.large, .inner, .right, .clear), (.medium, .inner, .right, .clear), (.small, .inner, .right, .clear), (.extraSmall, .inner, .right, .clear): - return 4 - case (.large, .none, .right, .clear), (.medium, .none, .right, .clear): - return 6 - case (.small, .none, .right, .clear), (.extraSmall, .none, .right, .clear): - return 4 - default: - return 6 + public func indicatorOffset(labelPlacement: TextAreaLabelPlacement, requiredPlacement: TextAreaRequiredPlacement, layout: TextAreaLayout) -> CGPoint { + switch layout { + case .default: + switch labelPlacement { + case .none: + return .zero + case .inner: + return .zero + case .outer: + switch requiredPlacement { + case .left: + switch self { + case .large: + return CGPoint(x: 6, y: 8) + case .medium: + return CGPoint(x: 6, y: 7) + case .small: + return CGPoint(x: 4, y: 6) + case .extraSmall: + return CGPoint(x: 4, y: 4) + } + case .right: + switch self { + case .large: + return CGPoint(x: 4, y: 4) + case .medium: + return CGPoint(x: 4, y: 4) + case .small: + return CGPoint(x: 4, y: 4) + case .extraSmall: + return CGPoint(x: 4, y: 2) + } + } + } + case .clear: + switch labelPlacement { + case .none: + switch requiredPlacement { + case .left: + switch self { + case .large: + return CGPoint(x: 6, y: 24) + case .medium: + return CGPoint(x: 6, y: 20) + case .small: + return CGPoint(x: 6, y: 17) + case .extraSmall: + return CGPoint(x: 4, y: 13) + } + case .right: + switch self { + case .large: + return CGPoint(x: 4, y: 24) + case .medium: + return CGPoint(x: 4, y: 20) + case .small: + return CGPoint(x: 6, y: 17) + case .extraSmall: + return CGPoint(x: 4, y: 13) + } + } + case .inner: + switch requiredPlacement { + case .left: + switch self { + case .large: + return CGPoint(x: 6, y: 24) + case .medium: + return CGPoint(x: 6, y: 20) + case .small: + return CGPoint(x: 6, y: 17) + case .extraSmall: + return CGPoint(x: 4, y: 13) + } + case .right: + switch self { + case .large: + return CGPoint(x: 4, y: 24) + case .medium: + return CGPoint(x: 4, y: 20) + case .small: + return CGPoint(x: 6, y: 17) + case .extraSmall: + return CGPoint(x: 4, y: 13) + } + } + case .outer: + switch requiredPlacement { + case .left: + switch self { + case .large: + return CGPoint(x: 6, y: 8) + case .medium: + return CGPoint(x: 6, y: 7) + case .small: + return CGPoint(x: 4, y: 6) + case .extraSmall: + return CGPoint(x: 4, y: 4) + } + case .right: + switch self { + case .large: + return CGPoint(x: 4, y: 4) + case .medium: + return CGPoint(x: 4, y: 4) + case .small: + return CGPoint(x: 4, y: 4) + case .extraSmall: + return CGPoint(x: 4, y: 2) + } + } + } } } + + public func fieldHeight(layout: TextAreaLayout) -> CGFloat { switch layout { case .default: diff --git a/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextField/ChipAppearance+SDDSTextField.swift b/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextField/ChipAppearance+SDDSTextField.swift index f6321cea8..056efbe3c 100644 --- a/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextField/ChipAppearance+SDDSTextField.swift +++ b/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextField/ChipAppearance+SDDSTextField.swift @@ -6,11 +6,11 @@ import SDDSComponents public extension ChipAppearance { static var textField: ChipAppearance { ChipAppearance( - titleColor: .surfaceInverseSolidPrimary.withOpacity(0.96), + titleColor: .textDefaultPrimary, titleTypography: ChipTextFieldTypography.text, - imageTintColor: ColorToken.textDefaultPrimary, - buttonTintColor: ColorToken.textDefaultPrimary, - backgroundColor: .surfaceDefaultSolidPrimary, + imageTintColor: .textDefaultPrimary, + buttonTintColor: .textDefaultPrimary, + backgroundColor: .surfaceDefaultTransparentSecondary, disabledAlpha: 0.5 ) } diff --git a/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextField/SDDSTextField+Preview.swift b/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextField/SDDSTextField+Preview.swift index 6b94c5866..f61de2b81 100644 --- a/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextField/SDDSTextField+Preview.swift +++ b/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextField/SDDSTextField+Preview.swift @@ -31,14 +31,14 @@ struct SDDSTextFieldPreview: PreviewProvider { textBefore: "", textAfter: "", disabled: false, - readOnly: true, - style: .default, - labelPlacement: .none, + readOnly: false, + style: .warning, + labelPlacement: .inner, required: false, requiredPlacement: .right, appearance: .defaultAppearance, - size: SDDSTextFieldSize.large, - layout: .default, + size: SDDSTextFieldSize.medium, + layout: .clear, iconViewProvider: ViewProvider(iconView), iconActionViewProvider: ViewProvider(iconActionView) ) @@ -54,8 +54,8 @@ struct SDDSTextFieldPreview: PreviewProvider { caption: "caption", disabled: false, style: .default, - labelPlacement: .outer, - required: false, + labelPlacement: .none, + required: true, requiredPlacement: .left, appearance: .defaultAppearance, size: SDDSTextFieldSize.large, diff --git a/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextField/TextFieldDefaultSize.swift b/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextField/TextFieldDefaultSize.swift index 4d0d4c1fb..40152348c 100644 --- a/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextField/TextFieldDefaultSize.swift +++ b/SDDSComponents/SDDSComponentsPreview/Components/SDDSTextField/TextFieldDefaultSize.swift @@ -144,67 +144,118 @@ public enum SDDSTextFieldSize: String, TextFieldSizeConfiguration { } } - public func indicatorYOffset(labelPlacement: TextFieldLabelPlacement, requiredPlacement: TextFieldRequiredPlacement, layout: TextFieldLayout) -> CGFloat { - switch (self, labelPlacement, requiredPlacement, layout) { - case (.large, .outer, .left, _): - return 8 - case (.medium, .outer, .left, _): - return 7 - case (.small, .outer, .left, _): - return 6 - case (.extraSmall, .outer, .left, _): - return 4 - case (.large, .inner, .right, .clear): - return 24 - case (.medium, .inner, .right, .clear): - return 23 - case (.small, .inner, .right, .clear): - return 22 - case (.extraSmall, .inner, .right, .clear): - return 21 - case (.large, .none, .left, .clear): - return 24 - case (.medium, .none, .left, .clear): - return 23 - case (.small, .none, .left, .clear): - return 22 - case (.extraSmall, .none, .left, .clear): - return 21 - case (.large, .outer, .right, _), (.medium, .outer, .right, _), (.small, .outer, .right, _): - return -2 - case (.extraSmall, .outer, .right, _): - return 0 - case (.large, .none, .right, .clear), (.medium, .none, .right, .clear), (.small, .none, .right, .clear): - return -4 - case (.extraSmall, .none, .right, .clear): - return -2 - default: - break - } - - return 0 - } - - public func indicatorPadding(labelPlacement: TextFieldLabelPlacement, requiredPlacement: TextFieldRequiredPlacement, layout: TextFieldLayout) -> CGFloat { - switch (self, labelPlacement, requiredPlacement, layout) { - case (.large, .outer, .left, _), (.medium, .outer, .left, _): - return 6 - case (.small, .outer, .left, _), (.extraSmall, .outer, .left, _): - return 4 - case (.large, .outer, .right, _), (.medium, .outer, .right, .default), (.small, .outer, .right, _), (.extraSmall, .outer, .right, _): - return 4 - case (.large, .inner, .left, .clear), (.medium, .inner, .left, .clear): - return 6 - case (.small, .inner, .left, .clear), (.extraSmall, .inner, .left, .clear): - return 4 - case (.large, .inner, .right, .clear), (.medium, .inner, .right, .clear), (.small, .inner, .right, .clear), (.extraSmall, .inner, .right, .clear): - return 4 - case (.large, .none, .right, .clear), (.medium, .none, .right, .clear): - return 6 - case (.small, .none, .right, .clear), (.extraSmall, .none, .right, .clear): - return 4 - default: - return 6 + public func indicatorOffset(labelPlacement: TextFieldLabelPlacement, requiredPlacement: TextFieldRequiredPlacement, layout: TextFieldLayout) -> CGPoint { + switch layout { + case .default: + switch labelPlacement { + case .none: + return .zero + case .inner: + return .zero + case .outer: + switch requiredPlacement { + case .left: + switch self { + case .large: + return CGPoint(x: 6, y: 8) + case .medium: + return CGPoint(x: 6, y: 7) + case .small: + return CGPoint(x: 4, y: 6) + case .extraSmall: + return CGPoint(x: 4, y: 4) + } + case .right: + switch self { + case .large: + return CGPoint(x: 4, y: 4) + case .medium: + return CGPoint(x: 4, y: 4) + case .small: + return CGPoint(x: 4, y: 4) + case .extraSmall: + return CGPoint(x: 4, y: 2) + } + } + } + case .clear: + switch labelPlacement { + case .none: + switch requiredPlacement { + case .left: + switch self { + case .large: + return CGPoint(x: 6, y: 24) + case .medium: + return CGPoint(x: 6, y: 20) + case .small: + return CGPoint(x: 6, y: 17) + case .extraSmall: + return CGPoint(x: 4, y: 13) + } + case .right: + switch self { + case .large: + return CGPoint(x: 4, y: 24) + case .medium: + return CGPoint(x: 4, y: 20) + case .small: + return CGPoint(x: 6, y: 17) + case .extraSmall: + return CGPoint(x: 4, y: 13) + } + } + case .inner: + switch requiredPlacement { + case .left: + switch self { + case .large: + return CGPoint(x: 6, y: 24) + case .medium: + return CGPoint(x: 6, y: 20) + case .small: + return CGPoint(x: 6, y: 17) + case .extraSmall: + return CGPoint(x: 4, y: 13) + } + case .right: + switch self { + case .large: + return CGPoint(x: 4, y: 24) + case .medium: + return CGPoint(x: 4, y: 20) + case .small: + return CGPoint(x: 6, y: 17) + case .extraSmall: + return CGPoint(x: 4, y: 13) + } + } + case .outer: + switch requiredPlacement { + case .left: + switch self { + case .large: + return CGPoint(x: 6, y: 8) + case .medium: + return CGPoint(x: 6, y: 7) + case .small: + return CGPoint(x: 4, y: 6) + case .extraSmall: + return CGPoint(x: 4, y: 4) + } + case .right: + switch self { + case .large: + return CGPoint(x: 4, y: 4) + case .medium: + return CGPoint(x: 4, y: 4) + case .small: + return CGPoint(x: 4, y: 4) + case .extraSmall: + return CGPoint(x: 4, y: 2) + } + } + } } } diff --git a/SDDSComponents/Sources/SDDSComponents/Components/SDDSTextArea/SDDSTextArea.swift b/SDDSComponents/Sources/SDDSComponents/Components/SDDSTextArea/SDDSTextArea.swift index 08d612bd4..21c50c773 100644 --- a/SDDSComponents/Sources/SDDSComponents/Components/SDDSTextArea/SDDSTextArea.swift +++ b/SDDSComponents/Sources/SDDSComponents/Components/SDDSTextArea/SDDSTextArea.swift @@ -186,7 +186,7 @@ public struct SDDSTextArea: View { public var body: some View { HStack(alignment: .top, spacing: 0) { - if showOuterTitleIndicatorForDefaultLayout || showInnerTitleIndicatorForClearLayout || showNoneTitleLeftIndicatorForClearLayout || showOuterTitleIndicatorForClearLayout { + if showOuterTitleIndicator || showInnerTitleIndicatorForClearLayout { indicatorWithTrailingPadding } @@ -209,8 +209,8 @@ public struct SDDSTextArea: View { } } - if showInnerTitleRightIndicatorForClearLayout || showNoneTitleIndicatorForClearLayout { - indicator + if showInnerTitleRightIndicatorForClearLayout { + indicatorWitLeadingPadding } } .opacity(disabled ? appearance.disabledAlpha : 1) @@ -221,14 +221,14 @@ public struct SDDSTextArea: View { @ViewBuilder private var titleLabel: some View { - HStack(alignment: .center, spacing: 0) { + HStack(alignment: .top, spacing: 0) { mainTitleView if !optionalTitle.isEmpty && !required { optionalTitleView } if shouldShowRequiredIndicatorAfterTitle { - indicator + indicatorWitLeadingPadding } } .padding(.bottom, size.titleBottomPadding, debug: debugConfiguration.titleBottomPadding) @@ -238,6 +238,7 @@ public struct SDDSTextArea: View { private var mainTitleView: some View { Text(title) .typography(titleTypography) + .frame(height: titleTypography.lineHeight) .foregroundColor(appearance.titleColor.color(for: colorScheme)) .multilineTextAlignment(appearance.titleTextAlignment) .debug(condition: debugConfiguration.title) @@ -245,11 +246,13 @@ public struct SDDSTextArea: View { @ViewBuilder private var optionalTitleView: some View { - Text(formattedOptionalTitle) + Text(optionalTitle) .typography(titleTypography) + .frame(height: titleTypography.lineHeight) .foregroundColor(appearance.optionalTitleColor.color(for: colorScheme)) .multilineTextAlignment(appearance.titleTextAlignment) .debug(condition: debugConfiguration.title) + .padding(.leading, size.optionalPadding) } @ViewBuilder @@ -257,26 +260,29 @@ public struct SDDSTextArea: View { if required { EmptyView() } else { - Text(formattedOptionalTitle) + Text(optionalTitle) .typography(innerTitleTypography) .foregroundColor(appearance.optionalTitleColor.color(for: colorScheme)) .multilineTextAlignment(appearance.titleTextAlignment) .debug(condition: debugConfiguration.title) + .padding(.leading, size.optionalPadding) } } @ViewBuilder - private var indicator: some View { + private var indicatorWithTrailingPadding: some View { indicatorView - .offset(y: indicatorYOffset, debug: debugConfiguration.indicatorYOffset) - .padding(.leading, indicatorPadding, debug: debugConfiguration.indicatorPadding) + .padding(.trailing, size.indicatorOffset(labelPlacement: labelPlacement, requiredPlacement: requiredPlacement, layout: layout).x) + .padding(.top, size.indicatorOffset(labelPlacement: labelPlacement, requiredPlacement: requiredPlacement, layout: layout).y) + .applyIf(showInnerTitleIndicatorForClearLayout) { $0.padding(.top, totalInnerTitlePadding) } } - + @ViewBuilder - private var indicatorWithTrailingPadding: some View { + private var indicatorWitLeadingPadding: some View { indicatorView - .offset(y: indicatorYOffset, debug: debugConfiguration.indicatorYOffset) - .padding(.trailing, indicatorPadding, debug: debugConfiguration.indicatorPadding) + .padding(.leading, size.indicatorOffset(labelPlacement: labelPlacement, requiredPlacement: requiredPlacement, layout: layout).x) + .padding(.top, size.indicatorOffset(labelPlacement: labelPlacement, requiredPlacement: requiredPlacement, layout: layout).y) + .applyIf(showInnerTitleRightIndicatorForClearLayout) { $0.padding(.top, totalInnerTitlePadding) } } @ViewBuilder @@ -408,9 +414,10 @@ public struct SDDSTextArea: View { if required { EmptyView() } else { - Text(" \(optionalTitle)") + Text(optionalTitle) .typography(textTypography) .foregroundColor(appearance.optionalTitleColor.color(for: colorScheme)) + .padding(.leading, size.optionalPadding) } } @@ -471,7 +478,7 @@ public struct SDDSTextArea: View { .padding(.leading, boxLeadingPadding, debug: debugConfiguration.boxLeadingPadding) .padding(.trailing, fieldTrailingPadding, debug: debugConfiguration.boxTrailingPadding) - if shouldShowIndicatorForInnerLabelDefaultLayout || shouldShowIndicatorForNoneLabelDefaultLayout { + if shouldShowEdgeIndicatorForDefaultLayout || shouldShowIndicatorForNoneLabelDefaultLayout { indicatorOverlayView } } @@ -492,7 +499,7 @@ public struct SDDSTextArea: View { private var totalHeight: CGFloat { var result = CGFloat(0) if shouldShowInnerTitle { - result += 2 * size.titleInnerPadding + result += totalInnerTitlePadding result += innerTitleTypography.lineHeight } if displayChips { @@ -671,14 +678,6 @@ public struct SDDSTextArea: View { private var iconActionViewHeight: CGFloat { min(size.iconActionSize.height, size.fieldHeight(layout: layout)) } - - private var indicatorYOffset: CGFloat { - size.indicatorYOffset(labelPlacement: labelPlacement, requiredPlacement: requiredPlacement, layout: layout) - } - - private var indicatorPadding: CGFloat { - size.indicatorPadding(labelPlacement: labelPlacement, requiredPlacement: requiredPlacement, layout: layout) - } private var captionTrailingPadding: CGFloat { boxTrailingPadding @@ -688,6 +687,10 @@ public struct SDDSTextArea: View { 0 } + private var totalInnerTitlePadding: CGFloat { + 2 * size.titleInnerPadding + } + private var iconActionTrailingPadding: CGFloat { if let _ = iconActionViewProvider?.view { return iconActionViewWidth + size.iconActionPadding @@ -703,8 +706,8 @@ public struct SDDSTextArea: View { (!text.isEmpty || isFocused) } - private var shouldShowIndicatorForInnerLabelDefaultLayout: Bool { - labelPlacement == .inner && + private var shouldShowEdgeIndicatorForDefaultLayout: Bool { + (labelPlacement == .inner || labelPlacement == .none) && required && layout == .default } @@ -720,11 +723,10 @@ public struct SDDSTextArea: View { requiredPlacement == .right } - private var showOuterTitleIndicatorForDefaultLayout: Bool { + private var showOuterTitleIndicator: Bool { labelPlacement == .outer && required && - requiredPlacement == .left && - layout == .default + requiredPlacement == .left } private var showNoneTitleIndicatorForClearLayout: Bool { @@ -735,33 +737,19 @@ public struct SDDSTextArea: View { } private var showInnerTitleIndicatorForClearLayout: Bool { - labelPlacement == .inner && - required && - requiredPlacement == .left && - layout == .clear - } - - private var showOuterTitleIndicatorForClearLayout: Bool { - labelPlacement == .outer && + (labelPlacement == .inner || labelPlacement == .none) && required && requiredPlacement == .left && layout == .clear } private var showInnerTitleRightIndicatorForClearLayout: Bool { - labelPlacement == .inner && + (labelPlacement == .inner || labelPlacement == .none) && required && requiredPlacement == .right && layout == .clear } - private var showNoneTitleLeftIndicatorForClearLayout: Bool { - labelPlacement == .none && - required && - layout == .clear && - requiredPlacement == .left - } - private var trailingContentPadding: CGFloat { iconActionViewProvider?.view != nil ? iconActionTrailingPadding : 0 } @@ -783,10 +771,6 @@ public struct SDDSTextArea: View { return min(size.chipGroupHeight, chipGroupContentHeight) } - private var formattedOptionalTitle: String { - " \(optionalTitle)" - } - private var chipCornerRadius: CGFloat { switch value { case .single: diff --git a/SDDSComponents/Sources/SDDSComponents/Components/SDDSTextArea/TextAreaSizeConfiguration.swift b/SDDSComponents/Sources/SDDSComponents/Components/SDDSTextArea/TextAreaSizeConfiguration.swift index eb77c7f1f..d91293993 100644 --- a/SDDSComponents/Sources/SDDSComponents/Components/SDDSTextArea/TextAreaSizeConfiguration.swift +++ b/SDDSComponents/Sources/SDDSComponents/Components/SDDSTextArea/TextAreaSizeConfiguration.swift @@ -9,6 +9,7 @@ public protocol TextAreaSizeConfiguration: CustomDebugStringConvertible { var boxTrailingPadding: CGFloat { get } var captionTopPadding: CGFloat { get } var captionBottomPadding: CGFloat { get } + var optionalPadding: CGFloat { get } var textInputPaddings: EdgeInsets { get } var cornerRadius: CGFloat { get } var borderWidth: CGFloat { get } @@ -31,6 +32,5 @@ public protocol TextAreaSizeConfiguration: CustomDebugStringConvertible { var chipsPadding: CGFloat { get } func fieldHeight(layout: TextAreaLayout) -> CGFloat - func indicatorPadding(labelPlacement: TextAreaLabelPlacement, requiredPlacement: TextAreaRequiredPlacement, layout: TextAreaLayout) -> CGFloat - func indicatorYOffset(labelPlacement: TextAreaLabelPlacement, requiredPlacement: TextAreaRequiredPlacement, layout: TextAreaLayout) -> CGFloat + func indicatorOffset(labelPlacement: TextAreaLabelPlacement, requiredPlacement: TextAreaRequiredPlacement, layout: TextAreaLayout) -> CGPoint } diff --git a/SDDSComponents/Sources/SDDSComponents/Components/SDDSTextField/SDDSTextField.swift b/SDDSComponents/Sources/SDDSComponents/Components/SDDSTextField/SDDSTextField.swift index 59affdc8b..400efd320 100644 --- a/SDDSComponents/Sources/SDDSComponents/Components/SDDSTextField/SDDSTextField.swift +++ b/SDDSComponents/Sources/SDDSComponents/Components/SDDSTextField/SDDSTextField.swift @@ -176,7 +176,7 @@ public struct SDDSTextField: View { public var body: some View { HStack(alignment: .top, spacing: 0) { - if showOuterTitleIndicatorForDefaultLayout || showNoneTitleLeftIndicatorForClearLayout { + if showOuterTitleIndicatorForDefaultLayout || showInnerTitleIndicatorForClearLayout { indicatorWithTrailingPadding } @@ -184,13 +184,9 @@ public struct SDDSTextField: View { if labelPlacement == .outer { titleLabel .multilineTextAlignment(appearance.titleTextAlignment) - .debug(condition: debugConfiguration.title) } HStack(spacing: 0) { - if showInnerTitleIndicatorForClearLayout { - indicatorWithTrailingPadding - } fieldView .onTapGesture { guard !displayChips else { @@ -204,14 +200,13 @@ public struct SDDSTextField: View { if showInnerTitleIndicatorForClearLayout { Spacer() .frame(width: size.indicatorSize.width) - .padding(.trailing, indicatorPadding, debug: debugConfiguration.indicatorPadding) } captionLabel } } if showInnerTitleRightIndicatorForClearLayout { - indicator + indicatorWitLeadingPadding } } .opacity(disabled ? appearance.disabledAlpha : 1) @@ -222,14 +217,14 @@ public struct SDDSTextField: View { @ViewBuilder private var titleLabel: some View { - HStack(alignment: .center, spacing: 0) { + HStack(alignment: .top, spacing: 0) { mainTitleView if !optionalTitle.isEmpty && !required { optionalTitleView } if shouldShowRequiredIndicatorAfterTitle { - indicator + indicatorWitLeadingPadding } } .padding(.bottom, size.titleBottomPadding, debug: debugConfiguration.titleBottomPadding) @@ -239,18 +234,20 @@ public struct SDDSTextField: View { private var mainTitleView: some View { Text(title) .typography(titleTypography) + .frame(height: titleTypography.lineHeight) .foregroundColor(appearance.titleColor.color(for: colorScheme)) .multilineTextAlignment(appearance.titleTextAlignment) - .debug(condition: debugConfiguration.title) } @ViewBuilder private var optionalTitleView: some View { Text(optionalTitle) .typography(titleTypography) + .frame(height: titleTypography.lineHeight) .foregroundColor(appearance.optionalTitleColor.color(for: colorScheme)) .multilineTextAlignment(appearance.titleTextAlignment) .debug(condition: debugConfiguration.title) + .padding(.leading, size.optionalPadding) } @ViewBuilder @@ -268,17 +265,17 @@ public struct SDDSTextField: View { } @ViewBuilder - private var indicator: some View { + private var indicatorWithTrailingPadding: some View { indicatorView - .offset(y: indicatorYOffset, debug: debugConfiguration.indicatorYOffset) - .padding(.leading, indicatorPadding, debug: debugConfiguration.indicatorPadding) + .padding(.trailing, size.indicatorOffset(labelPlacement: labelPlacement, requiredPlacement: requiredPlacement, layout: layout).x) + .padding(.top, size.indicatorOffset(labelPlacement: labelPlacement, requiredPlacement: requiredPlacement, layout: layout).y) } - + @ViewBuilder - private var indicatorWithTrailingPadding: some View { + private var indicatorWitLeadingPadding: some View { indicatorView - .offset(y: indicatorYOffset, debug: debugConfiguration.indicatorYOffset) - .padding(.trailing, indicatorPadding, debug: debugConfiguration.indicatorPadding) + .padding(.leading, size.indicatorOffset(labelPlacement: labelPlacement, requiredPlacement: requiredPlacement, layout: layout).x) + .padding(.top, size.indicatorOffset(labelPlacement: labelPlacement, requiredPlacement: requiredPlacement, layout: layout).y) } @ViewBuilder @@ -347,7 +344,6 @@ public struct SDDSTextField: View { placeholderAfterContent: { HStack(spacing: 0) { textAfterView - placeholderIndicator } }, onEditingChanged: { focused in @@ -386,7 +382,7 @@ public struct SDDSTextField: View { readOnly: readOnly, placeholderBeforeContent: {}, placeholderContent: { placeholderView }, - placeholderAfterContent: { placeholderIndicator }, + placeholderAfterContent: { EmptyView() }, onEditingChanged: { focused in isFocused = focused }, @@ -444,7 +440,7 @@ public struct SDDSTextField: View { @ViewBuilder private var innerOrNonePlacementOptionalTitleView: some View { - Text(" \(optionalTitle)") + Text(optionalTitle) .typography(textTypography) .foregroundColor(appearance.optionalTitleColor.color(for: colorScheme)) .padding(.leading, size.optionalPadding) @@ -503,7 +499,7 @@ public struct SDDSTextField: View { } } - if shouldShowIndicatorForInnerLabelDefaultLayout { + if shouldShowEdgeIndicatorForDefaultLayout { indicatorOverlayView } } @@ -587,12 +583,21 @@ public struct SDDSTextField: View { return appearance.lineColor.color(for: colorScheme) } } + + private var iconViewColor: Color { + switch style { + case .error, .success, .warning: + return appearance.placeholderColor(for: style, layout: layout).color(for: colorScheme) + case .default: + return appearance.startContentColor.color(for: colorScheme) + } + } @ViewBuilder private var iconView: some View { if let leftView = iconViewProvider?.view { leftView - .foregroundColor(appearance.startContentColor.color(for: colorScheme)) + .foregroundColor(iconViewColor) .frame(width: iconViewWidth, height: min(size.iconSize.height, size.fieldHeight), debug: debugConfiguration.icon) .padding(.trailing, size.iconPadding, debug: debugConfiguration.icon) } else { @@ -629,15 +634,6 @@ public struct SDDSTextField: View { .frame(width: size.indicatorSize.width, height: size.indicatorSize.height, debug: debugConfiguration.indicatorView) } - @ViewBuilder - private var placeholderIndicator: some View { - if showNoneTitleIndicatorForClearLayout { - indicator - } else { - EmptyView() - } - } - @ViewBuilder private var indicatorOverlayView: some View { VStack(spacing: 0) { @@ -693,14 +689,6 @@ public struct SDDSTextField: View { min(size.iconSize.width, size.fieldHeight) } - private var indicatorYOffset: CGFloat { - size.indicatorYOffset(labelPlacement: labelPlacement, requiredPlacement: requiredPlacement, layout: layout) - } - - private var indicatorPadding: CGFloat { - size.indicatorPadding(labelPlacement: labelPlacement, requiredPlacement: requiredPlacement, layout: layout) - } - private var shouldShowInnerTitle: Bool { labelPlacement == .inner && !displayChips && @@ -708,8 +696,8 @@ public struct SDDSTextField: View { !placeholder.isEmpty } - private var shouldShowIndicatorForInnerLabelDefaultLayout: Bool { - labelPlacement == .inner && + private var shouldShowEdgeIndicatorForDefaultLayout: Bool { + (labelPlacement == .inner || labelPlacement == .none) && required && layout == .default } @@ -720,14 +708,14 @@ public struct SDDSTextField: View { } private var showInnerTitleIndicatorForClearLayout: Bool { - labelPlacement == .inner && + (labelPlacement == .inner || labelPlacement == .none) && required && requiredPlacement == .left && layout == .clear } private var showInnerTitleRightIndicatorForClearLayout: Bool { - labelPlacement == .inner && + (labelPlacement == .inner || labelPlacement == .none) && required && requiredPlacement == .right && layout == .clear @@ -736,21 +724,8 @@ public struct SDDSTextField: View { private var showOuterTitleIndicatorForDefaultLayout: Bool { labelPlacement == .outer && required && - requiredPlacement == .left - } - - private var showNoneTitleLeftIndicatorForClearLayout: Bool { - labelPlacement == .none && - required && requiredPlacement == .left && - !isFocused - } - - private var showNoneTitleIndicatorForClearLayout: Bool { - labelPlacement == .none && - required && - requiredPlacement == .right && - !isFocused + layout == .default } private var shouldCenterText: Bool { @@ -770,10 +745,6 @@ public struct SDDSTextField: View { } } - private var formattedOptionalTitle: String { - " \(optionalTitle)" - } - private var chipCornerRadius: CGFloat { switch value { case .single: diff --git a/SDDSComponents/Sources/SDDSComponents/Components/SDDSTextField/TextFieldSizeConfiguration.swift b/SDDSComponents/Sources/SDDSComponents/Components/SDDSTextField/TextFieldSizeConfiguration.swift index 5c8cc87bb..6386dc1b3 100644 --- a/SDDSComponents/Sources/SDDSComponents/Components/SDDSTextField/TextFieldSizeConfiguration.swift +++ b/SDDSComponents/Sources/SDDSComponents/Components/SDDSTextField/TextFieldSizeConfiguration.swift @@ -25,7 +25,5 @@ public protocol TextFieldSizeConfiguration: CustomDebugStringConvertible { var textAfterLeadingPadding: CGFloat { get } var textAfterTrailingPadding: CGFloat { get } var chipsPadding: CGFloat { get } - - func indicatorPadding(labelPlacement: TextFieldLabelPlacement, requiredPlacement: TextFieldRequiredPlacement, layout: TextFieldLayout) -> CGFloat - func indicatorYOffset(labelPlacement: TextFieldLabelPlacement, requiredPlacement: TextFieldRequiredPlacement, layout: TextFieldLayout) -> CGFloat + func indicatorOffset(labelPlacement: TextFieldLabelPlacement, requiredPlacement: TextFieldRequiredPlacement, layout: TextFieldLayout) -> CGPoint } diff --git a/SDDSThemeBuilder/SDDSThemeBuilderCore/Stencil/BasicButtonSize+ButtonSizeConfiguration.stencil b/SDDSThemeBuilder/SDDSThemeBuilderCore/Stencil/BasicButtonSize+ButtonSizeConfiguration.stencil index a1b547c7a..5d074caec 100644 --- a/SDDSThemeBuilder/SDDSThemeBuilderCore/Stencil/BasicButtonSize+ButtonSizeConfiguration.stencil +++ b/SDDSThemeBuilder/SDDSThemeBuilderCore/Stencil/BasicButtonSize+ButtonSizeConfiguration.stencil @@ -25,7 +25,7 @@ extension BasicButtonSize: ButtonSizeConfiguration { case .cornered: switch self { {%- for variation, config in variations.size %} - case .{{ variation | sizeKey }}: return {{ config.shape.name | adjustedCornerRadius:config.shape.adjustment }} + case .{{ variation | sizeKey }}: return {{ config.shape.value | adjustedCornerRadius:config.shape.adjustment }} {%- endfor %} } case .pilled: diff --git a/SDDSThemeBuilder/SDDSThemeBuilderCore/Stencil/IconButtonSize+ButtonSizeConfiguration.stencil b/SDDSThemeBuilder/SDDSThemeBuilderCore/Stencil/IconButtonSize+ButtonSizeConfiguration.stencil index 4c5040b06..19b804b1a 100644 --- a/SDDSThemeBuilder/SDDSThemeBuilderCore/Stencil/IconButtonSize+ButtonSizeConfiguration.stencil +++ b/SDDSThemeBuilder/SDDSThemeBuilderCore/Stencil/IconButtonSize+ButtonSizeConfiguration.stencil @@ -25,7 +25,7 @@ extension IconButtonSize: ButtonSizeConfiguration { case .cornered: switch self { {%- for variation, config in variations.size %} - case .{{ variation | sizeKey }}: return {{ config.shape.name | adjustedCornerRadius:config.shape.adjustment }} + case .{{ variation | sizeKey }}: return {{ config.shape.value | adjustedCornerRadius:config.shape.adjustment }} {%- endfor %} } case .pilled: