From be9cf996a04ba9ca2b3587e7db6eddf87606581c Mon Sep 17 00:00:00 2001 From: david-swift Date: Sat, 18 May 2024 11:35:23 +0200 Subject: [PATCH] Add type safe style classes --- README.md | 2 +- Sources/Adwaita/View/CheckButton+.swift | 18 ++ Sources/Adwaita/View/Forms/ActionRow+.swift | 7 + Sources/Adwaita/View/HStack.swift | 10 + Sources/Adwaita/View/List.swift | 13 +- .../View/Modifiers/InspectorWrapper.swift | 198 ++++++++++++++++++ Sources/Adwaita/View/StatusPage+.swift | 7 + Sources/Adwaita/View/VStack.swift | 5 + Tests/AlertDialogDemo.swift | 4 +- Tests/CarouselDemo.swift | 2 +- Tests/CounterDemo.swift | 4 +- Tests/DialogDemo.swift | 4 +- Tests/DiceDemo.swift | 4 +- Tests/FlowBoxDemo.swift | 2 +- Tests/FormDemo.swift | 6 +- Tests/IdleDemo.swift | 2 +- Tests/ListDemo.swift | 4 +- Tests/NavigationViewDemo.swift | 4 +- Tests/PictureDemo.swift | 4 +- Tests/PopoverDemo.swift | 4 +- Tests/ToastDemo.swift | 4 +- Tests/ToolbarDemo.swift | 8 +- Tests/TransitionDemo.swift | 10 +- Tests/ViewSwitcherDemo.swift | 4 +- Tests/WindowsDemo.swift | 2 +- 25 files changed, 293 insertions(+), 39 deletions(-) create mode 100644 Sources/Adwaita/View/CheckButton+.swift diff --git a/README.md b/README.md index c77f65a..e0b7fc8 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ struct Counter: View { count -= 1 } Text("\(count)") - .style("title-1") + .title1() .frame(minWidth: 100) Button(icon: .default(icon: .goNext)) { count += 1 diff --git a/Sources/Adwaita/View/CheckButton+.swift b/Sources/Adwaita/View/CheckButton+.swift new file mode 100644 index 0000000..14bddb8 --- /dev/null +++ b/Sources/Adwaita/View/CheckButton+.swift @@ -0,0 +1,18 @@ +// +// CheckButton+.swift +// Adwaita +// +// Created by david-swift on 18.05.24. +// + +/// A button widget. +extension CheckButton { + + /// Apply the selection mode style class. + /// - Parameter active: Whether it is applied. + /// - Returns: A view. + public func selectionMode(_ active: Bool = true) -> View { + style("selection-mode", active: active) + } + +} diff --git a/Sources/Adwaita/View/Forms/ActionRow+.swift b/Sources/Adwaita/View/Forms/ActionRow+.swift index 0a4257d..97446f5 100644 --- a/Sources/Adwaita/View/Forms/ActionRow+.swift +++ b/Sources/Adwaita/View/Forms/ActionRow+.swift @@ -14,4 +14,11 @@ extension ActionRow { self = self.title(title) } + /// Deemphasize the row title and emphasize the subtitle. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func property(_ active: Bool = true) -> View { + style("property", active: active) + } + } diff --git a/Sources/Adwaita/View/HStack.swift b/Sources/Adwaita/View/HStack.swift index 594b706..da125ab 100644 --- a/Sources/Adwaita/View/HStack.swift +++ b/Sources/Adwaita/View/HStack.swift @@ -10,10 +10,13 @@ public struct HStack: View { /// The content. var content: () -> Body + /// Whether the linked style should be used. + var linked = false /// The view's body. public var view: Body { VStack(horizontal: true, content: content) + .linked(linked) } /// Initialize a `HStack`. @@ -22,4 +25,11 @@ public struct HStack: View { self.content = content } + /// Link the children. + public func linked(_ active: Bool = true) -> Self { + var newSelf = self + newSelf.linked = active + return newSelf + } + } diff --git a/Sources/Adwaita/View/List.swift b/Sources/Adwaita/View/List.swift index b78b4f8..013eeae 100644 --- a/Sources/Adwaita/View/List.swift +++ b/Sources/Adwaita/View/List.swift @@ -59,8 +59,17 @@ extension List { } /// Add the "navigation-sidebar" style class. - public func sidebarStyle() -> View { - style("navigation-sidebar") + /// - Parameter active: Whether the style is applied. + /// - Returns: A view. + public func sidebarStyle(_ active: Bool = true) -> View { + style("navigation-sidebar", active: active) + } + + /// Apply the boxed list style class. + /// - Parameter active: Whether the style is applied. + /// - Returns: A view. + public func boxedList(_ active: Bool = true) -> View { + style("boxed-list", active: active) } } diff --git a/Sources/Adwaita/View/Modifiers/InspectorWrapper.swift b/Sources/Adwaita/View/Modifiers/InspectorWrapper.swift index de2de49..6825a2a 100644 --- a/Sources/Adwaita/View/Modifiers/InspectorWrapper.swift +++ b/Sources/Adwaita/View/Modifiers/InspectorWrapper.swift @@ -128,6 +128,204 @@ extension View { } } + /// Make a button or similar widget use accent colors. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func suggested(_ active: Bool = true) -> View { + style("suggested-action", active: active) + } + + /// Make a button or similar widget use destructive colors. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func destructive(_ active: Bool = true) -> View { + style("destructive-action", active: active) + } + + /// Make a button or similar widget use flat appearance. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func flat(_ active: Bool = true) -> View { + style("flat", active: active) + } + + /// Make a button or similar widget use the regular appearance instead of the flat one. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func raised(_ active: Bool = true) -> View { + style("raised", active: active) + } + + /// Make a button or similar widget round. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func circular(_ active: Bool = true) -> View { + style("circular", active: active) + } + + /// Make a button or similar widget appear as a pill. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func pill(_ active: Bool = true) -> View { + style("pill", active: active) + } + + /// Make the view partially transparent. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func dimLabel(_ active: Bool = true) -> View { + style("dim-label", active: active) + } + + /// Use a title typography style. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func title1(_ active: Bool = true) -> View { + style("title-1", active: active) + } + + /// Use a title typography style. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func title2(_ active: Bool = true) -> View { + style("title-2", active: active) + } + + /// Use a title typography style. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func title3(_ active: Bool = true) -> View { + style("title-3", active: active) + } + + /// Use a title typography style. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func title4(_ active: Bool = true) -> View { + style("title-4", active: active) + } + + /// Use the heading typography style. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func heading(_ active: Bool = true) -> View { + style("heading", active: active) + } + + /// Use the body typography style. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func body(_ active: Bool = true) -> View { + style("body", active: active) + } + + /// Use the caption heading typography style. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func captionHeading(_ active: Bool = true) -> View { + style("caption-heading", active: active) + } + + /// Use the caption typography style. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func caption(_ active: Bool = true) -> View { + style("caption", active: active) + } + + /// Use the monospace typography style. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func monospace(_ active: Bool = true) -> View { + style("monospace", active: active) + } + + /// Use the numeric typography style. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func numeric(_ active: Bool = true) -> View { + style("numeric", active: active) + } + + /// Apply the accent color. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func accent(_ active: Bool = true) -> View { + style("accent", active: active) + } + + /// Apply the success color. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func success(_ active: Bool = true) -> View { + style("success", active: active) + } + + /// Apply the warning color. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func warning(_ active: Bool = true) -> View { + style("warning", active: active) + } + + /// Apply the error color. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func error(_ active: Bool = true) -> View { + style("error", active: active) + } + + /// Apply the card style. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func card(_ active: Bool = true) -> View { + style("card", active: active) + } + + /// Apply an icon dropshadow. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + /// + /// Use for icons larger than 32x32 pixels. + public func iconDropshadow(_ active: Bool = true) -> View { + style("icon-dropshadow", active: active) + } + + /// Use for icons smaller than or equal to 32x32 pixels. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func lowresIcon(_ active: Bool = true) -> View { + style("lowres-icon", active: active) + } + + /// Use the OSD style class. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func osd(_ active: Bool = true) -> View { + style("osd", active: active) + } + + /// Give a view the default window background and foreground colors. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func backgroundStyle(_ active: Bool = true) -> View { + style("background", active: active) + } + + /// Give a view the default view background and foreground colors. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func viewStyle(_ active: Bool = true) -> View { + style("view", active: active) + } + + /// Give a view the default border. + /// - Parameter active: Whether the style is currently applied. + /// - Returns: A view. + public func frameStyle(_ active: Bool = true) -> View { + style("frame", active: active) + } + /// Run a function when the view gets an update. /// - Parameter onUpdate: The function. /// - Returns: A view. diff --git a/Sources/Adwaita/View/StatusPage+.swift b/Sources/Adwaita/View/StatusPage+.swift index 472e9ae..c5410ff 100644 --- a/Sources/Adwaita/View/StatusPage+.swift +++ b/Sources/Adwaita/View/StatusPage+.swift @@ -26,4 +26,11 @@ extension StatusPage { self = self.child(content) } + /// Make the status page more compact. + /// - Parameter active: Whether the style is applied. + /// - Returns: A view. + public func compact(_ active: Bool = true) -> View { + style("compact", active: active) + } + } diff --git a/Sources/Adwaita/View/VStack.swift b/Sources/Adwaita/View/VStack.swift index 3b64b17..467b721 100644 --- a/Sources/Adwaita/View/VStack.swift +++ b/Sources/Adwaita/View/VStack.swift @@ -28,4 +28,9 @@ extension VStack { } } + /// Link the children. + public func linked(_ active: Bool = true) -> View { + style("linked", active: active) + } + } diff --git a/Tests/AlertDialogDemo.swift b/Tests/AlertDialogDemo.swift index 98aff45..072420c 100644 --- a/Tests/AlertDialogDemo.swift +++ b/Tests/AlertDialogDemo.swift @@ -19,8 +19,8 @@ struct AlertDialogDemo: View { Button("Show Dialog") { dialog = true } - .style("pill") - .style("suggested-action") + .pill() + .suggested() .frame(maxWidth: 100) .padding() } diff --git a/Tests/CarouselDemo.swift b/Tests/CarouselDemo.swift index 9c4d3d9..2f69c3a 100644 --- a/Tests/CarouselDemo.swift +++ b/Tests/CarouselDemo.swift @@ -32,7 +32,7 @@ struct CarouselDemo: View { } .vexpand() .hexpand() - .style("card") + .card() .onClick { print(element.id) } .padding(20) .frame(minWidth: 300, minHeight: 200) diff --git a/Tests/CounterDemo.swift b/Tests/CounterDemo.swift index 3cae929..f2a19b5 100644 --- a/Tests/CounterDemo.swift +++ b/Tests/CounterDemo.swift @@ -19,7 +19,7 @@ struct CounterDemo: View { HStack { CountButton(count: $count, icon: .goPrevious) { $0 -= 1 } Text("\(count)") - .style("title-1") + .title1() .frame(minWidth: 100) CountButton(count: $count, icon: .goNext) { $0 += 1 } } @@ -39,7 +39,7 @@ struct CounterDemo: View { Button(icon: .default(icon: icon)) { action(&count) } - .style("circular") + .circular() } } diff --git a/Tests/DialogDemo.swift b/Tests/DialogDemo.swift index fd9d452..ac7dbe2 100644 --- a/Tests/DialogDemo.swift +++ b/Tests/DialogDemo.swift @@ -21,8 +21,8 @@ struct DialogDemo: View { Button("Show Dialog") { dialog = true } - .style("pill") - .style("suggested-action") + .pill() + .suggested() .frame(maxWidth: 100) .padding() } diff --git a/Tests/DiceDemo.swift b/Tests/DiceDemo.swift index 9e0a873..f2676be 100644 --- a/Tests/DiceDemo.swift +++ b/Tests/DiceDemo.swift @@ -26,8 +26,8 @@ struct DiceDemo: View { Button(label) { number = .random(in: 1...6) } - .style("pill") - .style("suggested-action") + .pill() + .suggested() .frame(maxWidth: 100) } .valign(.center) diff --git a/Tests/FlowBoxDemo.swift b/Tests/FlowBoxDemo.swift index 221a5ed..d802586 100644 --- a/Tests/FlowBoxDemo.swift +++ b/Tests/FlowBoxDemo.swift @@ -28,8 +28,8 @@ struct FlowBoxDemo: View { selectedItem = items[safe: index]?.id ?? items[safe: index ?? 0 - 1]?.id ?? items.first?.id ?? "" } } + .linked() .padding() - .style("linked") .halign(.center) if !items.isEmpty { FlowBox(items, selection: $selectedItem) { item in diff --git a/Tests/FormDemo.swift b/Tests/FormDemo.swift index f0147ac..6753278 100644 --- a/Tests/FormDemo.swift +++ b/Tests/FormDemo.swift @@ -18,8 +18,8 @@ struct FormDemo: View { Button("View Demo") { app.showWindow("form-demo") } - .style("suggested-action") - .style("pill") + .suggested() + .pill() .frame(maxWidth: 100) } } @@ -43,7 +43,7 @@ struct FormDemo: View { EntryRow("Entry Row", text: $text) .suffix { Button(icon: .default(icon: .editCopy)) { State.copy(text) } - .style("flat") + .flat() .verticalCenter() } EntryRow(password, text: $password) diff --git a/Tests/IdleDemo.swift b/Tests/IdleDemo.swift index 96eca41..457b93d 100644 --- a/Tests/IdleDemo.swift +++ b/Tests/IdleDemo.swift @@ -37,7 +37,7 @@ struct IdleDemo: View { } } .padding() - .style("pill") + .pill() .hexpand() .halign(.center) .insensitive(activeProcess) diff --git a/Tests/ListDemo.swift b/Tests/ListDemo.swift index 0d97670..b245463 100644 --- a/Tests/ListDemo.swift +++ b/Tests/ListDemo.swift @@ -28,8 +28,8 @@ struct ListDemo: View { selectedItem = items[safe: index]?.id ?? items[safe: index ?? 0 - 1]?.id ?? items.first?.id ?? "" } } + .linked() .padding() - .style("linked") .halign(.center) if !items.isEmpty { List(items, selection: $selectedItem) { item in @@ -39,8 +39,8 @@ struct ListDemo: View { } .padding() } + .boxedList() .valign(.center) - .style("boxed-list") .padding() } } diff --git a/Tests/NavigationViewDemo.swift b/Tests/NavigationViewDemo.swift index fc7aa58..db41ea4 100644 --- a/Tests/NavigationViewDemo.swift +++ b/Tests/NavigationViewDemo.swift @@ -18,8 +18,8 @@ struct NavigationViewDemo: View { Button("View Demo") { app.showWindow("navigation") } - .style("suggested-action") - .style("pill") + .suggested() + .pill() .frame(maxWidth: 100) .padding() } diff --git a/Tests/PictureDemo.swift b/Tests/PictureDemo.swift index fb9dd7c..2da381d 100644 --- a/Tests/PictureDemo.swift +++ b/Tests/PictureDemo.swift @@ -31,8 +31,8 @@ struct PictureDemo: View { app.addWindow("picture", parent: window) } .halign(.center) - .style("pill") - .style("suggested-action") + .pill() + .suggested() .padding() } diff --git a/Tests/PopoverDemo.swift b/Tests/PopoverDemo.swift index 7f6fa1d..427304c 100644 --- a/Tests/PopoverDemo.swift +++ b/Tests/PopoverDemo.swift @@ -18,8 +18,8 @@ struct PopoverDemo: View { Button("Present Popover") { visible = true } - .style("suggested-action") - .style("pill") + .suggested() + .pill() .frame(maxWidth: 100) .popover(visible: $visible) { CounterDemo() diff --git a/Tests/ToastDemo.swift b/Tests/ToastDemo.swift index 2967b65..b22128f 100644 --- a/Tests/ToastDemo.swift +++ b/Tests/ToastDemo.swift @@ -18,8 +18,8 @@ struct ToastDemo: View { Button("Add Toast") { toast.signal() } - .style("suggested-action") - .style("pill") + .suggested() + .pill() .frame(maxWidth: 100) } } diff --git a/Tests/ToolbarDemo.swift b/Tests/ToolbarDemo.swift index b1c5acd..8590648 100644 --- a/Tests/ToolbarDemo.swift +++ b/Tests/ToolbarDemo.swift @@ -18,8 +18,8 @@ struct ToolbarDemo: View { Button("View Demo") { app.showWindow("toolbar-demo") } - .style("suggested-action") - .style("pill") + .suggested() + .pill() .frame(maxWidth: 100) } } @@ -34,8 +34,8 @@ struct ToolbarDemo: View { Button("Toggle Toolbar") { visible.toggle() } - .style("suggested-action") - .style("pill") + .suggested() + .pill() .frame(maxWidth: 100) .padding(15) } diff --git a/Tests/TransitionDemo.swift b/Tests/TransitionDemo.swift index 07fa860..9ef07ae 100644 --- a/Tests/TransitionDemo.swift +++ b/Tests/TransitionDemo.swift @@ -18,21 +18,21 @@ struct TransitionDemo: View { if firstView { Text("First View") .transition(.slideDown) - .style("accent") + .accent() } else { Text("Second View") .transition(.slideUp) - .style("success") + .success() } } - .modifyContent(Text.self) { $0.style("title-2").padding() } - .style("card") + .modifyContent(Text.self) { $0.title2().padding() } + .card() .frame(maxWidth: 200) .padding() Button("Toggle View") { firstView.toggle() } - .style("pill") + .pill() .padding() .frame(maxWidth: 100) } diff --git a/Tests/ViewSwitcherDemo.swift b/Tests/ViewSwitcherDemo.swift index bb083c6..3b23bcb 100644 --- a/Tests/ViewSwitcherDemo.swift +++ b/Tests/ViewSwitcherDemo.swift @@ -18,8 +18,8 @@ struct ViewSwitcherDemo: View { Button("View Demo") { app.showWindow("switcher-demo") } - .style("suggested-action") - .style("pill") + .suggested() + .pill() .frame(maxWidth: 100) } } diff --git a/Tests/WindowsDemo.swift b/Tests/WindowsDemo.swift index 9b5c763..7407298 100644 --- a/Tests/WindowsDemo.swift +++ b/Tests/WindowsDemo.swift @@ -25,8 +25,8 @@ struct WindowsDemo: View { } .hexpand() } + .linked() .valign(.center) - .style("linked") .padding() } .frame(maxWidth: 100)