// // MenuPicker.swift // TuskerComponents // // Created by Shadowfacts on 11/7/22. // Copyright © 2022 Shadowfacts. All rights reserved. // import SwiftUI public struct MenuPicker: UIViewRepresentable { public typealias UIViewType = UIButton @Binding var selection: Value let options: [Option] var buttonStyle: ButtonStyle private var selectedOption: Option { options.first(where: { $0.value == selection })! } public init(selection: Binding, options: [Option], buttonStyle: ButtonStyle = .labelAndIcon) { self._selection = selection self.options = options self.buttonStyle = buttonStyle } public func makeUIView(context: Context) -> UIButton { let button = UIButton(configuration: makeConfiguration()) button.showsMenuAsPrimaryAction = true button.setContentHuggingPriority(.required, for: .horizontal) return button } public func updateUIView(_ button: UIButton, context: Context) { button.configuration = makeConfiguration() button.menu = UIMenu(children: options.map { opt in let action = UIAction(title: opt.title, subtitle: opt.subtitle, image: opt.image, state: opt.value == selection ? .on : .off) { _ in selection = opt.value } action.accessibilityLabel = opt.accessibilityLabel return action }) button.accessibilityLabel = selectedOption.accessibilityLabel ?? selectedOption.title button.isPointerInteractionEnabled = buttonStyle == .iconOnly } private func makeConfiguration() -> UIButton.Configuration { var config = UIButton.Configuration.borderless() if #available(iOS 16.0, *) { config.indicator = .popup } if buttonStyle.hasIcon { config.image = selectedOption.image } if buttonStyle.hasLabel { config.title = selectedOption.title } #if targetEnvironment(macCatalyst) config.macIdiomStyle = .bordered #endif return config } public struct Option { public let value: Value public let title: String public let subtitle: String? public let image: UIImage? public let accessibilityLabel: String? public init(value: Value, title: String, subtitle: String? = nil, image: UIImage? = nil, accessibilityLabel: String? = nil) { self.value = value self.title = title self.subtitle = subtitle self.image = image self.accessibilityLabel = accessibilityLabel } } public enum ButtonStyle { case labelAndIcon, labelOnly, iconOnly var hasLabel: Bool { switch self { case .labelAndIcon, .labelOnly: return true default: return false } } var hasIcon: Bool { switch self { case .labelAndIcon, .iconOnly: return true default: return false } } } } struct MenuPicker_Previews: PreviewProvider { @State static var value = 0 static var previews: some View { MenuPicker(selection: $value, options: [ .init(value: 0, title: "Zero"), .init(value: 1, title: "One"), .init(value: 2, title: "Two"), ]) } }