import SwiftUI @available(macOS 10.15, *) extension Settings { /** Function builder for `Settings` components used in order to restrict types of child views to be of type `Section`. */ @resultBuilder public struct SectionBuilder { public static func buildBlock(_ sections: Section...) -> [Section] { sections } } /** A view which holds `Settings.Section` views and does all the alignment magic similar to `NSGridView` from AppKit. */ public struct Container: View { private let sectionBuilder: () -> [Section] private let contentWidth: Double private let minimumLabelWidth: Double @State private var maximumLabelWidth = 0.0 /** Creates an instance of container component, which handles layout of stacked `Settings.Section` views. Custom alignment requires content width to be specified beforehand. - Parameters: - contentWidth: A fixed width of the container's content (excluding paddings). - minimumLabelWidth: A minimum width for labels within this container. By default, it will fit to the largest label. - builder: A view builder that creates `Settings.Section`'s of this container. */ public init( contentWidth: Double, minimumLabelWidth: Double = 0, @SectionBuilder builder: @escaping () -> [Section] ) { self.sectionBuilder = builder self.contentWidth = contentWidth self.minimumLabelWidth = minimumLabelWidth } public var body: some View { let sections = sectionBuilder() return VStack(alignment: .settingsSectionLabel) { ForEach(0.. some View { sections[index] if index != sections.count - 1 && sections[index].bottomDivider { Divider() // Strangely doesn't work without width being specified. Probably because of custom alignment. .frame(width: contentWidth, height: 20) .alignmentGuide(.settingsSectionLabel) { $0[.leading] + max(minimumLabelWidth, maximumLabelWidth) } } } } } /** Extension with custom alignment guide for section title labels. */ @available(macOS 10.15, *) extension HorizontalAlignment { private enum SettingsSectionLabelAlignment: AlignmentID { // swiftlint:disable:next no_cgfloat static func defaultValue(in context: ViewDimensions) -> CGFloat { context[HorizontalAlignment.leading] } } static let settingsSectionLabel = HorizontalAlignment(SettingsSectionLabelAlignment.self) }