Skip to content

Instantly share code, notes, and snippets.

@schwa
Created June 12, 2024 06:18
Show Gist options
  • Save schwa/10606e1482ca23869577249c5cb107ac to your computer and use it in GitHub Desktop.
Save schwa/10606e1482ca23869577249c5cb107ac to your computer and use it in GitHub Desktop.
XForms.swift
import SwiftUI
struct XForm <Content>: View where Content: View {
let content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
ScrollView(.vertical) {
VStack {
Group(subviewsOf: content) { subviews in
ForEach(subviews.dropLast()) { subview in
subview
Divider()
}
subviews.last
}
}
.padding([.leading, .trailing])
}
}
}
struct XSection <Label, Content>: View where Label: View, Content: View {
let content: Content
let label: Label
@State
var contentIsHidden: Bool = false
@State
var isHovering: Bool = false
init(@ViewBuilder content: () -> Content, @ViewBuilder label: () -> Label) {
self.content = content()
self.label = label()
}
var body: some View {
VStack(alignment: .leading) {
HStack {
label.bold()
Spacer()
if isHovering {
Toggle(isOn: $contentIsHidden) {
switch contentIsHidden {
case false:
Text("Hide")
case true:
Text("Show")
}
}
.controlSize(.mini)
.toggleStyle(.button)
}
}
.onHover {
isHovering = $0
}
if !contentIsHidden {
Group(subviewsOf: content) { subviews in
Group(subviewsOf: content) { subviews in
ForEach(subviews) { subview in
if let label = subview.containerValues.xFieldLabel {
HStack(alignment: .top) {
HStack {
Spacer()
label()
}
.frame(width: 120)
subview
}
}
else {
subview
}
}
}
}
}
}
}
}
extension XSection where Label == Text {
init(_ title: String, @ViewBuilder content: () -> Content) {
self.init(content: content) {
Text(title)
}
}
}
// MARK: -
struct XFieldLabelContainerValueKey: ContainerValueKey {
static let defaultValue: (@Sendable () -> AnyView)? = nil
}
extension ContainerValues {
var xFieldLabel: (@Sendable () -> AnyView)? {
get { self[XFieldLabelContainerValueKey.self] }
set { self[XFieldLabelContainerValueKey.self] = newValue }
}
}
extension View {
func fieldTitle(_ title: String) -> some View {
labelsHidden()
.containerValue(\.xFieldLabel) {
AnyView(Text(title))
}
}
func fieldLabel(_ label: @Sendable @escaping () -> some View) -> some View {
labelsHidden()
.containerValue(\.xFieldLabel) {
AnyView(label())
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment