Add support for command bars
This commit is contained in:
parent
29715462f8
commit
c7a0fccde0
@ -27,17 +27,19 @@ let package = Package(
|
||||
url: "https://git.aparoksha.dev/aparoksha/levenshtein-transformations",
|
||||
branch: "main"
|
||||
),
|
||||
.package(url: "https://github.com/thebrowsercompany/swift-winui", branch: "main"),
|
||||
.package(url: "https://github.com/thebrowsercompany/swift-windowsappsdk", branch: "main"),
|
||||
.package(url: "https://github.com/thebrowsercompany/swift-windowsfoundation", branch: "main")
|
||||
.package(url: "https://github.com/thebrowsercompany/swift-windowsfoundation", branch: "main"),
|
||||
.package(url: "https://github.com/thebrowsercompany/swift-cwinrt", branch: "main"),
|
||||
.package(url: "https://github.com/AparokshaUI/winui", branch: "main")
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "Core",
|
||||
dependencies: [
|
||||
.product(name: "WinUI", package: "swift-winui"),
|
||||
.product(name: "WinUI", package: "winui"),
|
||||
.product(name: "WinAppSDK", package: "swift-windowsappsdk"),
|
||||
.product(name: "WindowsFoundation", package: "swift-windowsfoundation"),
|
||||
.product(name: "CWinRT", package: "swift-cwinrt"),
|
||||
.product(name: "LevenshteinTransformations", package: "levenshtein-transformations"),
|
||||
.product(name: "Meta", package: "meta")
|
||||
]
|
||||
|
71
Sources/Core/CommandBarContent/CommandBarCollection.swift
Normal file
71
Sources/Core/CommandBarContent/CommandBarCollection.swift
Normal file
@ -0,0 +1,71 @@
|
||||
//
|
||||
// CommandBarCollection.swift
|
||||
// WinUI
|
||||
//
|
||||
// Created by david-swift on 01.11.2024.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import WindowsFoundation
|
||||
import WinUI
|
||||
|
||||
/// A collection of command bar elements.
|
||||
public struct CommandBarCollection: CommandBarWidget, Wrapper {
|
||||
|
||||
/// The content of the collection.
|
||||
var content: Body
|
||||
|
||||
/// Initialize a command bar collection.
|
||||
/// - Parameter content: The content of the collection.
|
||||
public init(@ViewBuilder content: @escaping () -> Body) {
|
||||
self.content = content()
|
||||
}
|
||||
|
||||
/// The view storage.
|
||||
/// - Parameters:
|
||||
/// - modifiers: Modify the views before updating.
|
||||
/// - type: The type of the views.
|
||||
/// - Returns: The view storage.
|
||||
public func container<Data>(
|
||||
data: WidgetData,
|
||||
type: Data.Type
|
||||
) -> ViewStorage where Data: ViewRenderData {
|
||||
let storages = content.storages(data: data, type: type)
|
||||
var items: [ICommandBarElement?] = []
|
||||
getItems(items: &items, storages: storages)
|
||||
return .init(items, content: [.mainContent: storages])
|
||||
}
|
||||
|
||||
/// Update the stored content.
|
||||
/// - Parameters:
|
||||
/// - storage: The storage to update.
|
||||
/// - modifiers: Modify the views before updating.
|
||||
/// - updateProperties: Whether to update the properties.
|
||||
/// - type: The type of the views.
|
||||
public func update<Data>(
|
||||
_ storage: ViewStorage,
|
||||
data: WidgetData,
|
||||
updateProperties: Bool,
|
||||
type: Data.Type
|
||||
) where Data: ViewRenderData {
|
||||
guard let storages = storage.content[.mainContent] else {
|
||||
return
|
||||
}
|
||||
content.update(storages, data: data, updateProperties: updateProperties, type: type)
|
||||
}
|
||||
|
||||
/// Get the child items of the collection.
|
||||
/// - Parameters:
|
||||
/// - items: Pass the variable that will store the items.
|
||||
/// - storages: The storages.
|
||||
func getItems(items: inout [ICommandBarElement?], storages: [ViewStorage]) {
|
||||
for item in storages {
|
||||
if let item = item.pointer as? ICommandBarElement {
|
||||
items.append(item)
|
||||
} else {
|
||||
items += item.pointer as? [ICommandBarElement] ?? []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
21
Sources/Core/CommandBarContent/CommandBarContext.swift
Normal file
21
Sources/Core/CommandBarContent/CommandBarContext.swift
Normal file
@ -0,0 +1,21 @@
|
||||
//
|
||||
// CommandBarContext.swift
|
||||
// WinUI
|
||||
//
|
||||
// Created by david-swift on 01.11.24.
|
||||
//
|
||||
|
||||
/// The command bar context.
|
||||
public enum CommandBarContext: ViewRenderData {
|
||||
|
||||
/// The type of the widgets.
|
||||
public typealias WidgetType = CommandBarWidget
|
||||
/// The wrapper type.
|
||||
public typealias WrapperType = CommandBarCollection
|
||||
/// The either view type.
|
||||
public typealias EitherViewType = CommandBarEitherView
|
||||
|
||||
}
|
||||
|
||||
/// The type of the widgets.
|
||||
public protocol CommandBarWidget: Meta.Widget { }
|
23
Sources/Core/CommandBarContent/CommandBarEitherView.swift
Normal file
23
Sources/Core/CommandBarContent/CommandBarEitherView.swift
Normal file
@ -0,0 +1,23 @@
|
||||
//
|
||||
// CommandBarView.swift
|
||||
// WinUI
|
||||
//
|
||||
// Created by david-swift on 01.11.2024.
|
||||
//
|
||||
|
||||
/// Show one of two views depending on a condition.
|
||||
public struct CommandBarEitherView: Meta.EitherView, SimpleView {
|
||||
|
||||
/// The view.
|
||||
public var view: Body
|
||||
|
||||
/// Initialize an either view.
|
||||
/// - Parameters:
|
||||
/// - condition: The condition.
|
||||
/// - view1: The first view.
|
||||
/// - view2: The second view.
|
||||
public init(_ condition: Bool, view1: () -> Body, else view2: () -> Body) {
|
||||
self.view = condition ? view1() : view2()
|
||||
}
|
||||
|
||||
}
|
@ -8,15 +8,22 @@
|
||||
import WinUI
|
||||
|
||||
/// A button widget for menus.
|
||||
public struct Separator: MenuWidget {
|
||||
public struct Separator: MenuWidget, CommandBarWidget {
|
||||
|
||||
/// Initialize a separator menu item.
|
||||
public init() { }
|
||||
|
||||
/// Initialize the widget.
|
||||
/// - Returns: The widget.
|
||||
public func initializeWidget() -> Any {
|
||||
MenuFlyoutSeparator()
|
||||
/// The view storage.
|
||||
/// - Parameters:
|
||||
/// - data: The widget data.
|
||||
/// - type: The view render data type.
|
||||
/// - Returns: The view storage.
|
||||
public func container<Data>(data: WidgetData, type: Data.Type) -> ViewStorage where Data : ViewRenderData {
|
||||
if type == CommandBarContext.self {
|
||||
.init(AppBarSeparator())
|
||||
} else {
|
||||
.init(MenuFlyoutSeparator())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
57
Sources/Core/View/AppBar/AppBarButton.swift
Normal file
57
Sources/Core/View/AppBar/AppBarButton.swift
Normal file
@ -0,0 +1,57 @@
|
||||
//
|
||||
// AppBarButton.swift
|
||||
// WinUI
|
||||
//
|
||||
// Created by david-swift on 01.11.24.
|
||||
//
|
||||
|
||||
import CWinRT
|
||||
import WinUI
|
||||
|
||||
/// A button.
|
||||
public struct AppBarButton: WinUIWidget, CommandBarWidget {
|
||||
|
||||
/// The action to run when the button gets clicked.
|
||||
@Property(
|
||||
set: { button, closure, storage in
|
||||
if storage.fields["click"] == nil {
|
||||
button.click.addHandler { _, _ in
|
||||
(storage.fields["click"] as? () -> Void)?()
|
||||
}
|
||||
}
|
||||
storage.fields["click"] = closure
|
||||
},
|
||||
pointer: WinUI.AppBarButton.self
|
||||
)
|
||||
var action: (() -> Void)?
|
||||
/// The label.
|
||||
@Property(
|
||||
set: { $0.label = $1 },
|
||||
pointer: WinUI.AppBarButton.self
|
||||
)
|
||||
var label: String?
|
||||
/// The icon.
|
||||
@Property(
|
||||
set: { $0.icon = $1.winIcon },
|
||||
pointer: WinUI.AppBarButton.self
|
||||
)
|
||||
var icon: Icon?
|
||||
|
||||
/// Initialize an app bar button.
|
||||
/// - Parameters:
|
||||
/// - label: The button's label.
|
||||
/// - icon: An icon representing the action.
|
||||
/// - action: The button's action.
|
||||
public init(_ label: String, icon: Icon, action: @escaping () -> Void) {
|
||||
self.action = action
|
||||
self.label = label
|
||||
self.icon = icon
|
||||
}
|
||||
|
||||
/// Initialize the widget.
|
||||
/// - Returns: The widget.
|
||||
public func initializeWidget() -> Any {
|
||||
WinUI.AppBarButton()
|
||||
}
|
||||
|
||||
}
|
105
Sources/Core/View/AppBar/CommandBar.swift
Normal file
105
Sources/Core/View/AppBar/CommandBar.swift
Normal file
@ -0,0 +1,105 @@
|
||||
//
|
||||
// CommandBar.swift
|
||||
// WinUI
|
||||
//
|
||||
// Created by david-swift on 01.11.24.
|
||||
//
|
||||
|
||||
import CWinRT
|
||||
import WinUI
|
||||
|
||||
/// A command bar.
|
||||
public struct CommandBar: WinUIWidget {
|
||||
|
||||
/// The primary commands.
|
||||
var primaryCommands: Body
|
||||
/// The secondary commands.
|
||||
var secondaryCommands: Body
|
||||
/// Additional content.
|
||||
var content: Body = []
|
||||
/// Whether the labels are positioned right to the icon.
|
||||
var rightLabelPosition = false
|
||||
|
||||
/// Initialize a command bar.
|
||||
/// - Parameters:
|
||||
/// - primary: The primary commands.
|
||||
/// - secondary: The secondary commands.
|
||||
public init(@ViewBuilder primary: () -> Body, @ViewBuilder secondary: () -> Body = { [] }) {
|
||||
primaryCommands = primary()
|
||||
secondaryCommands = secondary()
|
||||
}
|
||||
|
||||
/// The view storage.
|
||||
/// - Parameters:
|
||||
/// - data: The widget data.
|
||||
/// - type: The view render data type.
|
||||
/// - Returns: The view storage.
|
||||
public func container<Data>(
|
||||
data: WidgetData,
|
||||
type: Data.Type
|
||||
) -> ViewStorage where Data: ViewRenderData {
|
||||
let bar = WinUI.CommandBar()
|
||||
let storage = ViewStorage(bar)
|
||||
let primary = CommandBarCollection { primaryCommands }.container(data: data.noModifiers, type: CommandBarContext.self)
|
||||
storage.content["primary"] = [primary]
|
||||
if let primary = primary.pointer as? [ICommandBarElement?] {
|
||||
primary.forEach { bar.primaryCommands.append($0) }
|
||||
}
|
||||
let secondary = CommandBarCollection { secondaryCommands }.container(data: data.noModifiers, type: CommandBarContext.self)
|
||||
storage.content["secondary"] = [secondary]
|
||||
if let secondary = secondary.pointer as? [ICommandBarElement?] {
|
||||
secondary.forEach { bar.secondaryCommands.append($0) }
|
||||
}
|
||||
let content = content.storage(data: data, type: type)
|
||||
storage.content[.mainContent] = [content]
|
||||
bar.content = content.pointer as? UIElement
|
||||
update(storage, data: data, updateProperties: true, type: type)
|
||||
return storage
|
||||
}
|
||||
|
||||
/// Update the stored content.
|
||||
/// - Parameters:
|
||||
/// - storage: The storage to update.
|
||||
/// - data: The widget data.
|
||||
/// - updateProperties: Whether to update the view's properties.
|
||||
/// - type: The view render data type.
|
||||
public func update<Data>(
|
||||
_ storage: ViewStorage,
|
||||
data: WidgetData,
|
||||
updateProperties: Bool,
|
||||
type: Data.Type
|
||||
) where Data: ViewRenderData {
|
||||
if let content = storage.content["primary"]?.first {
|
||||
CommandBarCollection { primaryCommands }.updateStorage(
|
||||
content,
|
||||
data: data.noModifiers,
|
||||
updateProperties: updateProperties,
|
||||
type: CommandBarContext.self
|
||||
)
|
||||
}
|
||||
if let content = storage.content["secondary"]?.first {
|
||||
CommandBarCollection { secondaryCommands }.updateStorage(
|
||||
content,
|
||||
data: data.noModifiers,
|
||||
updateProperties: updateProperties,
|
||||
type: CommandBarContext.self
|
||||
)
|
||||
}
|
||||
if let content = storage.content[.mainContent]?.first {
|
||||
self.content.updateStorage(content, data: data, updateProperties: updateProperties, type: type)
|
||||
}
|
||||
if updateProperties, (storage.previousState as? Self)?.rightLabelPosition != rightLabelPosition {
|
||||
(storage.pointer as? WinUI.CommandBar)?.defaultLabelPosition = rightLabelPosition ? .right : .bottom
|
||||
storage.previousState = self
|
||||
}
|
||||
}
|
||||
|
||||
public func content(@ViewBuilder content: () -> Body) -> Self {
|
||||
modify { $0.content = content() }
|
||||
}
|
||||
|
||||
public func rightLabelPosition(_ enabled: Bool = true) -> Self {
|
||||
modify { $0.rightLabelPosition = enabled }
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
//
|
||||
// VStack.swift
|
||||
// Button.swift
|
||||
// WinUI
|
||||
//
|
||||
// Created by david-swift on 11.10.24.
|
||||
|
64
Sources/Core/View/HStack.swift
Normal file
64
Sources/Core/View/HStack.swift
Normal file
@ -0,0 +1,64 @@
|
||||
//
|
||||
// VStack.swift
|
||||
// WinUI
|
||||
//
|
||||
// Created by david-swift on 11.10.24.
|
||||
//
|
||||
|
||||
import WinUI
|
||||
|
||||
/// A container arranging its children vertically.
|
||||
public struct HStack: WinUIWidget {
|
||||
|
||||
/// The content.
|
||||
var content: Body
|
||||
|
||||
/// Initialize the wrapper.
|
||||
/// - Parameter content: The view content.
|
||||
public init(@ViewBuilder content: () -> Body) {
|
||||
self.content = content()
|
||||
}
|
||||
|
||||
/// The view storage.
|
||||
/// - Parameters:
|
||||
/// - data: The widget data.
|
||||
/// - type: The view render data type.
|
||||
/// - Returns: The view storage.
|
||||
public func container<Data>(
|
||||
data: WidgetData,
|
||||
type: Data.Type
|
||||
) -> ViewStorage where Data: ViewRenderData {
|
||||
if content.count == 1, let view = content.first {
|
||||
return view.storage(data: data, type: type)
|
||||
}
|
||||
let stack = StackPanel()
|
||||
stack.orientation = .horizontal
|
||||
let storages = content.storages(data: data, type: type)
|
||||
for storage in storages {
|
||||
stack.children.append(storage.pointer as? UIElement)
|
||||
}
|
||||
return .init(stack, content: [.mainContent: storages])
|
||||
}
|
||||
|
||||
/// Update the stored content.
|
||||
/// - Parameters:
|
||||
/// - storage: The storage to update.
|
||||
/// - data: The widget data.
|
||||
/// - updateProperties: Whether to update the view's properties.
|
||||
/// - type: The view render data type.
|
||||
public func update<Data>(
|
||||
_ storage: ViewStorage,
|
||||
data: WidgetData,
|
||||
updateProperties: Bool,
|
||||
type: Data.Type
|
||||
) where Data: ViewRenderData {
|
||||
if content.count == 1, let view = content.first {
|
||||
view.updateStorage(storage, data: data, updateProperties: updateProperties, type: type)
|
||||
return
|
||||
}
|
||||
if let storages = storage.content[.mainContent] {
|
||||
content.update(storages, data: data, updateProperties: updateProperties, type: type)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -8,7 +8,7 @@
|
||||
import WinUI
|
||||
|
||||
/// A wrapper view for modifiers.
|
||||
public struct ModifierWrapper: WinUIWidget {
|
||||
public struct ModifierWrapper: WinUIWidget, CommandBarWidget {
|
||||
|
||||
/// The content view.
|
||||
var view: AnyView
|
||||
@ -26,6 +26,8 @@ public struct ModifierWrapper: WinUIWidget {
|
||||
var verticalAlignment: VerticalAlignment?
|
||||
/// The grid column.
|
||||
var gridColumn: Int?
|
||||
/// Whether the element is displayed.
|
||||
var visible: Bool?
|
||||
|
||||
// swiftlint:disable large_tuple
|
||||
/// Initialize the modifier wrapper.
|
||||
@ -37,6 +39,7 @@ public struct ModifierWrapper: WinUIWidget {
|
||||
/// - horizontalAlignment: The horizontal alignment.
|
||||
/// - verticalAlignment: The vertical alignment.
|
||||
/// - gridColumn: The grid column.
|
||||
/// - visible: Whether the view is visible.
|
||||
public init(
|
||||
view: AnyView,
|
||||
width: Double? = nil,
|
||||
@ -44,7 +47,8 @@ public struct ModifierWrapper: WinUIWidget {
|
||||
margin: (Double, Double, Double, Double)? = nil,
|
||||
horizontalAlignment: HorizontalAlignment? = nil,
|
||||
verticalAlignment: VerticalAlignment? = nil,
|
||||
gridColumn: Int? = nil
|
||||
gridColumn: Int? = nil,
|
||||
visible: Bool? = nil
|
||||
) {
|
||||
self.view = view
|
||||
self.width = width
|
||||
@ -53,6 +57,7 @@ public struct ModifierWrapper: WinUIWidget {
|
||||
self.horizontalAlignment = horizontalAlignment
|
||||
self.verticalAlignment = verticalAlignment
|
||||
self.gridColumn = gridColumn
|
||||
self.visible = visible
|
||||
}
|
||||
// swiftlint:enable large_tuple
|
||||
|
||||
@ -62,7 +67,9 @@ public struct ModifierWrapper: WinUIWidget {
|
||||
/// - type: The view render data type.
|
||||
/// - Returns: The view storage.
|
||||
public func container<Data>(data: WidgetData, type: Data.Type) -> ViewStorage where Data: ViewRenderData {
|
||||
let storage = view.storage(data: data, type: type)
|
||||
let content = view.storage(data: data, type: type)
|
||||
let storage = ViewStorage(content.pointer)
|
||||
storage.content[.mainContent] = [content]
|
||||
update(storage, data: data, updateProperties: true, type: type)
|
||||
return storage
|
||||
}
|
||||
@ -79,7 +86,9 @@ public struct ModifierWrapper: WinUIWidget {
|
||||
updateProperties: Bool,
|
||||
type: Data.Type
|
||||
) where Data: ViewRenderData {
|
||||
view.updateStorage(storage, data: data, updateProperties: updateProperties, type: type)
|
||||
if let storage = storage.content[.mainContent]?.first {
|
||||
view.updateStorage(storage, data: data, updateProperties: updateProperties, type: type)
|
||||
}
|
||||
guard updateProperties, let view = storage.pointer as? WinUI.FrameworkElement else {
|
||||
return
|
||||
}
|
||||
@ -102,6 +111,9 @@ public struct ModifierWrapper: WinUIWidget {
|
||||
if let gridColumn, previousState?.gridColumn != gridColumn {
|
||||
WinUI.Grid.setColumn(view, .init(gridColumn))
|
||||
}
|
||||
if let visible, previousState?.visible != visible {
|
||||
view.visibility = visible ? .visible : .collapsed
|
||||
}
|
||||
storage.previousState = self
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,32 @@ public struct NavigationView<Item>: WinUIWidget where Item: NavigationViewItem {
|
||||
var paneCustomContent: Body?
|
||||
/// The display mode of the navigation view.
|
||||
var mode: NavigationViewMode = .sidebar
|
||||
/// The primary commands in the header.
|
||||
var primaryCommands: Body = []
|
||||
/// The secondary commands in the header.
|
||||
var secondaryCommands: Body = []
|
||||
/// The label for the settings item.
|
||||
var settingsLabel: String?
|
||||
|
||||
/// The view's header.
|
||||
var header: AnyView? {
|
||||
if let settingsLabel {
|
||||
Grid {
|
||||
Text(selectedItem.description ?? settingsLabel)
|
||||
ModifierWrapper(
|
||||
view: CommandBar {
|
||||
primaryCommands
|
||||
} secondary: {
|
||||
secondaryCommands
|
||||
},
|
||||
margin: (0, 0, 50, 0),
|
||||
horizontalAlignment: .right
|
||||
)
|
||||
}
|
||||
} else {
|
||||
nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize the navigation view without the settings item.
|
||||
/// - Parameters:
|
||||
@ -62,6 +88,16 @@ public struct NavigationView<Item>: WinUIWidget where Item: NavigationViewItem {
|
||||
/// A custom item.
|
||||
case custom(item: Item)
|
||||
|
||||
/// The item's description.
|
||||
var description: String? {
|
||||
switch self {
|
||||
case .settings:
|
||||
nil
|
||||
case let .custom(item):
|
||||
item.description
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// The view storage.
|
||||
@ -86,6 +122,10 @@ public struct NavigationView<Item>: WinUIWidget where Item: NavigationViewItem {
|
||||
storage.content["pane-custom-content"] = [customStorage]
|
||||
view.paneCustomContent = customStorage.pointer as? UIElement
|
||||
}
|
||||
if let header = header?.storage(data: data, type: type) {
|
||||
view.header = header.pointer
|
||||
storage.content["header"] = [header]
|
||||
}
|
||||
if settings {
|
||||
view.isSettingsVisible = true
|
||||
} else {
|
||||
@ -113,6 +153,9 @@ public struct NavigationView<Item>: WinUIWidget where Item: NavigationViewItem {
|
||||
if let content = storage.content["pane-custom-content"]?.first {
|
||||
paneCustomContent?.updateStorage(content, data: data, updateProperties: updateProperties, type: type)
|
||||
}
|
||||
if let content = storage.content["header"]?.first {
|
||||
header?.updateStorage(content, data: data, updateProperties: updateProperties, type: type)
|
||||
}
|
||||
guard let navigationView = storage.pointer as? WinUI.NavigationView else {
|
||||
return
|
||||
}
|
||||
@ -163,6 +206,24 @@ public struct NavigationView<Item>: WinUIWidget where Item: NavigationViewItem {
|
||||
modify { $0.paneCustomContent = content() }
|
||||
}
|
||||
|
||||
/// The view's header.
|
||||
/// - Parameters:
|
||||
/// - settingsLabel: The label for the settings item.
|
||||
/// - primary: The primary command bar items.
|
||||
/// - secondary: The secondary command bar items.
|
||||
/// - Returns:
|
||||
public func header(
|
||||
settingsLabel: String,
|
||||
@ViewBuilder primary: () -> Body,
|
||||
@ViewBuilder secondary: () -> Body = { [] }
|
||||
) -> Self {
|
||||
modify { view in
|
||||
view.settingsLabel = settingsLabel
|
||||
view.primaryCommands = primary()
|
||||
view.secondaryCommands = secondary()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// The navigation selection type.
|
||||
|
@ -52,6 +52,12 @@ struct ContentView: View {
|
||||
.verticalAlignment(.center)
|
||||
}
|
||||
}
|
||||
.header(settingsLabel: "Settings") {
|
||||
AppBarButton("Delete", icon: .systemIcon(unicode: "\u{E74D}")) {
|
||||
print("Delete")
|
||||
}
|
||||
.visible(selectedItem != .shop)
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder var menu: Body {
|
||||
|
@ -53,4 +53,11 @@ extension AnyView {
|
||||
ModifierWrapper(view: self, gridColumn: column)
|
||||
}
|
||||
|
||||
/// Whether the view is visible.
|
||||
/// - Parameter visible: Whether the view is visible.
|
||||
/// - Returns: The view.
|
||||
public func visible(_ visible: Bool? = true) -> AnyView {
|
||||
ModifierWrapper(view: self, visible: visible)
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user