From 14d9b58a964c91fdb3f4e92a4e106dd942a5c7bb Mon Sep 17 00:00:00 2001 From: xiaoyu0722 Date: Wed, 18 Dec 2024 16:04:58 +0800 Subject: [PATCH 1/2] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20step=20progress?= =?UTF-8?q?=20indicator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SPIModelExample.swift | 12 +- .../StepProgressIndicatorExample.swift | 446 +++++++++++++----- .../Models/ModelDefinitions.swift | 14 +- .../StepProgressIndicator/StepsStack.swift | 41 ++ .../StepProgressIndicator/_DefaultSteps.swift | 4 +- .../{SingleStep.swift => _SingleStep.swift} | 10 +- ...wift => _StepProgressIndicator+View.swift} | 6 +- .../_StepsContainer.swift | 25 +- .../BaseComponentProtocols.swift | 13 + .../CompositeComponentProtocols.swift | 44 ++ .../_FioriStyles/LineStyle.fiori.swift | 20 + .../_FioriStyles/NodeStyle.fiori.swift | 20 + .../_FioriStyles/SingleStepStyle.fiori.swift | 145 ++++++ .../StepProgressIndicatorStyle.fiori.swift | 217 +++++++++ .../EnvironmentKey+Styles.generated.swift | 8 +- .../EnvironmentValue+Styles.generated.swift | 20 +- .../Line/Line.generated.swift | 57 +++ .../Line/LineStyle.generated.swift | 28 ++ .../Node/Node.generated.swift | 63 +++ .../Node/NodeStyle.generated.swift | 28 ++ .../SingleStep/SingleStep.generated.swift | 90 ++++ .../SingleStepStyle.generated.swift | 45 ++ .../StepProgressIndicator.generated.swift | 102 ++++ ...StepProgressIndicatorStyle.generated.swift | 44 ++ ...entStyleProtocol+Extension.generated.swift | 182 +++++++ .../EnvironmentVariables.generated.swift | 84 ++++ .../ModifiedStyle.generated.swift | 112 +++++ .../ResolvedStyle.generated.swift | 64 +++ .../View+Extension_.generated.swift | 68 +++ ...iewEmptyChecking+Extension.generated.swift | 30 ++ ....swift => _SingleStep+API.generated.swift} | 16 +- ...StepProgressIndicator+API.generated.swift} | 20 +- .../_SingleStep+View.generated.swift | 62 +++ ...StepProgressIndicator+View.generated.swift | 66 +++ ...swift => _SingleStep+Init.generated.swift} | 2 +- ...tepProgressIndicator+Init.generated.swift} | 14 +- ...ingleStepModel+Extensions.generated.swift} | 2 +- ...IndicatorModel+Extensions.generated.swift} | 2 +- .../en.lproj/FioriSwiftUICore.strings | 3 + .../.lib/Sources/utils/Type+Extensions.swift | 4 +- 40 files changed, 2033 insertions(+), 200 deletions(-) create mode 100644 Sources/FioriSwiftUICore/Views/StepProgressIndicator/StepsStack.swift rename Sources/FioriSwiftUICore/Views/StepProgressIndicator/{SingleStep.swift => _SingleStep.swift} (97%) rename Sources/FioriSwiftUICore/Views/StepProgressIndicator/{StepProgressIndicator+View.swift => _StepProgressIndicator+View.swift} (97%) create mode 100644 Sources/FioriSwiftUICore/_FioriStyles/LineStyle.fiori.swift create mode 100644 Sources/FioriSwiftUICore/_FioriStyles/NodeStyle.fiori.swift create mode 100644 Sources/FioriSwiftUICore/_FioriStyles/SingleStepStyle.fiori.swift create mode 100644 Sources/FioriSwiftUICore/_FioriStyles/StepProgressIndicatorStyle.fiori.swift create mode 100644 Sources/FioriSwiftUICore/_generated/StyleableComponents/Line/Line.generated.swift create mode 100644 Sources/FioriSwiftUICore/_generated/StyleableComponents/Line/LineStyle.generated.swift create mode 100644 Sources/FioriSwiftUICore/_generated/StyleableComponents/Node/Node.generated.swift create mode 100644 Sources/FioriSwiftUICore/_generated/StyleableComponents/Node/NodeStyle.generated.swift create mode 100644 Sources/FioriSwiftUICore/_generated/StyleableComponents/SingleStep/SingleStep.generated.swift create mode 100644 Sources/FioriSwiftUICore/_generated/StyleableComponents/SingleStep/SingleStepStyle.generated.swift create mode 100644 Sources/FioriSwiftUICore/_generated/StyleableComponents/StepProgressIndicator/StepProgressIndicator.generated.swift create mode 100644 Sources/FioriSwiftUICore/_generated/StyleableComponents/StepProgressIndicator/StepProgressIndicatorStyle.generated.swift rename Sources/FioriSwiftUICore/_generated/ViewModels/API/{SingleStep+API.generated.swift => _SingleStep+API.generated.swift} (76%) rename Sources/FioriSwiftUICore/_generated/ViewModels/API/{StepProgressIndicator+API.generated.swift => _StepProgressIndicator+API.generated.swift} (77%) create mode 100644 Sources/FioriSwiftUICore/_generated/ViewModels/Boilerplate/_SingleStep+View.generated.swift create mode 100644 Sources/FioriSwiftUICore/_generated/ViewModels/Boilerplate/_StepProgressIndicator+View.generated.swift rename Sources/FioriSwiftUICore/_generated/ViewModels/Init+Extensions/{SingleStep+Init.generated.swift => _SingleStep+Init.generated.swift} (88%) rename Sources/FioriSwiftUICore/_generated/ViewModels/Init+Extensions/{StepProgressIndicator+Init.generated.swift => _StepProgressIndicator+Init.generated.swift} (81%) rename Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/{SingleStepModel+Extensions.generated.swift => _SingleStepModel+Extensions.generated.swift} (86%) rename Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/{StepProgressIndicatorModel+Extensions.generated.swift => _StepProgressIndicatorModel+Extensions.generated.swift} (87%) diff --git a/Apps/Examples/Examples/FioriSwiftUICore/StepProgressIndicator/SPIModelExample.swift b/Apps/Examples/Examples/FioriSwiftUICore/StepProgressIndicator/SPIModelExample.swift index f84b6ffd7..1a68ea25a 100644 --- a/Apps/Examples/Examples/FioriSwiftUICore/StepProgressIndicator/SPIModelExample.swift +++ b/Apps/Examples/Examples/FioriSwiftUICore/StepProgressIndicator/SPIModelExample.swift @@ -1,7 +1,7 @@ import FioriSwiftUICore import SwiftUI -class SPIExampleModel: StepProgressIndicatorModel, ObservableObject { +class SPIExampleModel: _StepProgressIndicatorModel, ObservableObject { struct AllActionModel: _ActionModel { let actionText: String? = "All Steps" @@ -11,7 +11,7 @@ class SPIExampleModel: StepProgressIndicatorModel, ObservableObject { @Published var selection: String = "b" var title: String? = "SPI Title: b" - var steps: [SingleStepModel] = ["a", "b", "c", "d", "e", "f"] + var steps: [_SingleStepModel] = ["a", "b", "c", "d", "e", "f"] .map { SingelExampleModel(id: $0, title: "title: \($0)", @@ -23,16 +23,16 @@ class SPIExampleModel: StepProgressIndicatorModel, ObservableObject { } } -class SingelExampleModel: SingleStepModel { +class SingelExampleModel: _SingleStepModel { var id: String = "" var title: String? = "" var node: TextOrIcon - var substeps: [SingleStepModel] = [] + var substeps: [_SingleStepModel] = [] init(id: String = UUID().uuidString, title: String? = nil, node: TextOrIcon, - substeps: [SingleStepModel] = []) + substeps: [_SingleStepModel] = []) { self.id = id self.title = title @@ -47,7 +47,7 @@ struct SPIModelExample: View { var body: some View { VStack(alignment: .leading) { Text("Initialized by Model").bold() - StepProgressIndicator(model: self.model) + _StepProgressIndicator(model: self.model) .stepStyle { id in CustomModelStyleExample(isLast: id == "f") } diff --git a/Apps/Examples/Examples/FioriSwiftUICore/StepProgressIndicator/StepProgressIndicatorExample.swift b/Apps/Examples/Examples/FioriSwiftUICore/StepProgressIndicator/StepProgressIndicatorExample.swift index b803ff219..e14d16993 100644 --- a/Apps/Examples/Examples/FioriSwiftUICore/StepProgressIndicator/StepProgressIndicatorExample.swift +++ b/Apps/Examples/Examples/FioriSwiftUICore/StepProgressIndicator/StepProgressIndicatorExample.swift @@ -5,52 +5,82 @@ import SwiftUI struct StepProgressIndicatorExample: View { var body: some View { List { - NavigationLink { - SPIExampleWithHeader() - } label: { - Text("Steps With Header") - } - NavigationLink { - SPIExampleWithoutHeader() - } label: { - Text("Steps Without Header") - } - NavigationLink { - SPIExampleWithoutName() - } label: { - Text("Steps Without Names") - } - NavigationLink { - SPICustomStyleExample() - } label: { - Text("Steps With Custom Style") - } - NavigationLink { - SPIExampleByBuilder() - } label: { - Text("Steps By Builder") - } - NavigationLink { - SPIModelExample() - } label: { - Text("Steps By Model") + Section("New") { + NavigationLink { + SPIExampleWithHeader(isDeprecated: false) + } label: { + Text("Steps With Header") + } + NavigationLink { + SPIExampleWithoutHeader(isDeprecated: false) + } label: { + Text("Steps Without Header") + } + NavigationLink { + SPIExampleWithoutName(isDeprecated: false) + } label: { + Text("Steps Without Names") + } + NavigationLink { + SPICustomStyleExample(isDeprecated: false) + } label: { + Text("Steps With Custom Style") + } + NavigationLink { + SPIExampleByBuilder(isDeprecated: false) + } label: { + Text("Steps By Builder") + } + NavigationLink { + SPIExampleWithIcon(isDeprecated: false) + } label: { + Text("Steps By Icon") + } } - NavigationLink { - SPIExampleWithIcon() - } label: { - Text("Steps By Icon") + + Section("Deprecated") { + NavigationLink { + SPIExampleWithHeader(isDeprecated: true) + } label: { + Text("Steps With Header") + } + NavigationLink { + SPIExampleWithoutHeader(isDeprecated: true) + } label: { + Text("Steps Without Header") + } + NavigationLink { + SPIExampleWithoutName(isDeprecated: true) + } label: { + Text("Steps Without Names") + } + NavigationLink { + SPICustomStyleExample(isDeprecated: true) + } label: { + Text("Steps With Custom Style") + } + NavigationLink { + SPIExampleByBuilder(isDeprecated: true) + } label: { + Text("Steps By Builder") + } + NavigationLink { + SPIModelExample() + } label: { + Text("Steps By Model") + } + NavigationLink { + SPIExampleWithIcon(isDeprecated: true) + } label: { + Text("Steps By Icon") + } } } } } -struct StepProgressIndicatorExample_Previews: PreviewProvider { - static var previews: some View { - StepProgressIndicatorExample() - } -} - struct SPIExampleWithIcon: View { + let isDeprecated: Bool @State var title: String = "" @State var iconSteps = [StepItemData(title: "Sign In", node: .icon(FioriIcon.arrows.initiative), state: .completed), StepItemData(title: "User Info", node: .icon(FioriIcon.people.personPlaceholder), state: .completed), @@ -71,18 +101,38 @@ struct SPIExampleWithIcon: View { var body: some View { VStack(alignment: .leading) { Text("Step: Only Icon Node").bold() - StepProgressIndicator(selection: self.$iconSelection, - stepItems: self.iconSteps) - { - Text(self.$title.wrappedValue).lineLimit(1) - } action: { - Button {} label: { - HStack(spacing: 2) { - Text("All Steps(\(self.iconSteps.count))") - .foregroundStyle(Color.preferredColor(.tintColor)) - FioriIcon.actions.slimArrowRight - .font(.fiori(forTextStyle: .subheadline, weight: .semibold)) - .foregroundStyle(Color.preferredColor(.separator)) + Group { + if self.isDeprecated { + _StepProgressIndicator(selection: self.$iconSelection, + stepItems: self.iconSteps) + { + Text(self.$title.wrappedValue).lineLimit(1) + } action: { + Button {} label: { + HStack(spacing: 2) { + Text("All Steps(\(self.iconSteps.count))") + .foregroundStyle(Color.preferredColor(.tintColor)) + FioriIcon.actions.slimArrowRight + .font(.fiori(forTextStyle: .subheadline, weight: .semibold)) + .foregroundStyle(Color.preferredColor(.separator)) + } + } + } + } else { + StepProgressIndicator(selection: self.$iconSelection, + stepItems: self.iconSteps) + { + Text(self.$title.wrappedValue).lineLimit(1) + } action: { + Button {} label: { + HStack(spacing: 2) { + Text("All Steps(\(self.iconSteps.count))") + .foregroundStyle(Color.preferredColor(.tintColor)) + FioriIcon.actions.slimArrowRight + .font(.fiori(forTextStyle: .subheadline, weight: .semibold)) + .foregroundStyle(Color.preferredColor(.separator)) + } + } } } } @@ -95,13 +145,21 @@ struct SPIExampleWithIcon: View { } Text("Step: Only Text Node").bold() - StepProgressIndicator(selection: self.$textSelection, - stepItems: self.textSteps) - { - Text("Invariant title").lineLimit(1) - } action: {} - .padding() - + if self.isDeprecated { + _StepProgressIndicator(selection: self.$textSelection, + stepItems: self.textSteps) + { + Text("Invariant title").lineLimit(1) + } action: {} + .padding() + } else { + StepProgressIndicator(selection: self.$textSelection, + stepItems: self.textSteps) + { + Text("Invariant title").lineLimit(1) + } action: {} + .padding() + } Spacer().padding(20) Button { self.completeStep() @@ -158,6 +216,7 @@ struct SPIExampleWithIcon: View { } struct SPIExampleWithoutHeader: View { + let isDeprecated: Bool @State var steps = [StepItemData(title: "Step A", state: .completed), StepItemData(title: "Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name"), StepItemData(title: "Step 3", substeps: [ @@ -177,8 +236,13 @@ struct SPIExampleWithoutHeader: View { var body: some View { VStack(alignment: .leading) { Text("Without Header").bold() - StepProgressIndicator(selection: self.$selection, - stepItems: self.steps) + if self.isDeprecated { + _StepProgressIndicator(selection: self.$selection, + stepItems: self.steps) + } else { + StepProgressIndicator(selection: self.$selection, + stepItems: self.steps) + } Spacer().padding(20) Button { self.completeStep() @@ -208,6 +272,8 @@ struct SPIExampleWithoutHeader: View { } struct SPIExampleWithHeader: View { + let isDeprecated: Bool + @State var title: String = "" @State var steps = [StepItemData(title: "Step A", state: .completed), StepItemData(title: "Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name"), @@ -228,16 +294,32 @@ struct SPIExampleWithHeader: View { var body: some View { VStack(alignment: .leading) { Text("With Header").bold() - StepProgressIndicator(selection: self.$selection, stepItems: self.steps) { - Text(self.title).lineLimit(1) - } action: { - Button {} label: { - HStack(spacing: 2) { - Text("All Steps(\(self.steps.count)") - .foregroundStyle(Color.preferredColor(.tintColor)) - FioriIcon.actions.slimArrowRight - .font(.fiori(forTextStyle: .subheadline, weight: .semibold)) - .foregroundStyle(Color.preferredColor(.separator)) + if self.isDeprecated { + _StepProgressIndicator(selection: self.$selection, stepItems: self.steps) { + Text(self.title).lineLimit(1) + } action: { + Button {} label: { + HStack(spacing: 2) { + Text("All Steps(\(self.steps.count)") + .foregroundStyle(Color.preferredColor(.tintColor)) + FioriIcon.actions.slimArrowRight + .font(.fiori(forTextStyle: .subheadline, weight: .semibold)) + .foregroundStyle(Color.preferredColor(.separator)) + } + } + } + } else { + StepProgressIndicator(selection: self.$selection, stepItems: self.steps) { + Text(self.title).lineLimit(1) + } action: { + Button {} label: { + HStack(spacing: 2) { + Text("All Steps(\(self.steps.count)") + .foregroundStyle(Color.preferredColor(.tintColor)) + FioriIcon.actions.slimArrowRight + .font(.fiori(forTextStyle: .subheadline, weight: .semibold)) + .foregroundStyle(Color.preferredColor(.separator)) + } } } } @@ -304,6 +386,8 @@ struct SPIExampleWithHeader: View { } struct SPIExampleWithoutName: View { + let isDeprecated: Bool + @State var steps = [StepItemData(), StepItemData(), StepItemData(substeps: [ @@ -321,16 +405,30 @@ struct SPIExampleWithoutName: View { var body: some View { VStack(alignment: .leading) { Text("Steps Without Names").bold() - - StepProgressIndicator(selection: self.$selection, - stepItems: self.steps) {} action: { - Button {} label: { - HStack(spacing: 2) { - Text("All Steps(\(self.steps.count)") - .foregroundStyle(Color.preferredColor(.tintColor)) - FioriIcon.actions.slimArrowRight - .font(.fiori(forTextStyle: .subheadline, weight: .semibold)) - .foregroundStyle(Color.preferredColor(.separator)) + if self.isDeprecated { + _StepProgressIndicator(selection: self.$selection, + stepItems: self.steps) {} action: { + Button {} label: { + HStack(spacing: 2) { + Text("All Steps(\(self.steps.count)") + .foregroundStyle(Color.preferredColor(.tintColor)) + FioriIcon.actions.slimArrowRight + .font(.fiori(forTextStyle: .subheadline, weight: .semibold)) + .foregroundStyle(Color.preferredColor(.separator)) + } + } + } + } else { + StepProgressIndicator(selection: self.$selection, + stepItems: self.steps) {} action: { + Button {} label: { + HStack(spacing: 2) { + Text("All Steps(\(self.steps.count)") + .foregroundStyle(Color.preferredColor(.tintColor)) + FioriIcon.actions.slimArrowRight + .font(.fiori(forTextStyle: .subheadline, weight: .semibold)) + .foregroundStyle(Color.preferredColor(.separator)) + } } } } @@ -362,53 +460,113 @@ struct SPIExampleWithoutName: View { } struct SPIExampleByBuilder: View { + let isDeprecated: Bool @State var selection: String = "" var body: some View { - VStack { - StepProgressIndicator(selection: self.$selection, action: { - Button {} label: { - HStack(spacing: 2) { - Text("All Steps(2)") - .foregroundStyle(Color.preferredColor(.tintColor)) - FioriIcon.actions.slimArrowRight - .font(.fiori(forTextStyle: .subheadline, weight: .semibold)) - .foregroundStyle(Color.preferredColor(.separator)) + ScrollView(.vertical) { + if self.isDeprecated { + _StepProgressIndicator(selection: self.$selection, action: { + Button {} label: { + HStack(spacing: 2) { + Text("All Steps(2)") + .foregroundStyle(Color.preferredColor(.tintColor)) + FioriIcon.actions.slimArrowRight + .font(.fiori(forTextStyle: .subheadline, weight: .semibold)) + .foregroundStyle(Color.preferredColor(.separator)) + } } - } - }, steps: { - SingleStep(id: "1") { - self.node("1") - } substeps: { - SingleStep(id: "1.1") { - self.node("1.1") + }, steps: { + _SingleStep(id: "1") { + self.node("1") + } substeps: { + _SingleStep(id: "1.1") { + self.node("1.1") + } } - } - - SingleStep(id: "2") { - self.node("2") - } substeps: { - SingleStep(id: "2.1") { - self.node("2.1") + + _SingleStep(id: "2") { + self.node("2") } substeps: { - SingleStep { - self.node("2.1.1") + _SingleStep(id: "2.1") { + self.node("2.1") + } substeps: { + _SingleStep { + self.node("2.1.1") + } + .customStepId("2.1.1") + } + + _SingleStep(id: "2.2") { + self.node("2.2") + } substeps: { + _SingleStep { + self.node("2.2.1") + } + .customStepId("2.2.1") + .stepLineModifier { + $0.foregroundColor(.clear) + } } - .customStepId("2.1.1") + } + }) + } else { + StepProgressIndicator(selection: self.$selection, action: { + Button {} label: { + HStack(spacing: 2) { + Text("All Steps(2)") + .foregroundStyle(Color.preferredColor(.tintColor)) + FioriIcon.actions.slimArrowRight + .font(.fiori(forTextStyle: .subheadline, weight: .semibold)) + .foregroundStyle(Color.preferredColor(.separator)) + } + } + }, steps: { + SingleStep(id: "1") { + self.node("1") + } substeps: { + SingleStep(id: "1.1") { + self.node("1.1") + } + .nodeStyle { c in + c.node.foregroundStyle(Color.preferredColor(.negativeLabel)) + } + } + .nodeStyle { c in + c.node.font(Font.fiori(fixedSize: 16)) + .foregroundStyle(Color.preferredColor(.blue7)) } - SingleStep(id: "2.2") { - self.node("2.2") + SingleStep(id: "2") { + self.node("2") } substeps: { - SingleStep { - self.node("2.2.1") + SingleStep(id: "2.1") { + self.node("2.1") + } substeps: { + SingleStep { + self.node("2.1.1") + } } - .customStepId("2.2.1") - .stepLineModifier { - $0.foregroundColor(.clear) + + SingleStep(id: "2.2") { + self.node("2.2") + } substeps: { + SingleStep { + self.node("2.2.1") + } + // stepLineModifier will be deprecated, please use the latest modifier. + .lineStyle { c in + c.line.foregroundStyle(Color.clear) + } } } - } - }) + .nodeStyle { c in + c.node.font(Font.fiori(fixedSize: 12)) + } + .lineStyle { c in + c.line.foregroundStyle(Color.preferredColor(.negativeLabel)) + } + }) + } Spacer() }.padding() .onChange(of: self.selection) { newValue in @@ -420,7 +578,7 @@ struct SPIExampleByBuilder: View { func node(_ s: String, _ background: Color = Color.random) -> some View { ZStack { background - Text(s).font(Font.fiori(fixedSize: 10)) + Text(s) } .frame(width: 40, height: 40) .border(self.selection == s ? Color.black : Color.clear, width: 2) @@ -428,6 +586,7 @@ struct SPIExampleByBuilder: View { } struct SPICustomStyleExample: View { + let isDeprecated: Bool @State var title: String = "" @State var steps = [StepItemData(id: "1", title: "Step A", state: .completed), StepItemData(id: "2", title: "Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name Step B This is a very very long step name"), @@ -448,22 +607,51 @@ struct SPICustomStyleExample: View { var body: some View { VStack(alignment: .leading) { Text("Custom Styles").bold() - StepProgressIndicator(selection: self.$selection, stepItems: self.steps) { - Text(self.title).lineLimit(1) - } action: { - Button {} label: { - HStack(spacing: 2) { - Text("All Steps(\(self.steps.count)") - .foregroundStyle(Color.preferredColor(.tintColor)) - FioriIcon.actions.slimArrowRight - .font(.fiori(forTextStyle: .subheadline, weight: .semibold)) - .foregroundStyle(Color.preferredColor(.separator)) + if self.isDeprecated { + _StepProgressIndicator(selection: self.$selection, stepItems: self.steps) { + Text(self.title).lineLimit(1) + } action: { + Button {} label: { + HStack(spacing: 2) { + Text("All Steps(\(self.steps.count)") + .foregroundStyle(Color.preferredColor(.tintColor)) + FioriIcon.actions.slimArrowRight + .font(.fiori(forTextStyle: .subheadline, weight: .semibold)) + .foregroundStyle(Color.preferredColor(.separator)) + } } } + .stepStyle { _ in + CustomStyleExample() + } + } else { + StepProgressIndicator(selection: self.$selection, stepItems: self.steps) { + Text(self.title).lineLimit(1) + } action: { + Button {} label: { + HStack(spacing: 2) { + Text("All Steps(\(self.steps.count)") + FioriIcon.actions.slimArrowRight + .font(.fiori(forTextStyle: .subheadline, weight: .semibold)) + .foregroundStyle(Color.preferredColor(.separator)) + } + } + } + .stepStyle { _ in + CustomStyleExample() + } + .titleStyle { c in + c.title.font(.fiori(forTextStyle: .title1, weight: .semibold)) + .foregroundStyle(Color.preferredColor(.tintColor)) + } + .actionStyle { c in + c.action.foregroundStyle(Color.preferredColor(.negativeLabel)) + } + .cancelActionStyle { c in + c.cancelAction.font(.fiori(forTextStyle: .subheadline)).foregroundStyle(Color.preferredColor(.negativeLabel)) + } } - .stepStyle { _ in - CustomStyleExample() - } + Spacer().padding(20) Button { self.completeStep() diff --git a/Sources/FioriSwiftUICore/Models/ModelDefinitions.swift b/Sources/FioriSwiftUICore/Models/ModelDefinitions.swift index a80dd2c2d..26a40302b 100644 --- a/Sources/FioriSwiftUICore/Models/ModelDefinitions.swift +++ b/Sources/FioriSwiftUICore/Models/ModelDefinitions.swift @@ -433,7 +433,7 @@ public protocol KPIHeaderItemModel {} // sourcery: virtualPropStepState = "var state: StepProgressIndicatorState?" // sourcery: virtualPropIsLastStep = "var isLastStep: Bool = false" // sourcery: generated_component_composite -public protocol SingleStepModel { +public protocol _SingleStepModel { // sourcery: default.value = UUID().uuidString // sourcery: no_view var id: String { get set } @@ -446,9 +446,12 @@ public protocol SingleStepModel { // sourcery: backingComponent=_StepsContainer // sourcery: customFunctionBuilder=IndexedViewBuilder // sourcery: genericParameter.type=IndexedViewContainer - var substeps: [SingleStepModel] { get set } + var substeps: [_SingleStepModel] { get set } } +@available(*, unavailable, renamed: "_SingleStepModel", message: "Will be removed in the future release. Please use SingleStep instead.") +public protocol SingleStepModel {} + // sourcery: add_env_props = "presentationMode" // sourcery: virtualPropAxis = "var axis: Axis = .horizontal" // sourcery: virtualPropStepsData = "var stepItems: [StepItem] = []" @@ -456,7 +459,7 @@ public protocol SingleStepModel { // sourcery: virtualPropStepFrames = "@State var stepFrames: [String: CGRect] = [:]" // sourcery: virtualPropScrollBounds = "@State var scrollBounds: CGRect = .zero" // sourcery: generated_component_composite -public protocol StepProgressIndicatorModel: AnyObject { +public protocol _StepProgressIndicatorModel: AnyObject { // sourcery: bindingProperty // sourcery: no_view var selection: String { get set } @@ -471,13 +474,16 @@ public protocol StepProgressIndicatorModel: AnyObject { // sourcery: backingComponent=_StepsContainer // sourcery: customFunctionBuilder=IndexedViewBuilder // sourcery: genericParameter.type=IndexedViewContainer - var steps: [SingleStepModel] { get } + var steps: [_SingleStepModel] { get } // sourcery: genericParameter.name = CancelActionView // sourcery: default.value = _CancelActionDefault() var cancelAction: _ActionModel? { get } } +@available(*, unavailable, renamed: "_StepProgressIndicatorModel", message: "Will be removed in the future release. Please use StepProgressIndicator instead.") +public protocol StepProgressIndicatorModel {} + // sourcery: generated_component_composite public protocol FilterFeedbackBarModel: AnyObject { // sourcery: bindingProperty diff --git a/Sources/FioriSwiftUICore/Views/StepProgressIndicator/StepsStack.swift b/Sources/FioriSwiftUICore/Views/StepProgressIndicator/StepsStack.swift new file mode 100644 index 000000000..546225f8f --- /dev/null +++ b/Sources/FioriSwiftUICore/Views/StepProgressIndicator/StepsStack.swift @@ -0,0 +1,41 @@ +import SwiftUI + +struct StepsStack: View { + var steps: [StepItem] + var selection: Binding? = nil + /// :nodoc: + init(_ steps: [StepItem], selection: Binding? = nil) { + self.steps = steps + self.selection = selection + } + + var body: some View { + ForEach(0 ..< self.count, id: \.self) { index in + self.view(at: index) + } + } +} + +extension StepsStack: IndexedViewContainer { + /// :nodoc: + public var count: Int { + self.steps.count + } + + /// :nodoc: + @ViewBuilder public func view(at index: Int) -> some View { + if index < self.count { + _DefaultSteps(stepItems: self.steps, selection: self.selection ?? .constant("")).view(at: index) + } else { + EmptyView() + } + } + + @ViewBuilder func titleView(for title: String?) -> some View { + if let title { + Text(title) + } else { + EmptyView() + } + } +} diff --git a/Sources/FioriSwiftUICore/Views/StepProgressIndicator/_DefaultSteps.swift b/Sources/FioriSwiftUICore/Views/StepProgressIndicator/_DefaultSteps.swift index 0c6ad439d..d84bcbeca 100644 --- a/Sources/FioriSwiftUICore/Views/StepProgressIndicator/_DefaultSteps.swift +++ b/Sources/FioriSwiftUICore/Views/StepProgressIndicator/_DefaultSteps.swift @@ -90,7 +90,7 @@ struct DefaultSingleStep: View { func singleStep() -> some View { if self.stepItem.state.isSupported { let isSelected = self.stepItem.id == self.selection - SingleStep(id: self.stepItem.id) { + _SingleStep(id: self.stepItem.id) { if let title = stepItem.title { Text(title) } else { @@ -130,7 +130,7 @@ struct DefaultSingleStep: View { func singleSubstep() -> some View { if self.stepItem.state.isSupported { let isSelected = self.stepItem.id == self.selection - SingleStep(id: self.stepItem.id) { + _SingleStep(id: self.stepItem.id) { if let title = stepItem.title { Text(title) } else { diff --git a/Sources/FioriSwiftUICore/Views/StepProgressIndicator/SingleStep.swift b/Sources/FioriSwiftUICore/Views/StepProgressIndicator/_SingleStep.swift similarity index 97% rename from Sources/FioriSwiftUICore/Views/StepProgressIndicator/SingleStep.swift rename to Sources/FioriSwiftUICore/Views/StepProgressIndicator/_SingleStep.swift index 59b6d694c..7f0d4d0d9 100644 --- a/Sources/FioriSwiftUICore/Views/StepProgressIndicator/SingleStep.swift +++ b/Sources/FioriSwiftUICore/Views/StepProgressIndicator/_SingleStep.swift @@ -1,7 +1,7 @@ import SwiftUI extension Fiori { - enum SingleStep { + enum _SingleStep { typealias Title = EmptyModifier typealias TitleCumulative = EmptyModifier typealias Node = EmptyModifier @@ -37,7 +37,7 @@ public struct _StepNode: View { } } -public extension SingleStep where Title == _ConditionalContent, +public extension _SingleStep where Title == _ConditionalContent, Node == _StepNode, Substeps == _StepItemsContainer { @@ -56,7 +56,7 @@ public extension SingleStep where Title == _ConditionalContent, } } -public extension SingleStep where Substeps == EmptyView { +public extension _SingleStep where Substeps == EmptyView { /// Convenience initialization for empty sub-steps. /// - Parameters: /// - id: String value for step id. @@ -73,7 +73,7 @@ public extension SingleStep where Substeps == EmptyView { } } -public extension SingleStep where Title == EmptyView, Substeps == EmptyView { +public extension _SingleStep where Title == EmptyView, Substeps == EmptyView { /// Convenience initialization for empty title and sub-steps. /// - Parameters: /// - id: String value for step id. @@ -85,7 +85,7 @@ public extension SingleStep where Title == EmptyView, Substeps == EmptyView { } } -extension SingleStep: View { +extension _SingleStep: View { var stepsSpacing: CGFloat { 2 } diff --git a/Sources/FioriSwiftUICore/Views/StepProgressIndicator/StepProgressIndicator+View.swift b/Sources/FioriSwiftUICore/Views/StepProgressIndicator/_StepProgressIndicator+View.swift similarity index 97% rename from Sources/FioriSwiftUICore/Views/StepProgressIndicator/StepProgressIndicator+View.swift rename to Sources/FioriSwiftUICore/Views/StepProgressIndicator/_StepProgressIndicator+View.swift index 4717cca47..8b9ef2058 100644 --- a/Sources/FioriSwiftUICore/Views/StepProgressIndicator/StepProgressIndicator+View.swift +++ b/Sources/FioriSwiftUICore/Views/StepProgressIndicator/_StepProgressIndicator+View.swift @@ -2,7 +2,7 @@ import FioriThemeManager import SwiftUI extension Fiori { - enum StepProgressIndicator { + enum _StepProgressIndicator { typealias Title = EmptyModifier typealias TitleCumulative = EmptyModifier typealias Action = EmptyModifier @@ -18,7 +18,7 @@ extension Fiori { } } -extension StepProgressIndicator: View { +extension _StepProgressIndicator: View { var stepsCount: Int { steps.count } @@ -120,7 +120,7 @@ extension StepProgressIndicator: View { } /// :nodoc: -public extension StepProgressIndicator where Steps == _DefaultSteps, CancelActionView == _Action { +public extension _StepProgressIndicator where Steps == _DefaultSteps, CancelActionView == _Action { /// Convenience initialization for default step progress indicator. /// - Parameters: /// - selection: A binding string for selected step id. diff --git a/Sources/FioriSwiftUICore/Views/StepProgressIndicator/_StepsContainer.swift b/Sources/FioriSwiftUICore/Views/StepProgressIndicator/_StepsContainer.swift index 56fbaacbb..2b263624d 100644 --- a/Sources/FioriSwiftUICore/Views/StepProgressIndicator/_StepsContainer.swift +++ b/Sources/FioriSwiftUICore/Views/StepProgressIndicator/_StepsContainer.swift @@ -3,14 +3,14 @@ import SwiftUI /// Not used by developers. public struct _StepsContainer { - var steps: [SingleStepModel] + var steps: [_SingleStepModel] /// :nodoc: - public init(steps: [SingleStepModel]) { + public init(steps: [_SingleStepModel]) { self.steps = steps } /// :nodoc: - public init(substeps: [SingleStepModel]) { + public init(substeps: [_SingleStepModel]) { self.steps = substeps } } @@ -28,10 +28,10 @@ extension _StepsContainer: IndexedViewContainer { let title = self.steps[index].title let node = self.steps[index].node let substeps = self.steps[index].substeps - SingleStep(id: id, - title: title, - node: node, - substeps: substeps) + _SingleStep(id: id, + title: title, + node: node, + substeps: substeps) } else { EmptyView() } @@ -56,9 +56,18 @@ extension _StepItemsContainer: IndexedViewContainer { /// :nodoc: @ViewBuilder public func view(at index: Int) -> some View { if index < self.count { - SingleStep(item: self.steps[index]) + _SingleStep(item: self.steps[index]) } else { EmptyView() } } } + +extension _StepItemsContainer: View { + /// :nodoc: + public var body: some View { + ForEach(0 ..< self.count, id: \.self) { index in + self.view(at: index) + } + } +} diff --git a/Sources/FioriSwiftUICore/_ComponentProtocols/BaseComponentProtocols.swift b/Sources/FioriSwiftUICore/_ComponentProtocols/BaseComponentProtocols.swift index 3f79f960a..f74a6ac0b 100755 --- a/Sources/FioriSwiftUICore/_ComponentProtocols/BaseComponentProtocols.swift +++ b/Sources/FioriSwiftUICore/_ComponentProtocols/BaseComponentProtocols.swift @@ -467,3 +467,16 @@ protocol _ProgressComponent { // sourcery: defaultValue = "ProgressView()" var progress: ProgressView { get } } + +// sourcery: BaseComponent +protocol _NodeComponent { + // sourcery: resultBuilder.name = @ViewBuilder, resultBuilder.backingComponent = TextOrIconView + var node: TextOrIcon? { get } +} + +// sourcery: BaseComponent +protocol _LineComponent { + // sourcery: defaultValue = "{ Rectangle() }" + @ViewBuilder + var line: (() -> any View)? { get } +} diff --git a/Sources/FioriSwiftUICore/_ComponentProtocols/CompositeComponentProtocols.swift b/Sources/FioriSwiftUICore/_ComponentProtocols/CompositeComponentProtocols.swift index ed22ae321..277296be3 100755 --- a/Sources/FioriSwiftUICore/_ComponentProtocols/CompositeComponentProtocols.swift +++ b/Sources/FioriSwiftUICore/_ComponentProtocols/CompositeComponentProtocols.swift @@ -741,3 +741,47 @@ protocol _ActivityItemComponent: _IconComponent, _SubtitleComponent { // sourcery: defaultValue = .vertical var layout: ActivityItemLayout { get } } + +// sourcery: CompositeComponent +protocol _SingleStepComponent: _TitleComponent, _NodeComponent, _LineComponent { + // sourcery: default.value = UUID().uuidString + // sourcery: no_view + var id: String { get } + + // sourcery: default.value = .normal + // sourcery: no_view + var state: StepProgressIndicatorState { get } + + // sourcery: resultBuilder.backingComponent = StepsStack + // sourcery: resultBuilder.name = @IndexedViewBuilder + // sourcery: resultBuilder.returnType = any IndexedViewContainer + var substeps: [StepItem] { get } +} + +/// `StepProgressIndicator` is view support a list of `StepItem` in a horizontal stack. Also customized steps is also supported. +/// ## Usage +/// ```swift +/// @State var selection: String = "id" +/// var steps: [StepItem] = [] +/// StepProgressIndicator(selection: self.$selection, +/// stepItems: self.steps) +/// Also indexed view builder is also supported. +/// StepProgressIndicator(title: <#T##() -> any View#>, action: <#T##() -> any View#>, cancelAction: <#T##() -> any View#>, selection: <#T##Binding#>, steps: <#T##() -> any IndexedViewContainer#>) +/// ``` +/// Only `stepStyle` will continue to be supported. And other legacy modifiers will be deprecated in the future. Please use latest modifiers. +/// `func titleStyle(_ style: some TitleStyle) -> some View` +/// `func actionStyle(_ style: some ActionStyle) -> some View` +/// `func cancelActionStyle(_ style: some CancelActionStyle) -> some View` +/// `func lineStyle(_ style: some LineStyle) -> some View` +/// `func nodeStyle(_ style: some NodeStyle) -> some View` +/// `func stepStyle(_ style: @escaping ((_ id: String) -> (some StepStyle)?)) -> some View` +// sourcery: CompositeComponent +protocol _StepProgressIndicatorComponent: _TitleComponent, _ActionComponent, _CancelActionComponent { + // sourcery: @Binding + var selection: String { get } + + // sourcery: resultBuilder.backingComponent = StepsStack + // sourcery: resultBuilder.name = @IndexedViewBuilder + // sourcery: resultBuilder.returnType = any IndexedViewContainer + var steps: [StepItem] { get } +} diff --git a/Sources/FioriSwiftUICore/_FioriStyles/LineStyle.fiori.swift b/Sources/FioriSwiftUICore/_FioriStyles/LineStyle.fiori.swift new file mode 100644 index 000000000..597aac185 --- /dev/null +++ b/Sources/FioriSwiftUICore/_FioriStyles/LineStyle.fiori.swift @@ -0,0 +1,20 @@ +import FioriThemeManager +import Foundation +import SwiftUI + +// Base Layout style +public struct LineBaseStyle: LineStyle { + @ViewBuilder + public func makeBody(_ configuration: LineConfiguration) -> some View { + // Add default layout here + configuration.line + } +} + +// Default fiori styles +public struct LineFioriStyle: LineStyle { + @ViewBuilder + public func makeBody(_ configuration: LineConfiguration) -> some View { + Line(configuration) + } +} diff --git a/Sources/FioriSwiftUICore/_FioriStyles/NodeStyle.fiori.swift b/Sources/FioriSwiftUICore/_FioriStyles/NodeStyle.fiori.swift new file mode 100644 index 000000000..16d0c6ff3 --- /dev/null +++ b/Sources/FioriSwiftUICore/_FioriStyles/NodeStyle.fiori.swift @@ -0,0 +1,20 @@ +import FioriThemeManager +import Foundation +import SwiftUI + +// Base Layout style +public struct NodeBaseStyle: NodeStyle { + @ViewBuilder + public func makeBody(_ configuration: NodeConfiguration) -> some View { + // Add default layout here + configuration.node + } +} + +// Default fiori styles +public struct NodeFioriStyle: NodeStyle { + @ViewBuilder + public func makeBody(_ configuration: NodeConfiguration) -> some View { + Node(configuration) + } +} diff --git a/Sources/FioriSwiftUICore/_FioriStyles/SingleStepStyle.fiori.swift b/Sources/FioriSwiftUICore/_FioriStyles/SingleStepStyle.fiori.swift new file mode 100644 index 000000000..54454ab21 --- /dev/null +++ b/Sources/FioriSwiftUICore/_FioriStyles/SingleStepStyle.fiori.swift @@ -0,0 +1,145 @@ +import FioriThemeManager +import Foundation +import SwiftUI + +public extension SingleStep { + init(id: String = UUID().uuidString, + @ViewBuilder title: () -> any View, + @ViewBuilder node: () -> any View, + @IndexedViewBuilder substeps: () -> any IndexedViewContainer) + { + self.init(title: title, node: node, id: id, substeps: substeps) + } + + init(id: String = UUID().uuidString, + @ViewBuilder node: () -> any View, + @IndexedViewBuilder substeps: () -> any IndexedViewContainer) + { + self.init(title: { EmptyView() }, node: node, id: id, substeps: substeps) + } + + init(id: String = UUID().uuidString, + @ViewBuilder node: () -> any View) + { + self.init(title: { EmptyView() }, node: node, id: id) + } +} + +// Base Layout style +public struct SingleStepBaseStyle: SingleStepStyle { + @Environment(\.stepAxis) var stepAxis + @Environment(\.currentStepId) var currentStepId + + let stepsSpacing: CGFloat = 2 + + var horizontalSpacing: CGFloat = 8 + var leading: CGFloat = 8 + var top: CGFloat = 8 + var verticalSpacing: CGFloat = 8 + var trailing: CGFloat = 8 + var bottom: CGFloat = 8 + + /// :nodoc: + public func makeBody(_ configuration: SingleStepConfiguration) -> some View { + self.singleStep(configuration) + } + + @ViewBuilder + func singleStep(_ configuration: SingleStepConfiguration) -> some View { + let subSteps = configuration.substeps + switch self.stepAxis { + case .horizontal: + HStack(spacing: self.stepsSpacing) { + self.stepContainer(configuration) + ForEach(0 ..< subSteps.count, id: \.self) { index in + subSteps.view(at: index).typeErased + } + } + case .vertical: + VStack(spacing: self.stepsSpacing) { + self.stepContainer(configuration) + ForEach(0 ..< subSteps.count, id: \.self) { index in + subSteps.view(at: index).typeErased + } + } + } + } + + @ViewBuilder func stepContainer(_ configuration: SingleStepConfiguration) -> some View { + let _id = configuration.id + let state = configuration.state + let isLastStep = false + + Button { + if self.currentStepId.wrappedValue != _id, state != .disabled { + self.currentStepId.wrappedValue = _id + } + } label: { + // setup label in button style + EmptyView() + } + .buttonStyle(StepButtonStyle(id: _id, + node: configuration.node.typeErased, + title: configuration.title.typeErased, + line: configuration.line.typeErased, + state: state, + isSelected: self.currentStepId.wrappedValue == _id, + isLastStep: isLastStep, + isTitleEmptyView: configuration.title.isEmpty, + top: self.top, + bottom: self.bottom, + leading: self.leading, + trailing: self.trailing, + horizontalSpacing: self.horizontalSpacing, + verticalSpacing: self.verticalSpacing, + lineSize: nil)) + } +} + +// Default fiori styles +extension SingleStepFioriStyle { + struct ContentFioriStyle: SingleStepStyle { + func makeBody(_ configuration: SingleStepConfiguration) -> some View { + SingleStep(configuration) + } + } + + struct TitleFioriStyle: TitleStyle { + let singleStepConfiguration: SingleStepConfiguration + + func makeBody(_ configuration: TitleConfiguration) -> some View { + Title(configuration) + } + } + + struct NodeFioriStyle: NodeStyle { + let singleStepConfiguration: SingleStepConfiguration + + func makeBody(_ configuration: NodeConfiguration) -> some View { + Node(configuration) + } + + @ViewBuilder func node(_ singleStepConfiguration: SingleStepConfiguration) -> some View { + switch singleStepConfiguration.state { + case .normal: + Circle().strokeBorder(lineWidth: 2) + case .completed: + Circle().fill(Color.clear) + case .disabled: + let strokeStyle = StrokeStyle(lineWidth: 2, lineCap: .butt, lineJoin: .miter, miterLimit: 0, dash: [3], dashPhase: 0) + Circle() + .strokeBorder(style: strokeStyle) + default: + Circle().strokeBorder(lineWidth: 1) + } + } + } + + struct LineFioriStyle: LineStyle { + let singleStepConfiguration: SingleStepConfiguration + + func makeBody(_ configuration: LineConfiguration) -> some View { + Line(configuration) + } + } +} diff --git a/Sources/FioriSwiftUICore/_FioriStyles/StepProgressIndicatorStyle.fiori.swift b/Sources/FioriSwiftUICore/_FioriStyles/StepProgressIndicatorStyle.fiori.swift new file mode 100644 index 000000000..7702246e4 --- /dev/null +++ b/Sources/FioriSwiftUICore/_FioriStyles/StepProgressIndicatorStyle.fiori.swift @@ -0,0 +1,217 @@ +import FioriThemeManager +import Foundation +import SwiftUI + +/// :nodoc: +public extension StepProgressIndicator { + init(selection: Binding, + @ViewBuilder title: () -> any View = { EmptyView() }, + @ViewBuilder action: () -> any View = { EmptyView() }, + @ViewBuilder cancelAction: () -> any View = { FioriButton { _ in Text("Cancel".localizedFioriString()) } }, + @IndexedViewBuilder steps: () -> any IndexedViewContainer = { EmptyView() }) + { + self.init(title: title, action: action, cancelAction: cancelAction, selection: selection, steps: steps) + } + + /// Convenience initialization for default step progress indicator. + /// - Parameters: + /// - selection: A binding string for selected step id. + /// - stepItems: An array of `StepItem` for default steps generation. + /// - title: Title for current step displayed on steps top-left . + /// - action: Action for steps displayed on steps top-right that will show a vertical steps. + init(selection: Binding, + stepItems: [StepItem], + @ViewBuilder title: @escaping () -> any View, + @ViewBuilder action: @escaping () -> any View) + { + self.init(title: title, + action: action, + selection: selection, + steps: { StepsStack(stepItems, selection: selection) }) + } + + /// Convenience initialization for default step progress indicator. + /// - Parameters: + /// - selection: A binding string for selected step id. + /// - stepItems: An array of `StepItem` for default steps generation. + /// - title: Title for current step displayed on steps top-left . + init(selection: Binding, + stepItems: [StepItem], + @ViewBuilder title: @escaping () -> any View) + { + self.init(title: title, + selection: selection, + steps: { StepsStack(stepItems, selection: selection) }) + } + + /// Convenience initialization for default step progress indicator. + /// - Parameters: + /// - selection: A binding string for selected step id. + /// - stepItems: An array of `StepItem` for default steps generation. + /// - action: Action for steps displayed on steps top-right that will show a vertical steps. + init(selection: Binding, + stepItems: [StepItem], + @ViewBuilder action: @escaping () -> any View) + { + self.init(title: { EmptyView() }, + action: action, + selection: selection, + steps: { StepsStack(stepItems, selection: selection) }) + } + + /// Convenience initialization for default step progress indicator. + /// - Parameters: + /// - selection: A binding string for selected step id. + /// - stepItems: An array of `StepItem` for default steps generation. + init(selection: Binding, + stepItems: [StepItem]) + { + self.init(title: { EmptyView() }, + selection: selection, + steps: { StepsStack(stepItems, selection: selection) }) + } +} + +// Base Layout style +public struct StepProgressIndicatorBaseStyle: StepProgressIndicatorStyle { + @State var isPresented: Bool = false + @State var stepFrames: [String: CGRect] = [:] + @State var scrollBounds: CGRect = .zero + let stepsSpacing: CGFloat = 2 + + @ViewBuilder + public func makeBody(_ configuration: StepProgressIndicatorConfiguration) -> some View { + VStack(spacing: 0) { + self.stepsHeader(configuration) + self.stepsContainer(configuration, axis: .horizontal) + } + } + + @ViewBuilder func stepsHeader(_ configuration: StepProgressIndicatorConfiguration) -> some View { + if configuration.action.isEmpty, configuration.title.isEmpty { + EmptyView() + } else { + HStack(alignment: .center) { + configuration.title + .font(.fiori(forTextStyle: .headline, weight: .semibold)) + Spacer() + configuration.action + .onSimultaneousTapGesture(perform: { + self.isPresented.toggle() + }) + } + .frame(minHeight: 44) + .sheet(isPresented: self.$isPresented) { + NavigationStack { + ScrollViewReader { _ in + self.stepsContainer(configuration, axis: .vertical) + } + .navigationTitle(NSLocalizedString(NSLocalizedString("All Steps", tableName: "FioriSwiftUICore", bundle: Bundle.accessor, comment: "All Steps"), comment: "")) + .toolbar { + ToolbarItem(placement: .navigationBarLeading) { + configuration.cancelAction.onSimultaneousTapGesture { + self.isPresented.toggle() + } + } + } + .navigationBarBackButtonHidden(true) + } + } + } + } + + @ViewBuilder func stepsContainer(_ configuration: StepProgressIndicatorConfiguration, axis: Axis) -> some View { + switch axis { + case .horizontal: + ScrollViewReader { proxy in + ScrollView(.horizontal, showsIndicators: false) { + self.stepsGenerator(configuration, axis: .horizontal) + .environment(\.stepFrames, self.$stepFrames) + .setOnChange(of: configuration.$selection.wrappedValue, action1: { newValue in + if let currentFrame = stepFrames[newValue], + !scrollBounds.contains(currentFrame) + { + withAnimation { + proxy.scrollTo(newValue, anchor: .leading) + } + } + }) { _, newValue in + if let currentFrame = stepFrames[newValue], + !scrollBounds.contains(currentFrame) + { + withAnimation { + proxy.scrollTo(newValue, anchor: .leading) + } + } + } + } + } + .coordinateSpace(name: "SPICoordinateSpace") + .frameReader(in: .local) { rect in + self.scrollBounds = rect + } + case .vertical: + ScrollViewReader { _ in + ScrollView(.vertical, showsIndicators: false) { + self.stepsGenerator(configuration, axis: .vertical) + }.padding(20) + } + } + } + + @ViewBuilder func stepsGenerator(_ configuration: StepProgressIndicatorConfiguration, axis: Axis) -> some View { + switch axis { + case .horizontal: + HStack(alignment: .top, spacing: self.stepsSpacing) { + ForEach(0 ..< configuration.steps.count, id: \.self) { index in + configuration.steps.view(at: index).typeErased + .environment(\.stepAxis, axis) + .environment(\.currentStepId, configuration.$selection) + } + } + case .vertical: + VStack(alignment: .stepsLeadingAlignment, spacing: self.stepsSpacing) { + ForEach(0 ..< configuration.steps.count, id: \.self) { index in + configuration.steps.view(at: index).typeErased + .environment(\.stepAxis, axis) + .environment(\.currentStepId, configuration.$selection) + } + } + } + } +} + +// Default fiori styles +extension StepProgressIndicatorFioriStyle { + struct ContentFioriStyle: StepProgressIndicatorStyle { + func makeBody(_ configuration: StepProgressIndicatorConfiguration) -> some View { + StepProgressIndicator(configuration) + } + } + + struct TitleFioriStyle: TitleStyle { + let stepProgressIndicatorConfiguration: StepProgressIndicatorConfiguration + + func makeBody(_ configuration: TitleConfiguration) -> some View { + Title(configuration) + .font(.fiori(forTextStyle: .headline, weight: .semibold)) + } + } + + struct ActionFioriStyle: ActionStyle { + let stepProgressIndicatorConfiguration: StepProgressIndicatorConfiguration + + func makeBody(_ configuration: ActionConfiguration) -> some View { + Action(configuration) + } + } + + struct CancelActionFioriStyle: CancelActionStyle { + let stepProgressIndicatorConfiguration: StepProgressIndicatorConfiguration + + func makeBody(_ configuration: CancelActionConfiguration) -> some View { + CancelAction(configuration) + .fioriButtonStyle(FioriPlainButtonStyle()) + } + } +} diff --git a/Sources/FioriSwiftUICore/_generated/Components/EnvironmentKey+Styles.generated.swift b/Sources/FioriSwiftUICore/_generated/Components/EnvironmentKey+Styles.generated.swift index 2cf28252d..794134bda 100644 --- a/Sources/FioriSwiftUICore/_generated/Components/EnvironmentKey+Styles.generated.swift +++ b/Sources/FioriSwiftUICore/_generated/Components/EnvironmentKey+Styles.generated.swift @@ -210,10 +210,6 @@ struct SaveActionModifierKey: EnvironmentKey { public static let defaultValue = AnyViewModifier { $0 } } -struct NodeModifierKey: EnvironmentKey { - public static let defaultValue = AnyViewModifier { $0 } -} - struct ResetActionModifierKey: EnvironmentKey { public static let defaultValue = AnyViewModifier { $0 } } @@ -237,3 +233,7 @@ struct DenyActionModifierKey: EnvironmentKey { struct NotNowActionModifierKey: EnvironmentKey { public static let defaultValue = AnyViewModifier { $0 } } + +struct NodeModifierKey: EnvironmentKey { + public static let defaultValue = AnyViewModifier { $0 } +} diff --git a/Sources/FioriSwiftUICore/_generated/Components/EnvironmentValue+Styles.generated.swift b/Sources/FioriSwiftUICore/_generated/Components/EnvironmentValue+Styles.generated.swift index 377575186..c4c286b6c 100644 --- a/Sources/FioriSwiftUICore/_generated/Components/EnvironmentValue+Styles.generated.swift +++ b/Sources/FioriSwiftUICore/_generated/Components/EnvironmentValue+Styles.generated.swift @@ -264,11 +264,6 @@ extension EnvironmentValues { set { self[SaveActionModifierKey.self] = newValue } } - public var nodeModifier: AnyViewModifier { - get { return self[NodeModifierKey.self] } - set { self[NodeModifierKey.self] = newValue } - } - public var resetActionModifier: AnyViewModifier { get { return self[ResetActionModifierKey.self] } set { self[ResetActionModifierKey.self] = newValue } @@ -299,6 +294,11 @@ extension EnvironmentValues { set { self[NotNowActionModifierKey.self] = newValue } } + public var nodeModifier: AnyViewModifier { + get { return self[NodeModifierKey.self] } + set { self[NodeModifierKey.self] = newValue } + } + } public extension View { @@ -563,11 +563,6 @@ public extension View { self.environment(\.saveActionModifier, AnyViewModifier(transform)) } - @ViewBuilder - func nodeModifier(_ transform: @escaping (AnyViewModifier.Content) -> V) -> some View { - self.environment(\.nodeModifier, AnyViewModifier(transform)) - } - @ViewBuilder func resetActionModifier(_ transform: @escaping (AnyViewModifier.Content) -> V) -> some View { self.environment(\.resetActionModifier, AnyViewModifier(transform)) @@ -598,4 +593,9 @@ public extension View { self.environment(\.notNowActionModifier, AnyViewModifier(transform)) } + @ViewBuilder + func nodeModifier(_ transform: @escaping (AnyViewModifier.Content) -> V) -> some View { + self.environment(\.nodeModifier, AnyViewModifier(transform)) + } + } diff --git a/Sources/FioriSwiftUICore/_generated/StyleableComponents/Line/Line.generated.swift b/Sources/FioriSwiftUICore/_generated/StyleableComponents/Line/Line.generated.swift new file mode 100644 index 000000000..a62bf07ae --- /dev/null +++ b/Sources/FioriSwiftUICore/_generated/StyleableComponents/Line/Line.generated.swift @@ -0,0 +1,57 @@ +// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +import Foundation +import SwiftUI + +public struct Line { + let line: any View + + @Environment(\.lineStyle) var style + + fileprivate var _shouldApplyDefaultStyle = true + + public init(@ViewBuilder line: () -> any View = { Rectangle() }) { + self.line = line() + } +} + +public extension Line { + init(_ configuration: LineConfiguration) { + self.init(configuration, shouldApplyDefaultStyle: false) + } + + internal init(_ configuration: LineConfiguration, shouldApplyDefaultStyle: Bool) { + self.line = configuration.line + self._shouldApplyDefaultStyle = shouldApplyDefaultStyle + } +} + +extension Line: View { + public var body: some View { + if self._shouldApplyDefaultStyle { + self.defaultStyle() + } else { + self.style.resolve(configuration: .init(line: .init(self.line))).typeErased + .transformEnvironment(\.lineStyleStack) { stack in + if !stack.isEmpty { + stack.removeLast() + } + } + } + } +} + +private extension Line { + func shouldApplyDefaultStyle(_ bool: Bool) -> some View { + var s = self + s._shouldApplyDefaultStyle = bool + return s + } + + func defaultStyle() -> some View { + Line(.init(line: .init(self.line))) + .shouldApplyDefaultStyle(false) + .lineStyle(.fiori) + .typeErased + } +} diff --git a/Sources/FioriSwiftUICore/_generated/StyleableComponents/Line/LineStyle.generated.swift b/Sources/FioriSwiftUICore/_generated/StyleableComponents/Line/LineStyle.generated.swift new file mode 100644 index 000000000..5291f8d32 --- /dev/null +++ b/Sources/FioriSwiftUICore/_generated/StyleableComponents/Line/LineStyle.generated.swift @@ -0,0 +1,28 @@ +// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +import Foundation +import SwiftUI + +public protocol LineStyle: DynamicProperty { + associatedtype Body: View + + func makeBody(_ configuration: LineConfiguration) -> Body +} + +struct AnyLineStyle: LineStyle { + let content: (LineConfiguration) -> any View + + init(@ViewBuilder _ content: @escaping (LineConfiguration) -> any View) { + self.content = content + } + + public func makeBody(_ configuration: LineConfiguration) -> some View { + self.content(configuration).typeErased + } +} + +public struct LineConfiguration { + public let line: Line + + public typealias Line = ConfigurationViewWrapper +} diff --git a/Sources/FioriSwiftUICore/_generated/StyleableComponents/Node/Node.generated.swift b/Sources/FioriSwiftUICore/_generated/StyleableComponents/Node/Node.generated.swift new file mode 100644 index 000000000..f12bdf172 --- /dev/null +++ b/Sources/FioriSwiftUICore/_generated/StyleableComponents/Node/Node.generated.swift @@ -0,0 +1,63 @@ +// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +import Foundation +import SwiftUI + +public struct Node { + let node: any View + + @Environment(\.nodeStyle) var style + + fileprivate var _shouldApplyDefaultStyle = true + + public init(@ViewBuilder node: () -> any View = { EmptyView() }) { + self.node = node() + } +} + +public extension Node { + init(node: TextOrIcon? = nil) { + self.init(node: { TextOrIconView(node) }) + } +} + +public extension Node { + init(_ configuration: NodeConfiguration) { + self.init(configuration, shouldApplyDefaultStyle: false) + } + + internal init(_ configuration: NodeConfiguration, shouldApplyDefaultStyle: Bool) { + self.node = configuration.node + self._shouldApplyDefaultStyle = shouldApplyDefaultStyle + } +} + +extension Node: View { + public var body: some View { + if self._shouldApplyDefaultStyle { + self.defaultStyle() + } else { + self.style.resolve(configuration: .init(node: .init(self.node))).typeErased + .transformEnvironment(\.nodeStyleStack) { stack in + if !stack.isEmpty { + stack.removeLast() + } + } + } + } +} + +private extension Node { + func shouldApplyDefaultStyle(_ bool: Bool) -> some View { + var s = self + s._shouldApplyDefaultStyle = bool + return s + } + + func defaultStyle() -> some View { + Node(.init(node: .init(self.node))) + .shouldApplyDefaultStyle(false) + .nodeStyle(.fiori) + .typeErased + } +} diff --git a/Sources/FioriSwiftUICore/_generated/StyleableComponents/Node/NodeStyle.generated.swift b/Sources/FioriSwiftUICore/_generated/StyleableComponents/Node/NodeStyle.generated.swift new file mode 100644 index 000000000..633de22b8 --- /dev/null +++ b/Sources/FioriSwiftUICore/_generated/StyleableComponents/Node/NodeStyle.generated.swift @@ -0,0 +1,28 @@ +// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +import Foundation +import SwiftUI + +public protocol NodeStyle: DynamicProperty { + associatedtype Body: View + + func makeBody(_ configuration: NodeConfiguration) -> Body +} + +struct AnyNodeStyle: NodeStyle { + let content: (NodeConfiguration) -> any View + + init(@ViewBuilder _ content: @escaping (NodeConfiguration) -> any View) { + self.content = content + } + + public func makeBody(_ configuration: NodeConfiguration) -> some View { + self.content(configuration).typeErased + } +} + +public struct NodeConfiguration { + public let node: Node + + public typealias Node = ConfigurationViewWrapper +} diff --git a/Sources/FioriSwiftUICore/_generated/StyleableComponents/SingleStep/SingleStep.generated.swift b/Sources/FioriSwiftUICore/_generated/StyleableComponents/SingleStep/SingleStep.generated.swift new file mode 100644 index 000000000..40d896301 --- /dev/null +++ b/Sources/FioriSwiftUICore/_generated/StyleableComponents/SingleStep/SingleStep.generated.swift @@ -0,0 +1,90 @@ +// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +import Foundation +import SwiftUI + +public struct SingleStep { + let title: any View + let node: any View + let line: any View + let id: String + let state: StepProgressIndicatorState + let substeps: any IndexedViewContainer + + @Environment(\.singleStepStyle) var style + + fileprivate var _shouldApplyDefaultStyle = true + + public init(@ViewBuilder title: () -> any View, + @ViewBuilder node: () -> any View = { EmptyView() }, + @ViewBuilder line: () -> any View = { Rectangle() }, + id: String = UUID().uuidString, + state: StepProgressIndicatorState = .normal, + @IndexedViewBuilder substeps: () -> any IndexedViewContainer = { EmptyView() }) + { + self.title = Title(title: title) + self.node = Node(node: node) + self.line = Line(line: line) + self.id = id + self.state = state + self.substeps = substeps() + } +} + +public extension SingleStep { + init(title: AttributedString, + node: TextOrIcon? = nil, + @ViewBuilder line: () -> any View = { Rectangle() }, + id: String = UUID().uuidString, + state: StepProgressIndicatorState = .normal, + substeps: [StepItem] = []) + { + self.init(title: { Text(title) }, node: { TextOrIconView(node) }, line: line, id: id, state: state, substeps: { StepsStack(substeps) }) + } +} + +public extension SingleStep { + init(_ configuration: SingleStepConfiguration) { + self.init(configuration, shouldApplyDefaultStyle: false) + } + + internal init(_ configuration: SingleStepConfiguration, shouldApplyDefaultStyle: Bool) { + self.title = configuration.title + self.node = configuration.node + self.line = configuration.line + self.id = configuration.id + self.state = configuration.state + self.substeps = configuration.substeps + self._shouldApplyDefaultStyle = shouldApplyDefaultStyle + } +} + +extension SingleStep: View { + public var body: some View { + if self._shouldApplyDefaultStyle { + self.defaultStyle() + } else { + self.style.resolve(configuration: .init(title: .init(self.title), node: .init(self.node), line: .init(self.line), id: self.id, state: self.state, substeps: self.substeps)).typeErased + .transformEnvironment(\.singleStepStyleStack) { stack in + if !stack.isEmpty { + stack.removeLast() + } + } + } + } +} + +private extension SingleStep { + func shouldApplyDefaultStyle(_ bool: Bool) -> some View { + var s = self + s._shouldApplyDefaultStyle = bool + return s + } + + func defaultStyle() -> some View { + SingleStep(.init(title: .init(self.title), node: .init(self.node), line: .init(self.line), id: self.id, state: self.state, substeps: self.substeps)) + .shouldApplyDefaultStyle(false) + .singleStepStyle(SingleStepFioriStyle.ContentFioriStyle()) + .typeErased + } +} diff --git a/Sources/FioriSwiftUICore/_generated/StyleableComponents/SingleStep/SingleStepStyle.generated.swift b/Sources/FioriSwiftUICore/_generated/StyleableComponents/SingleStep/SingleStepStyle.generated.swift new file mode 100644 index 000000000..185eb04aa --- /dev/null +++ b/Sources/FioriSwiftUICore/_generated/StyleableComponents/SingleStep/SingleStepStyle.generated.swift @@ -0,0 +1,45 @@ +// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +import Foundation +import SwiftUI + +public protocol SingleStepStyle: DynamicProperty { + associatedtype Body: View + + func makeBody(_ configuration: SingleStepConfiguration) -> Body +} + +struct AnySingleStepStyle: SingleStepStyle { + let content: (SingleStepConfiguration) -> any View + + init(@ViewBuilder _ content: @escaping (SingleStepConfiguration) -> any View) { + self.content = content + } + + public func makeBody(_ configuration: SingleStepConfiguration) -> some View { + self.content(configuration).typeErased + } +} + +public struct SingleStepConfiguration { + public let title: Title + public let node: Node + public let line: Line + public let id: String + public let state: StepProgressIndicatorState + public let substeps: Substeps + + public typealias Title = ConfigurationViewWrapper + public typealias Node = ConfigurationViewWrapper + public typealias Line = ConfigurationViewWrapper + public typealias Substeps = any IndexedViewContainer +} + +public struct SingleStepFioriStyle: SingleStepStyle { + public func makeBody(_ configuration: SingleStepConfiguration) -> some View { + SingleStep(configuration) + .titleStyle(TitleFioriStyle(singleStepConfiguration: configuration)) + .nodeStyle(NodeFioriStyle(singleStepConfiguration: configuration)) + .lineStyle(LineFioriStyle(singleStepConfiguration: configuration)) + } +} diff --git a/Sources/FioriSwiftUICore/_generated/StyleableComponents/StepProgressIndicator/StepProgressIndicator.generated.swift b/Sources/FioriSwiftUICore/_generated/StyleableComponents/StepProgressIndicator/StepProgressIndicator.generated.swift new file mode 100644 index 000000000..a9e8620cc --- /dev/null +++ b/Sources/FioriSwiftUICore/_generated/StyleableComponents/StepProgressIndicator/StepProgressIndicator.generated.swift @@ -0,0 +1,102 @@ +// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +import Foundation +import SwiftUI + +/// `StepProgressIndicator` is view support a list of `StepItem` in a horizontal stack. Also customized steps is also supported. +/// ## Usage +/// ```swift +/// @State var selection: String = "id" +/// var steps: [StepItem] = [] +/// StepProgressIndicator(selection: self.$selection, +/// stepItems: self.steps) +/// Also indexed view builder is also supported. +/// StepProgressIndicator(title: <#T##() -> any View#>, action: <#T##() -> any View#>, cancelAction: <#T##() -> any View#>, selection: <#T##Binding#>, steps: <#T##() -> any IndexedViewContainer#>) +/// ``` +/// Only `stepStyle` will continue to be supported. And other legacy modifiers will be deprecated in the future. Please use latest modifiers. +/// `func titleStyle(_ style: some TitleStyle) -> some View` +/// `func actionStyle(_ style: some ActionStyle) -> some View` +/// `func cancelActionStyle(_ style: some CancelActionStyle) -> some View` +/// `func lineStyle(_ style: some LineStyle) -> some View` +/// `func nodeStyle(_ style: some NodeStyle) -> some View` +/// `func stepStyle(_ style: @escaping ((_ id: String) -> (some StepStyle)?)) -> some View` +public struct StepProgressIndicator { + let title: any View + let action: any View + let cancelAction: any View + @Binding var selection: String + let steps: any IndexedViewContainer + + @Environment(\.stepProgressIndicatorStyle) var style + + fileprivate var _shouldApplyDefaultStyle = true + + public init(@ViewBuilder title: () -> any View, + @ViewBuilder action: () -> any View = { EmptyView() }, + @ViewBuilder cancelAction: () -> any View = { FioriButton { _ in Text("Cancel".localizedFioriString()) } }, + selection: Binding, + @IndexedViewBuilder steps: () -> any IndexedViewContainer = { EmptyView() }) + { + self.title = Title(title: title) + self.action = Action(action: action) + self.cancelAction = CancelAction(cancelAction: cancelAction) + self._selection = selection + self.steps = steps() + } +} + +public extension StepProgressIndicator { + init(title: AttributedString, + action: FioriButton? = nil, + cancelAction: FioriButton? = FioriButton { _ in Text("Cancel".localizedFioriString()) }, + selection: Binding, + steps: [StepItem] = []) + { + self.init(title: { Text(title) }, action: { action }, cancelAction: { cancelAction }, selection: selection, steps: { StepsStack(steps) }) + } +} + +public extension StepProgressIndicator { + init(_ configuration: StepProgressIndicatorConfiguration) { + self.init(configuration, shouldApplyDefaultStyle: false) + } + + internal init(_ configuration: StepProgressIndicatorConfiguration, shouldApplyDefaultStyle: Bool) { + self.title = configuration.title + self.action = configuration.action + self.cancelAction = configuration.cancelAction + self._selection = configuration.$selection + self.steps = configuration.steps + self._shouldApplyDefaultStyle = shouldApplyDefaultStyle + } +} + +extension StepProgressIndicator: View { + public var body: some View { + if self._shouldApplyDefaultStyle { + self.defaultStyle() + } else { + self.style.resolve(configuration: .init(title: .init(self.title), action: .init(self.action), cancelAction: .init(self.cancelAction), selection: self.$selection, steps: self.steps)).typeErased + .transformEnvironment(\.stepProgressIndicatorStyleStack) { stack in + if !stack.isEmpty { + stack.removeLast() + } + } + } + } +} + +private extension StepProgressIndicator { + func shouldApplyDefaultStyle(_ bool: Bool) -> some View { + var s = self + s._shouldApplyDefaultStyle = bool + return s + } + + func defaultStyle() -> some View { + StepProgressIndicator(.init(title: .init(self.title), action: .init(self.action), cancelAction: .init(self.cancelAction), selection: self.$selection, steps: self.steps)) + .shouldApplyDefaultStyle(false) + .stepProgressIndicatorStyle(StepProgressIndicatorFioriStyle.ContentFioriStyle()) + .typeErased + } +} diff --git a/Sources/FioriSwiftUICore/_generated/StyleableComponents/StepProgressIndicator/StepProgressIndicatorStyle.generated.swift b/Sources/FioriSwiftUICore/_generated/StyleableComponents/StepProgressIndicator/StepProgressIndicatorStyle.generated.swift new file mode 100644 index 000000000..646952d6e --- /dev/null +++ b/Sources/FioriSwiftUICore/_generated/StyleableComponents/StepProgressIndicator/StepProgressIndicatorStyle.generated.swift @@ -0,0 +1,44 @@ +// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +import Foundation +import SwiftUI + +public protocol StepProgressIndicatorStyle: DynamicProperty { + associatedtype Body: View + + func makeBody(_ configuration: StepProgressIndicatorConfiguration) -> Body +} + +struct AnyStepProgressIndicatorStyle: StepProgressIndicatorStyle { + let content: (StepProgressIndicatorConfiguration) -> any View + + init(@ViewBuilder _ content: @escaping (StepProgressIndicatorConfiguration) -> any View) { + self.content = content + } + + public func makeBody(_ configuration: StepProgressIndicatorConfiguration) -> some View { + self.content(configuration).typeErased + } +} + +public struct StepProgressIndicatorConfiguration { + public let title: Title + public let action: Action + public let cancelAction: CancelAction + @Binding public var selection: String + public let steps: Steps + + public typealias Title = ConfigurationViewWrapper + public typealias Action = ConfigurationViewWrapper + public typealias CancelAction = ConfigurationViewWrapper + public typealias Steps = any IndexedViewContainer +} + +public struct StepProgressIndicatorFioriStyle: StepProgressIndicatorStyle { + public func makeBody(_ configuration: StepProgressIndicatorConfiguration) -> some View { + StepProgressIndicator(configuration) + .titleStyle(TitleFioriStyle(stepProgressIndicatorConfiguration: configuration)) + .actionStyle(ActionFioriStyle(stepProgressIndicatorConfiguration: configuration)) + .cancelActionStyle(CancelActionFioriStyle(stepProgressIndicatorConfiguration: configuration)) + } +} diff --git a/Sources/FioriSwiftUICore/_generated/SupportingFiles/ComponentStyleProtocol+Extension.generated.swift b/Sources/FioriSwiftUICore/_generated/SupportingFiles/ComponentStyleProtocol+Extension.generated.swift index e247b5ed0..144ffd17a 100755 --- a/Sources/FioriSwiftUICore/_generated/SupportingFiles/ComponentStyleProtocol+Extension.generated.swift +++ b/Sources/FioriSwiftUICore/_generated/SupportingFiles/ComponentStyleProtocol+Extension.generated.swift @@ -2572,6 +2572,20 @@ public extension LabelItemStyle where Self == LabelItemTitleStyle { } } +// MARK: LineStyle + +public extension LineStyle where Self == LineBaseStyle { + static var base: LineBaseStyle { + LineBaseStyle() + } +} + +public extension LineStyle where Self == LineFioriStyle { + static var fiori: LineFioriStyle { + LineFioriStyle() + } +} + // MARK: LinearProgressIndicatorStyle public extension LinearProgressIndicatorStyle where Self == LinearProgressIndicatorBaseStyle { @@ -3139,6 +3153,20 @@ public extension MoreActionOverflowStyle where Self == MoreActionOverflowFioriSt } } +// MARK: NodeStyle + +public extension NodeStyle where Self == NodeBaseStyle { + static var base: NodeBaseStyle { + NodeBaseStyle() + } +} + +public extension NodeStyle where Self == NodeFioriStyle { + static var fiori: NodeFioriStyle { + NodeFioriStyle() + } +} + // MARK: NoteFormViewStyle public extension NoteFormViewStyle where Self == NoteFormViewBaseStyle { @@ -4532,6 +4560,83 @@ public extension SideBarListItemStyle where Self == SideBarListItemSwitchStyle { } } +// MARK: SingleStepStyle + +public extension SingleStepStyle where Self == SingleStepBaseStyle { + static var base: SingleStepBaseStyle { + SingleStepBaseStyle() + } +} + +public extension SingleStepStyle where Self == SingleStepFioriStyle { + static var fiori: SingleStepFioriStyle { + SingleStepFioriStyle() + } +} + +public struct SingleStepTitleStyle: SingleStepStyle { + let style: any TitleStyle + + public func makeBody(_ configuration: SingleStepConfiguration) -> some View { + SingleStep(configuration) + .titleStyle(self.style) + .typeErased + } +} + +public extension SingleStepStyle where Self == SingleStepTitleStyle { + static func titleStyle(_ style: some TitleStyle) -> SingleStepTitleStyle { + SingleStepTitleStyle(style: style) + } + + static func titleStyle(@ViewBuilder content: @escaping (TitleConfiguration) -> some View) -> SingleStepTitleStyle { + let style = AnyTitleStyle(content) + return SingleStepTitleStyle(style: style) + } +} + +public struct SingleStepNodeStyle: SingleStepStyle { + let style: any NodeStyle + + public func makeBody(_ configuration: SingleStepConfiguration) -> some View { + SingleStep(configuration) + .nodeStyle(self.style) + .typeErased + } +} + +public extension SingleStepStyle where Self == SingleStepNodeStyle { + static func nodeStyle(_ style: some NodeStyle) -> SingleStepNodeStyle { + SingleStepNodeStyle(style: style) + } + + static func nodeStyle(@ViewBuilder content: @escaping (NodeConfiguration) -> some View) -> SingleStepNodeStyle { + let style = AnyNodeStyle(content) + return SingleStepNodeStyle(style: style) + } +} + +public struct SingleStepLineStyle: SingleStepStyle { + let style: any LineStyle + + public func makeBody(_ configuration: SingleStepConfiguration) -> some View { + SingleStep(configuration) + .lineStyle(self.style) + .typeErased + } +} + +public extension SingleStepStyle where Self == SingleStepLineStyle { + static func lineStyle(_ style: some LineStyle) -> SingleStepLineStyle { + SingleStepLineStyle(style: style) + } + + static func lineStyle(@ViewBuilder content: @escaping (LineConfiguration) -> some View) -> SingleStepLineStyle { + let style = AnyLineStyle(content) + return SingleStepLineStyle(style: style) + } +} + // MARK: StatusStyle public extension StatusStyle where Self == StatusBaseStyle { @@ -4546,6 +4651,83 @@ public extension StatusStyle where Self == StatusFioriStyle { } } +// MARK: StepProgressIndicatorStyle + +public extension StepProgressIndicatorStyle where Self == StepProgressIndicatorBaseStyle { + static var base: StepProgressIndicatorBaseStyle { + StepProgressIndicatorBaseStyle() + } +} + +public extension StepProgressIndicatorStyle where Self == StepProgressIndicatorFioriStyle { + static var fiori: StepProgressIndicatorFioriStyle { + StepProgressIndicatorFioriStyle() + } +} + +public struct StepProgressIndicatorTitleStyle: StepProgressIndicatorStyle { + let style: any TitleStyle + + public func makeBody(_ configuration: StepProgressIndicatorConfiguration) -> some View { + StepProgressIndicator(configuration) + .titleStyle(self.style) + .typeErased + } +} + +public extension StepProgressIndicatorStyle where Self == StepProgressIndicatorTitleStyle { + static func titleStyle(_ style: some TitleStyle) -> StepProgressIndicatorTitleStyle { + StepProgressIndicatorTitleStyle(style: style) + } + + static func titleStyle(@ViewBuilder content: @escaping (TitleConfiguration) -> some View) -> StepProgressIndicatorTitleStyle { + let style = AnyTitleStyle(content) + return StepProgressIndicatorTitleStyle(style: style) + } +} + +public struct StepProgressIndicatorActionStyle: StepProgressIndicatorStyle { + let style: any ActionStyle + + public func makeBody(_ configuration: StepProgressIndicatorConfiguration) -> some View { + StepProgressIndicator(configuration) + .actionStyle(self.style) + .typeErased + } +} + +public extension StepProgressIndicatorStyle where Self == StepProgressIndicatorActionStyle { + static func actionStyle(_ style: some ActionStyle) -> StepProgressIndicatorActionStyle { + StepProgressIndicatorActionStyle(style: style) + } + + static func actionStyle(@ViewBuilder content: @escaping (ActionConfiguration) -> some View) -> StepProgressIndicatorActionStyle { + let style = AnyActionStyle(content) + return StepProgressIndicatorActionStyle(style: style) + } +} + +public struct StepProgressIndicatorCancelActionStyle: StepProgressIndicatorStyle { + let style: any CancelActionStyle + + public func makeBody(_ configuration: StepProgressIndicatorConfiguration) -> some View { + StepProgressIndicator(configuration) + .cancelActionStyle(self.style) + .typeErased + } +} + +public extension StepProgressIndicatorStyle where Self == StepProgressIndicatorCancelActionStyle { + static func cancelActionStyle(_ style: some CancelActionStyle) -> StepProgressIndicatorCancelActionStyle { + StepProgressIndicatorCancelActionStyle(style: style) + } + + static func cancelActionStyle(@ViewBuilder content: @escaping (CancelActionConfiguration) -> some View) -> StepProgressIndicatorCancelActionStyle { + let style = AnyCancelActionStyle(content) + return StepProgressIndicatorCancelActionStyle(style: style) + } +} + // MARK: StepperFieldStyle public extension StepperFieldStyle where Self == StepperFieldBaseStyle { diff --git a/Sources/FioriSwiftUICore/_generated/SupportingFiles/EnvironmentVariables.generated.swift b/Sources/FioriSwiftUICore/_generated/SupportingFiles/EnvironmentVariables.generated.swift index afe031c81..1157633c4 100755 --- a/Sources/FioriSwiftUICore/_generated/SupportingFiles/EnvironmentVariables.generated.swift +++ b/Sources/FioriSwiftUICore/_generated/SupportingFiles/EnvironmentVariables.generated.swift @@ -990,6 +990,27 @@ extension EnvironmentValues { } } +// MARK: LineStyle + +struct LineStyleStackKey: EnvironmentKey { + static let defaultValue: [any LineStyle] = [] +} + +extension EnvironmentValues { + var lineStyle: any LineStyle { + self.lineStyleStack.last ?? .base + } + + var lineStyleStack: [any LineStyle] { + get { + self[LineStyleStackKey.self] + } + set { + self[LineStyleStackKey.self] = newValue + } + } +} + // MARK: LinearProgressIndicatorStyle struct LinearProgressIndicatorStyleStackKey: EnvironmentKey { @@ -1242,6 +1263,27 @@ extension EnvironmentValues { } } +// MARK: NodeStyle + +struct NodeStyleStackKey: EnvironmentKey { + static let defaultValue: [any NodeStyle] = [] +} + +extension EnvironmentValues { + var nodeStyle: any NodeStyle { + self.nodeStyleStack.last ?? .base + } + + var nodeStyleStack: [any NodeStyle] { + get { + self[NodeStyleStackKey.self] + } + set { + self[NodeStyleStackKey.self] = newValue + } + } +} + // MARK: NoteFormViewStyle struct NoteFormViewStyleStackKey: EnvironmentKey { @@ -1851,6 +1893,27 @@ extension EnvironmentValues { } } +// MARK: SingleStepStyle + +struct SingleStepStyleStackKey: EnvironmentKey { + static let defaultValue: [any SingleStepStyle] = [] +} + +extension EnvironmentValues { + var singleStepStyle: any SingleStepStyle { + self.singleStepStyleStack.last ?? .base.concat(.fiori) + } + + var singleStepStyleStack: [any SingleStepStyle] { + get { + self[SingleStepStyleStackKey.self] + } + set { + self[SingleStepStyleStackKey.self] = newValue + } + } +} + // MARK: StatusStyle struct StatusStyleStackKey: EnvironmentKey { @@ -1872,6 +1935,27 @@ extension EnvironmentValues { } } +// MARK: StepProgressIndicatorStyle + +struct StepProgressIndicatorStyleStackKey: EnvironmentKey { + static let defaultValue: [any StepProgressIndicatorStyle] = [] +} + +extension EnvironmentValues { + var stepProgressIndicatorStyle: any StepProgressIndicatorStyle { + self.stepProgressIndicatorStyleStack.last ?? .base.concat(.fiori) + } + + var stepProgressIndicatorStyleStack: [any StepProgressIndicatorStyle] { + get { + self[StepProgressIndicatorStyleStackKey.self] + } + set { + self[StepProgressIndicatorStyleStackKey.self] = newValue + } + } +} + // MARK: StepperFieldStyle struct StepperFieldStyleStackKey: EnvironmentKey { diff --git a/Sources/FioriSwiftUICore/_generated/SupportingFiles/ModifiedStyle.generated.swift b/Sources/FioriSwiftUICore/_generated/SupportingFiles/ModifiedStyle.generated.swift index 393373a5d..4c98d65f8 100755 --- a/Sources/FioriSwiftUICore/_generated/SupportingFiles/ModifiedStyle.generated.swift +++ b/Sources/FioriSwiftUICore/_generated/SupportingFiles/ModifiedStyle.generated.swift @@ -1324,6 +1324,34 @@ public extension LabelItemStyle { } } +// MARK: LineStyle + +extension ModifiedStyle: LineStyle where Style: LineStyle { + public func makeBody(_ configuration: LineConfiguration) -> some View { + Line(configuration) + .lineStyle(self.style) + .modifier(self.modifier) + } +} + +public struct LineStyleModifier: ViewModifier { + let style: Style + + public func body(content: Content) -> some View { + content.lineStyle(self.style) + } +} + +public extension LineStyle { + func modifier(_ modifier: some ViewModifier) -> some LineStyle { + ModifiedStyle(style: self, modifier: modifier) + } + + func concat(_ style: some LineStyle) -> some LineStyle { + style.modifier(LineStyleModifier(style: self)) + } +} + // MARK: LinearProgressIndicatorStyle extension ModifiedStyle: LinearProgressIndicatorStyle where Style: LinearProgressIndicatorStyle { @@ -1660,6 +1688,34 @@ public extension MoreActionOverflowStyle { } } +// MARK: NodeStyle + +extension ModifiedStyle: NodeStyle where Style: NodeStyle { + public func makeBody(_ configuration: NodeConfiguration) -> some View { + Node(configuration) + .nodeStyle(self.style) + .modifier(self.modifier) + } +} + +public struct NodeStyleModifier: ViewModifier { + let style: Style + + public func body(content: Content) -> some View { + content.nodeStyle(self.style) + } +} + +public extension NodeStyle { + func modifier(_ modifier: some ViewModifier) -> some NodeStyle { + ModifiedStyle(style: self, modifier: modifier) + } + + func concat(_ style: some NodeStyle) -> some NodeStyle { + style.modifier(NodeStyleModifier(style: self)) + } +} + // MARK: NoteFormViewStyle extension ModifiedStyle: NoteFormViewStyle where Style: NoteFormViewStyle { @@ -2472,6 +2528,34 @@ public extension SideBarListItemStyle { } } +// MARK: SingleStepStyle + +extension ModifiedStyle: SingleStepStyle where Style: SingleStepStyle { + public func makeBody(_ configuration: SingleStepConfiguration) -> some View { + SingleStep(configuration) + .singleStepStyle(self.style) + .modifier(self.modifier) + } +} + +public struct SingleStepStyleModifier: ViewModifier { + let style: Style + + public func body(content: Content) -> some View { + content.singleStepStyle(self.style) + } +} + +public extension SingleStepStyle { + func modifier(_ modifier: some ViewModifier) -> some SingleStepStyle { + ModifiedStyle(style: self, modifier: modifier) + } + + func concat(_ style: some SingleStepStyle) -> some SingleStepStyle { + style.modifier(SingleStepStyleModifier(style: self)) + } +} + // MARK: StatusStyle extension ModifiedStyle: StatusStyle where Style: StatusStyle { @@ -2500,6 +2584,34 @@ public extension StatusStyle { } } +// MARK: StepProgressIndicatorStyle + +extension ModifiedStyle: StepProgressIndicatorStyle where Style: StepProgressIndicatorStyle { + public func makeBody(_ configuration: StepProgressIndicatorConfiguration) -> some View { + StepProgressIndicator(configuration) + .stepProgressIndicatorStyle(self.style) + .modifier(self.modifier) + } +} + +public struct StepProgressIndicatorStyleModifier: ViewModifier { + let style: Style + + public func body(content: Content) -> some View { + content.stepProgressIndicatorStyle(self.style) + } +} + +public extension StepProgressIndicatorStyle { + func modifier(_ modifier: some ViewModifier) -> some StepProgressIndicatorStyle { + ModifiedStyle(style: self, modifier: modifier) + } + + func concat(_ style: some StepProgressIndicatorStyle) -> some StepProgressIndicatorStyle { + style.modifier(StepProgressIndicatorStyleModifier(style: self)) + } +} + // MARK: StepperFieldStyle extension ModifiedStyle: StepperFieldStyle where Style: StepperFieldStyle { diff --git a/Sources/FioriSwiftUICore/_generated/SupportingFiles/ResolvedStyle.generated.swift b/Sources/FioriSwiftUICore/_generated/SupportingFiles/ResolvedStyle.generated.swift index 6a394ebdb..34fe1a609 100755 --- a/Sources/FioriSwiftUICore/_generated/SupportingFiles/ResolvedStyle.generated.swift +++ b/Sources/FioriSwiftUICore/_generated/SupportingFiles/ResolvedStyle.generated.swift @@ -755,6 +755,22 @@ extension LabelItemStyle { } } +// MARK: LineStyle + +struct ResolvedLineStyle: View { + let style: Style + let configuration: LineConfiguration + var body: some View { + self.style.makeBody(self.configuration) + } +} + +extension LineStyle { + func resolve(configuration: LineConfiguration) -> some View { + ResolvedLineStyle(style: self, configuration: configuration) + } +} + // MARK: LinearProgressIndicatorStyle struct ResolvedLinearProgressIndicatorStyle: View { @@ -947,6 +963,22 @@ extension MoreActionOverflowStyle { } } +// MARK: NodeStyle + +struct ResolvedNodeStyle: View { + let style: Style + let configuration: NodeConfiguration + var body: some View { + self.style.makeBody(self.configuration) + } +} + +extension NodeStyle { + func resolve(configuration: NodeConfiguration) -> some View { + ResolvedNodeStyle(style: self, configuration: configuration) + } +} + // MARK: NoteFormViewStyle struct ResolvedNoteFormViewStyle: View { @@ -1411,6 +1443,22 @@ extension SideBarListItemStyle { } } +// MARK: SingleStepStyle + +struct ResolvedSingleStepStyle: View { + let style: Style + let configuration: SingleStepConfiguration + var body: some View { + self.style.makeBody(self.configuration) + } +} + +extension SingleStepStyle { + func resolve(configuration: SingleStepConfiguration) -> some View { + ResolvedSingleStepStyle(style: self, configuration: configuration) + } +} + // MARK: StatusStyle struct ResolvedStatusStyle: View { @@ -1427,6 +1475,22 @@ extension StatusStyle { } } +// MARK: StepProgressIndicatorStyle + +struct ResolvedStepProgressIndicatorStyle: View { + let style: Style + let configuration: StepProgressIndicatorConfiguration + var body: some View { + self.style.makeBody(self.configuration) + } +} + +extension StepProgressIndicatorStyle { + func resolve(configuration: StepProgressIndicatorConfiguration) -> some View { + ResolvedStepProgressIndicatorStyle(style: self, configuration: configuration) + } +} + // MARK: StepperFieldStyle struct ResolvedStepperFieldStyle: View { diff --git a/Sources/FioriSwiftUICore/_generated/SupportingFiles/View+Extension_.generated.swift b/Sources/FioriSwiftUICore/_generated/SupportingFiles/View+Extension_.generated.swift index 04f05b78e..e13a275e9 100755 --- a/Sources/FioriSwiftUICore/_generated/SupportingFiles/View+Extension_.generated.swift +++ b/Sources/FioriSwiftUICore/_generated/SupportingFiles/View+Extension_.generated.swift @@ -802,6 +802,23 @@ public extension View { } } +// MARK: LineStyle + +public extension View { + func lineStyle(_ style: some LineStyle) -> some View { + self.transformEnvironment(\.lineStyleStack) { stack in + stack.append(style) + } + } + + func lineStyle(@ViewBuilder content: @escaping (LineConfiguration) -> some View) -> some View { + self.transformEnvironment(\.lineStyleStack) { stack in + let style = AnyLineStyle(content) + stack.append(style) + } + } +} + // MARK: LinearProgressIndicatorStyle public extension View { @@ -1006,6 +1023,23 @@ public extension View { } } +// MARK: NodeStyle + +public extension View { + func nodeStyle(_ style: some NodeStyle) -> some View { + self.transformEnvironment(\.nodeStyleStack) { stack in + stack.append(style) + } + } + + func nodeStyle(@ViewBuilder content: @escaping (NodeConfiguration) -> some View) -> some View { + self.transformEnvironment(\.nodeStyleStack) { stack in + let style = AnyNodeStyle(content) + stack.append(style) + } + } +} + // MARK: NoteFormViewStyle public extension View { @@ -1499,6 +1533,23 @@ public extension View { } } +// MARK: SingleStepStyle + +public extension View { + func singleStepStyle(_ style: some SingleStepStyle) -> some View { + self.transformEnvironment(\.singleStepStyleStack) { stack in + stack.append(style) + } + } + + func singleStepStyle(@ViewBuilder content: @escaping (SingleStepConfiguration) -> some View) -> some View { + self.transformEnvironment(\.singleStepStyleStack) { stack in + let style = AnySingleStepStyle(content) + stack.append(style) + } + } +} + // MARK: StatusStyle public extension View { @@ -1516,6 +1567,23 @@ public extension View { } } +// MARK: StepProgressIndicatorStyle + +public extension View { + func stepProgressIndicatorStyle(_ style: some StepProgressIndicatorStyle) -> some View { + self.transformEnvironment(\.stepProgressIndicatorStyleStack) { stack in + stack.append(style) + } + } + + func stepProgressIndicatorStyle(@ViewBuilder content: @escaping (StepProgressIndicatorConfiguration) -> some View) -> some View { + self.transformEnvironment(\.stepProgressIndicatorStyleStack) { stack in + let style = AnyStepProgressIndicatorStyle(content) + stack.append(style) + } + } +} + // MARK: StepperFieldStyle public extension View { diff --git a/Sources/FioriSwiftUICore/_generated/SupportingFiles/ViewEmptyChecking+Extension.generated.swift b/Sources/FioriSwiftUICore/_generated/SupportingFiles/ViewEmptyChecking+Extension.generated.swift index 6ffb7e45c..a7fef1868 100755 --- a/Sources/FioriSwiftUICore/_generated/SupportingFiles/ViewEmptyChecking+Extension.generated.swift +++ b/Sources/FioriSwiftUICore/_generated/SupportingFiles/ViewEmptyChecking+Extension.generated.swift @@ -350,6 +350,12 @@ extension LabelItem: _ViewEmptyChecking { } } +extension Line: _ViewEmptyChecking { + public var isEmpty: Bool { + line.isEmpty + } +} + extension LinearProgressIndicator: _ViewEmptyChecking { public var isEmpty: Bool { false @@ -435,6 +441,12 @@ extension MoreActionOverflow: _ViewEmptyChecking { } } +extension Node: _ViewEmptyChecking { + public var isEmpty: Bool { + node.isEmpty + } +} + extension NoteFormView: _ViewEmptyChecking { public var isEmpty: Bool { placeholder.isEmpty @@ -641,12 +653,30 @@ extension SideBarListItem: _ViewEmptyChecking { } } +extension SingleStep: _ViewEmptyChecking { + public var isEmpty: Bool { + title.isEmpty && + node.isEmpty && + line.isEmpty && + substeps.isEmpty + } +} + extension Status: _ViewEmptyChecking { public var isEmpty: Bool { status.isEmpty } } +extension StepProgressIndicator: _ViewEmptyChecking { + public var isEmpty: Bool { + title.isEmpty && + action.isEmpty && + cancelAction.isEmpty && + steps.isEmpty + } +} + extension StepperField: _ViewEmptyChecking { public var isEmpty: Bool { decrementAction.isEmpty && diff --git a/Sources/FioriSwiftUICore/_generated/ViewModels/API/SingleStep+API.generated.swift b/Sources/FioriSwiftUICore/_generated/ViewModels/API/_SingleStep+API.generated.swift similarity index 76% rename from Sources/FioriSwiftUICore/_generated/ViewModels/API/SingleStep+API.generated.swift rename to Sources/FioriSwiftUICore/_generated/ViewModels/API/_SingleStep+API.generated.swift index 2dd398a18..63bdfd7b2 100644 --- a/Sources/FioriSwiftUICore/_generated/ViewModels/API/SingleStep+API.generated.swift +++ b/Sources/FioriSwiftUICore/_generated/ViewModels/API/_SingleStep+API.generated.swift @@ -2,7 +2,7 @@ // DO NOT EDIT import SwiftUI -public struct SingleStep { +public struct _SingleStep { @Environment(\.titleModifier) private var titleModifier @Environment(\.nodeModifier) private var nodeModifier @Environment(\.stepStyle) var stepStyle @@ -41,16 +41,16 @@ public struct SingleStep, +extension _SingleStep where Title == _ConditionalContent, Node == TextOrIconView, Substeps == _StepsContainer { - public init(model: SingleStepModel) { + public init(model: _SingleStepModel) { self.init(id: model.id, title: model.title, node: model.node, substeps: model.substeps) } - public init(id: String = UUID().uuidString, title: String? = nil, node: TextOrIcon, substeps: [SingleStepModel] = []) { + public init(id: String = UUID().uuidString, title: String? = nil, node: TextOrIcon, substeps: [_SingleStepModel] = []) { self._id = id self._title = title != nil ? ViewBuilder.buildEither(first: Text(title!)) : ViewBuilder.buildEither(second: EmptyView()) self._node = TextOrIconView(node: node) diff --git a/Sources/FioriSwiftUICore/_generated/ViewModels/API/StepProgressIndicator+API.generated.swift b/Sources/FioriSwiftUICore/_generated/ViewModels/API/_StepProgressIndicator+API.generated.swift similarity index 77% rename from Sources/FioriSwiftUICore/_generated/ViewModels/API/StepProgressIndicator+API.generated.swift rename to Sources/FioriSwiftUICore/_generated/ViewModels/API/_StepProgressIndicator+API.generated.swift index 2c2a3f1b6..e1d5d0f9f 100644 --- a/Sources/FioriSwiftUICore/_generated/ViewModels/API/StepProgressIndicator+API.generated.swift +++ b/Sources/FioriSwiftUICore/_generated/ViewModels/API/_StepProgressIndicator+API.generated.swift @@ -2,7 +2,7 @@ // DO NOT EDIT import SwiftUI -public struct StepProgressIndicator { +public struct _StepProgressIndicator { @Environment(\.titleModifier) private var titleModifier @Environment(\.actionModifier) private var actionModifier @Environment(\.cancelActionModifier) private var cancelActionModifier @@ -40,16 +40,16 @@ public struct StepProgressIndicator, +extension _StepProgressIndicator where Title == _ConditionalContent, ActionView == _ConditionalContent<_Action, EmptyView>, Steps == _StepsContainer, CancelActionView == _ConditionalContent<_Action, EmptyView> { - public init(model: StepProgressIndicatorModel) { + public init(model: _StepProgressIndicatorModel) { self.init(selection: Binding(get: { model.selection }, set: { model.selection = $0 }), title: model.title, action: model.action != nil ? _Action(model: model.action!) : nil, steps: model.steps, cancelAction: model.cancelAction != nil ? _Action(model: model.cancelAction!) : nil) } - public init(selection: Binding, title: String? = nil, action: _Action? = _Action(model: _AllStepsActionDefault()), steps: [SingleStepModel] = [], cancelAction: _Action? = _Action(model: _CancelActionDefault())) { + public init(selection: Binding, title: String? = nil, action: _Action? = _Action(model: _AllStepsActionDefault()), steps: [_SingleStepModel] = [], cancelAction: _Action? = _Action(model: _CancelActionDefault())) { self._selection = selection self._title = title != nil ? ViewBuilder.buildEither(first: Text(title!)) : ViewBuilder.buildEither(second: EmptyView()) self._action = action != nil ? ViewBuilder.buildEither(first: action!) : ViewBuilder.buildEither(second: EmptyView()) diff --git a/Sources/FioriSwiftUICore/_generated/ViewModels/Boilerplate/_SingleStep+View.generated.swift b/Sources/FioriSwiftUICore/_generated/ViewModels/Boilerplate/_SingleStep+View.generated.swift new file mode 100644 index 000000000..12e941c58 --- /dev/null +++ b/Sources/FioriSwiftUICore/_generated/ViewModels/Boilerplate/_SingleStep+View.generated.swift @@ -0,0 +1,62 @@ +// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +//TODO: Copy commented code to new file: `FioriSwiftUICore/Views/_SingleStep+View.swift` +//TODO: Implement default Fiori style definitions as `ViewModifier` +//TODO: Implement _SingleStep `View` body +//TODO: Implement LibraryContentProvider + +/// - Important: to make `@Environment` properties (e.g. `horizontalSizeClass`), internally accessible +/// to extensions, add as sourcery annotation in `FioriSwiftUICore/Models/ModelDefinitions.swift` +/// to declare a wrapped property +/// e.g.: `// sourcery: add_env_props = ["horizontalSizeClass"]` + +/* +import SwiftUI + +// FIXME: - Implement Fiori style definitions + +extension Fiori { + enum _SingleStep { + typealias Title = EmptyModifier + typealias TitleCumulative = EmptyModifier + typealias Node = EmptyModifier + typealias NodeCumulative = EmptyModifier + + // TODO: - substitute type-specific ViewModifier for EmptyModifier + /* + // replace `typealias Subtitle = EmptyModifier` with: + + struct Subtitle: ViewModifier { + func body(content: Content) -> some View { + content + .font(.body) + .foregroundColor(.preferredColor(.primary3)) + } + } + */ + static let title = Title() + static let node = Node() + static let titleCumulative = TitleCumulative() + static let nodeCumulative = NodeCumulative() + } +} + +// FIXME: - Implement _SingleStep View body + +extension _SingleStep: View { + public var body: some View { + <# View body #> + } +} + +// FIXME: - Implement _SingleStep specific LibraryContentProvider + +@available(iOS 14.0, macOS 11.0, *) +struct _SingleStepLibraryContent: LibraryContentProvider { + @LibraryContentBuilder + var views: [LibraryItem] { + LibraryItem(_SingleStep(model: LibraryPreviewData.Person.laurelosborn), + category: .control) + } +} +*/ diff --git a/Sources/FioriSwiftUICore/_generated/ViewModels/Boilerplate/_StepProgressIndicator+View.generated.swift b/Sources/FioriSwiftUICore/_generated/ViewModels/Boilerplate/_StepProgressIndicator+View.generated.swift new file mode 100644 index 000000000..8cc158e8d --- /dev/null +++ b/Sources/FioriSwiftUICore/_generated/ViewModels/Boilerplate/_StepProgressIndicator+View.generated.swift @@ -0,0 +1,66 @@ +// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +//TODO: Copy commented code to new file: `FioriSwiftUICore/Views/_StepProgressIndicator+View.swift` +//TODO: Implement default Fiori style definitions as `ViewModifier` +//TODO: Implement _StepProgressIndicator `View` body +//TODO: Implement LibraryContentProvider + +/// - Important: to make `@Environment` properties (e.g. `horizontalSizeClass`), internally accessible +/// to extensions, add as sourcery annotation in `FioriSwiftUICore/Models/ModelDefinitions.swift` +/// to declare a wrapped property +/// e.g.: `// sourcery: add_env_props = ["horizontalSizeClass"]` + +/* +import SwiftUI + +// FIXME: - Implement Fiori style definitions + +extension Fiori { + enum _StepProgressIndicator { + typealias Title = EmptyModifier + typealias TitleCumulative = EmptyModifier + typealias Action = EmptyModifier + typealias ActionCumulative = EmptyModifier + typealias CancelAction = EmptyModifier + typealias CancelActionCumulative = EmptyModifier + + // TODO: - substitute type-specific ViewModifier for EmptyModifier + /* + // replace `typealias Subtitle = EmptyModifier` with: + + struct Subtitle: ViewModifier { + func body(content: Content) -> some View { + content + .font(.body) + .foregroundColor(.preferredColor(.primary3)) + } + } + */ + static let title = Title() + static let action = Action() + static let cancelAction = CancelAction() + static let titleCumulative = TitleCumulative() + static let actionCumulative = ActionCumulative() + static let cancelActionCumulative = CancelActionCumulative() + } +} + +// FIXME: - Implement _StepProgressIndicator View body + +extension _StepProgressIndicator: View { + public var body: some View { + <# View body #> + } +} + +// FIXME: - Implement _StepProgressIndicator specific LibraryContentProvider + +@available(iOS 14.0, macOS 11.0, *) +struct _StepProgressIndicatorLibraryContent: LibraryContentProvider { + @LibraryContentBuilder + var views: [LibraryItem] { + LibraryItem(_StepProgressIndicator(model: LibraryPreviewData.Person.laurelosborn), + category: .control) + } +} +*/ diff --git a/Sources/FioriSwiftUICore/_generated/ViewModels/Init+Extensions/SingleStep+Init.generated.swift b/Sources/FioriSwiftUICore/_generated/ViewModels/Init+Extensions/_SingleStep+Init.generated.swift similarity index 88% rename from Sources/FioriSwiftUICore/_generated/ViewModels/Init+Extensions/SingleStep+Init.generated.swift rename to Sources/FioriSwiftUICore/_generated/ViewModels/Init+Extensions/_SingleStep+Init.generated.swift index dc4e59edf..cc30ccb26 100644 --- a/Sources/FioriSwiftUICore/_generated/ViewModels/Init+Extensions/SingleStep+Init.generated.swift +++ b/Sources/FioriSwiftUICore/_generated/ViewModels/Init+Extensions/_SingleStep+Init.generated.swift @@ -2,7 +2,7 @@ // DO NOT EDIT import SwiftUI -extension SingleStep where Title == EmptyView { +extension _SingleStep where Title == EmptyView { public init( id: String = UUID().uuidString, @ViewBuilder node: () -> Node, diff --git a/Sources/FioriSwiftUICore/_generated/ViewModels/Init+Extensions/StepProgressIndicator+Init.generated.swift b/Sources/FioriSwiftUICore/_generated/ViewModels/Init+Extensions/_StepProgressIndicator+Init.generated.swift similarity index 81% rename from Sources/FioriSwiftUICore/_generated/ViewModels/Init+Extensions/StepProgressIndicator+Init.generated.swift rename to Sources/FioriSwiftUICore/_generated/ViewModels/Init+Extensions/_StepProgressIndicator+Init.generated.swift index 091996fcd..851061a92 100644 --- a/Sources/FioriSwiftUICore/_generated/ViewModels/Init+Extensions/StepProgressIndicator+Init.generated.swift +++ b/Sources/FioriSwiftUICore/_generated/ViewModels/Init+Extensions/_StepProgressIndicator+Init.generated.swift @@ -2,7 +2,7 @@ // DO NOT EDIT import SwiftUI -extension StepProgressIndicator where Title == EmptyView { +extension _StepProgressIndicator where Title == EmptyView { public init( selection: Binding, @ViewBuilder action: () -> ActionView, @@ -19,7 +19,7 @@ extension StepProgressIndicator where Title == EmptyView { } } -extension StepProgressIndicator where ActionView == _Action { +extension _StepProgressIndicator where ActionView == _Action { public init( selection: Binding, @ViewBuilder title: () -> Title, @@ -36,7 +36,7 @@ extension StepProgressIndicator where ActionView == _Action { } } -extension StepProgressIndicator where CancelActionView == _Action { +extension _StepProgressIndicator where CancelActionView == _Action { public init( selection: Binding, @ViewBuilder title: () -> Title, @@ -53,7 +53,7 @@ extension StepProgressIndicator where CancelActionView == _Action { } } -extension StepProgressIndicator where Title == EmptyView, ActionView == _Action { +extension _StepProgressIndicator where Title == EmptyView, ActionView == _Action { public init( selection: Binding, @IndexedViewBuilder steps: () -> Steps, @@ -69,7 +69,7 @@ extension StepProgressIndicator where Title == EmptyView, ActionView == _Action } } -extension StepProgressIndicator where Title == EmptyView, CancelActionView == _Action { +extension _StepProgressIndicator where Title == EmptyView, CancelActionView == _Action { public init( selection: Binding, @ViewBuilder action: () -> ActionView, @@ -85,7 +85,7 @@ extension StepProgressIndicator where Title == EmptyView, CancelActionView == _A } } -extension StepProgressIndicator where ActionView == _Action, CancelActionView == _Action { +extension _StepProgressIndicator where ActionView == _Action, CancelActionView == _Action { public init( selection: Binding, @ViewBuilder title: () -> Title, @@ -101,7 +101,7 @@ extension StepProgressIndicator where ActionView == _Action, CancelActionView == } } -extension StepProgressIndicator where Title == EmptyView, ActionView == _Action, CancelActionView == _Action { +extension _StepProgressIndicator where Title == EmptyView, ActionView == _Action, CancelActionView == _Action { public init( selection: Binding, @IndexedViewBuilder steps: () -> Steps diff --git a/Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/SingleStepModel+Extensions.generated.swift b/Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/_SingleStepModel+Extensions.generated.swift similarity index 86% rename from Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/SingleStepModel+Extensions.generated.swift rename to Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/_SingleStepModel+Extensions.generated.swift index 76691baf9..21a5c40c0 100644 --- a/Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/SingleStepModel+Extensions.generated.swift +++ b/Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/_SingleStepModel+Extensions.generated.swift @@ -2,7 +2,7 @@ // DO NOT EDIT import SwiftUI -public extension SingleStepModel { +public extension _SingleStepModel { var id: String { return UUID().uuidString } diff --git a/Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/StepProgressIndicatorModel+Extensions.generated.swift b/Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/_StepProgressIndicatorModel+Extensions.generated.swift similarity index 87% rename from Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/StepProgressIndicatorModel+Extensions.generated.swift rename to Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/_StepProgressIndicatorModel+Extensions.generated.swift index 91d7cb7e2..a11a577bf 100644 --- a/Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/StepProgressIndicatorModel+Extensions.generated.swift +++ b/Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/_StepProgressIndicatorModel+Extensions.generated.swift @@ -2,7 +2,7 @@ // DO NOT EDIT import SwiftUI -public extension StepProgressIndicatorModel { +public extension _StepProgressIndicatorModel { var action: _ActionModel? { return _AllStepsActionDefault() } diff --git a/Sources/FioriSwiftUICore/_localization/en.lproj/FioriSwiftUICore.strings b/Sources/FioriSwiftUICore/_localization/en.lproj/FioriSwiftUICore.strings index f82bc59cd..3ee20bd76 100644 --- a/Sources/FioriSwiftUICore/_localization/en.lproj/FioriSwiftUICore.strings +++ b/Sources/FioriSwiftUICore/_localization/en.lproj/FioriSwiftUICore.strings @@ -301,3 +301,6 @@ /* Progress Indicator accessibility label: progress halted with indicator progress */ "Progress halted, %.0f" = "Progress halted, %.0f"; + +/* XTIT: Title of step progress indicator, see https://experience.sap.com/fiori-design-ios/article/step-progress-indicator/#adaptive-design */ +"All Steps" = "All Steps"; diff --git a/sourcery/.lib/Sources/utils/Type+Extensions.swift b/sourcery/.lib/Sources/utils/Type+Extensions.swift index b700f461d..2ea7c67f0 100644 --- a/sourcery/.lib/Sources/utils/Type+Extensions.swift +++ b/sourcery/.lib/Sources/utils/Type+Extensions.swift @@ -74,7 +74,9 @@ public extension Type { "_SideBarModel", "_SideBarListItemModel", "_ActivityItemModel", - "_ProgressIndicatorModel"] + "_ProgressIndicatorModel", + "_SingleStepModel", + "_StepProgressIndicatorModel"] if deprecatedComponents.contains(name) { return name.replacingOccurrences(of: "Model", with: "") From c29d09cea8d24996d4b80b364c89cb5f16f576b1 Mon Sep 17 00:00:00 2001 From: xiaoyu0722 Date: Fri, 20 Dec 2024 16:18:53 +0800 Subject: [PATCH 2/2] =?UTF-8?q?docs:=20=E2=9C=8F=EF=B8=8F=20update?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_StepProgressIndicator+View.swift | 16 ++++++++-------- .../CompositeComponentProtocols.swift | 9 ++------- .../StepProgressIndicatorStyle.fiori.swift | 16 ++++++++-------- .../StepProgressIndicator.generated.swift | 9 ++------- 4 files changed, 20 insertions(+), 30 deletions(-) diff --git a/Sources/FioriSwiftUICore/Views/StepProgressIndicator/_StepProgressIndicator+View.swift b/Sources/FioriSwiftUICore/Views/StepProgressIndicator/_StepProgressIndicator+View.swift index 8b9ef2058..2dbcb483b 100644 --- a/Sources/FioriSwiftUICore/Views/StepProgressIndicator/_StepProgressIndicator+View.swift +++ b/Sources/FioriSwiftUICore/Views/StepProgressIndicator/_StepProgressIndicator+View.swift @@ -121,12 +121,12 @@ extension _StepProgressIndicator: View { /// :nodoc: public extension _StepProgressIndicator where Steps == _DefaultSteps, CancelActionView == _Action { - /// Convenience initialization for default step progress indicator. + /// Convenience initializer for default step progress indicator. /// - Parameters: /// - selection: A binding string for selected step id. /// - stepItems: An array of `StepItem` for default steps generation. - /// - title: Title for current step displayed on steps top-left . - /// - action: Action for steps displayed on steps top-right that will show a vertical steps. + /// - title: Title for current step displayed on the top leading side of the step progress indicator. + /// - action: Action for steps displayed on the top trailing side of the step progress indicator. It will show vertical steps. init(selection: Binding, stepItems: [StepItem], @ViewBuilder title: @escaping () -> Title, @@ -142,11 +142,11 @@ public extension _StepProgressIndicator where Steps == _DefaultSteps, CancelActi selection: selection) } - /// Convenience initialization for default step progress indicator. + /// Convenience initializer for default step progress indicator. /// - Parameters: /// - selection: A binding string for selected step id. /// - stepItems: An array of `StepItem` for default steps generation. - /// - title: Title for current step displayed on steps top-left . + /// - title: Title for current step displayed on the top leading side of the step progress indicator. init(selection: Binding, stepItems: [StepItem], @ViewBuilder title: @escaping () -> Title) where ActionView == EmptyView @@ -157,11 +157,11 @@ public extension _StepProgressIndicator where Steps == _DefaultSteps, CancelActi action: { EmptyView() }) } - /// Convenience initialization for default step progress indicator. + /// Convenience initializer for default step progress indicator. /// - Parameters: /// - selection: A binding string for selected step id. /// - stepItems: An array of `StepItem` for default steps generation. - /// - action: Action for steps displayed on steps top-right that will show a vertical steps. + /// - action: Action for steps displayed on the top trailing side of the step progress indicator. It will show vertical steps. init(selection: Binding, stepItems: [StepItem], @ViewBuilder action: @escaping () -> ActionView) where Title == EmptyView @@ -172,7 +172,7 @@ public extension _StepProgressIndicator where Steps == _DefaultSteps, CancelActi action: action) } - /// Convenience initialization for default step progress indicator. + /// Convenience initializer for default step progress indicator. /// - Parameters: /// - selection: A binding string for selected step id. /// - stepItems: An array of `StepItem` for default steps generation. diff --git a/Sources/FioriSwiftUICore/_ComponentProtocols/CompositeComponentProtocols.swift b/Sources/FioriSwiftUICore/_ComponentProtocols/CompositeComponentProtocols.swift index 277296be3..f5e93cb69 100755 --- a/Sources/FioriSwiftUICore/_ComponentProtocols/CompositeComponentProtocols.swift +++ b/Sources/FioriSwiftUICore/_ComponentProtocols/CompositeComponentProtocols.swift @@ -758,7 +758,7 @@ protocol _SingleStepComponent: _TitleComponent, _NodeComponent, _LineComponent { var substeps: [StepItem] { get } } -/// `StepProgressIndicator` is view support a list of `StepItem` in a horizontal stack. Also customized steps is also supported. +/// `StepProgressIndicator` is a view supporting a list of `StepItem` in a horizontal stack. Also customized steps are also supported. /// ## Usage /// ```swift /// @State var selection: String = "id" @@ -768,12 +768,7 @@ protocol _SingleStepComponent: _TitleComponent, _NodeComponent, _LineComponent { /// Also indexed view builder is also supported. /// StepProgressIndicator(title: <#T##() -> any View#>, action: <#T##() -> any View#>, cancelAction: <#T##() -> any View#>, selection: <#T##Binding#>, steps: <#T##() -> any IndexedViewContainer#>) /// ``` -/// Only `stepStyle` will continue to be supported. And other legacy modifiers will be deprecated in the future. Please use latest modifiers. -/// `func titleStyle(_ style: some TitleStyle) -> some View` -/// `func actionStyle(_ style: some ActionStyle) -> some View` -/// `func cancelActionStyle(_ style: some CancelActionStyle) -> some View` -/// `func lineStyle(_ style: some LineStyle) -> some View` -/// `func nodeStyle(_ style: some NodeStyle) -> some View` +/// You can also update step style for different states, if you created `StepProgressIndicator` by `[StepItem]`. /// `func stepStyle(_ style: @escaping ((_ id: String) -> (some StepStyle)?)) -> some View` // sourcery: CompositeComponent protocol _StepProgressIndicatorComponent: _TitleComponent, _ActionComponent, _CancelActionComponent { diff --git a/Sources/FioriSwiftUICore/_FioriStyles/StepProgressIndicatorStyle.fiori.swift b/Sources/FioriSwiftUICore/_FioriStyles/StepProgressIndicatorStyle.fiori.swift index 7702246e4..c2b7dd40c 100644 --- a/Sources/FioriSwiftUICore/_FioriStyles/StepProgressIndicatorStyle.fiori.swift +++ b/Sources/FioriSwiftUICore/_FioriStyles/StepProgressIndicatorStyle.fiori.swift @@ -13,12 +13,12 @@ public extension StepProgressIndicator { self.init(title: title, action: action, cancelAction: cancelAction, selection: selection, steps: steps) } - /// Convenience initialization for default step progress indicator. + /// Convenience initializer for default step progress indicator. /// - Parameters: /// - selection: A binding string for selected step id. /// - stepItems: An array of `StepItem` for default steps generation. - /// - title: Title for current step displayed on steps top-left . - /// - action: Action for steps displayed on steps top-right that will show a vertical steps. + /// - title: Title for current step displayed on the top leading side of the step progress indicator. + /// - action: Action for steps displayed on the top trailing side of the step progress indicator. It will show vertical steps. init(selection: Binding, stepItems: [StepItem], @ViewBuilder title: @escaping () -> any View, @@ -30,11 +30,11 @@ public extension StepProgressIndicator { steps: { StepsStack(stepItems, selection: selection) }) } - /// Convenience initialization for default step progress indicator. + /// Convenience initializer for default step progress indicator. /// - Parameters: /// - selection: A binding string for selected step id. /// - stepItems: An array of `StepItem` for default steps generation. - /// - title: Title for current step displayed on steps top-left . + /// - title: Title for current step displayed on the top leading side of the step progress indicator. init(selection: Binding, stepItems: [StepItem], @ViewBuilder title: @escaping () -> any View) @@ -44,11 +44,11 @@ public extension StepProgressIndicator { steps: { StepsStack(stepItems, selection: selection) }) } - /// Convenience initialization for default step progress indicator. + /// Convenience initializer for default step progress indicator. /// - Parameters: /// - selection: A binding string for selected step id. /// - stepItems: An array of `StepItem` for default steps generation. - /// - action: Action for steps displayed on steps top-right that will show a vertical steps. + /// - action: Action for steps displayed on the top trailing side of the step progress indicator. It will show vertical steps. init(selection: Binding, stepItems: [StepItem], @ViewBuilder action: @escaping () -> any View) @@ -59,7 +59,7 @@ public extension StepProgressIndicator { steps: { StepsStack(stepItems, selection: selection) }) } - /// Convenience initialization for default step progress indicator. + /// Convenience initializer for default step progress indicator. /// - Parameters: /// - selection: A binding string for selected step id. /// - stepItems: An array of `StepItem` for default steps generation. diff --git a/Sources/FioriSwiftUICore/_generated/StyleableComponents/StepProgressIndicator/StepProgressIndicator.generated.swift b/Sources/FioriSwiftUICore/_generated/StyleableComponents/StepProgressIndicator/StepProgressIndicator.generated.swift index a9e8620cc..fd76695eb 100644 --- a/Sources/FioriSwiftUICore/_generated/StyleableComponents/StepProgressIndicator/StepProgressIndicator.generated.swift +++ b/Sources/FioriSwiftUICore/_generated/StyleableComponents/StepProgressIndicator/StepProgressIndicator.generated.swift @@ -3,7 +3,7 @@ import Foundation import SwiftUI -/// `StepProgressIndicator` is view support a list of `StepItem` in a horizontal stack. Also customized steps is also supported. +/// `StepProgressIndicator` is a view supporting a list of `StepItem` in a horizontal stack. Also customized steps are also supported. /// ## Usage /// ```swift /// @State var selection: String = "id" @@ -13,12 +13,7 @@ import SwiftUI /// Also indexed view builder is also supported. /// StepProgressIndicator(title: <#T##() -> any View#>, action: <#T##() -> any View#>, cancelAction: <#T##() -> any View#>, selection: <#T##Binding#>, steps: <#T##() -> any IndexedViewContainer#>) /// ``` -/// Only `stepStyle` will continue to be supported. And other legacy modifiers will be deprecated in the future. Please use latest modifiers. -/// `func titleStyle(_ style: some TitleStyle) -> some View` -/// `func actionStyle(_ style: some ActionStyle) -> some View` -/// `func cancelActionStyle(_ style: some CancelActionStyle) -> some View` -/// `func lineStyle(_ style: some LineStyle) -> some View` -/// `func nodeStyle(_ style: some NodeStyle) -> some View` +/// You can also update step style for different states, if you created `StepProgressIndicator` by `[StepItem]`. /// `func stepStyle(_ style: @escaping ((_ id: String) -> (some StepStyle)?)) -> some View` public struct StepProgressIndicator { let title: any View