Skip to content

Commit 0331e9e

Browse files
committed
Add menu with prototype named child syntax
1 parent a454989 commit 0331e9e

File tree

3 files changed

+87
-0
lines changed

3 files changed

+87
-0
lines changed

Sources/LiveViewNative/BuiltinRegistry.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ struct BuiltinRegistry {
6060
EditButton()
6161
case "toggle":
6262
Toggle(element: element, context: context)
63+
case "menu":
64+
Menu(element: element, context: context)
6365
case "phx-form":
6466
PhxForm<R>(element: element, context: context)
6567
case "phx-submit-button":

Sources/LiveViewNative/LiveContext.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77

88
import SwiftUI
9+
import LiveViewNativeCore
910

1011
/// The context provides information at initialization-time to views in a LiveView.
1112
public struct LiveContext<R: CustomRegistry> {
@@ -45,4 +46,40 @@ public struct LiveContext<R: CustomRegistry> {
4546
public func buildChildren(of element: ElementNode) -> some View {
4647
return coordinator.builder.fromNodes(element.children(), context: self)
4748
}
49+
50+
public func buildChildren(
51+
of element: ElementNode,
52+
`where` condition: (NodeChildrenSequence.Element) -> Bool
53+
) -> some View {
54+
ForEach(element.children().filter(condition).map({ ($0.id, $0.children()) }), id: \.0) { subChildren in
55+
coordinator.builder.fromNodes(subChildren.1, context: self)
56+
}
57+
}
58+
59+
public func buildChildren(
60+
of element: ElementNode,
61+
withTagName tagName: String,
62+
namespace: String? = nil
63+
) -> some View {
64+
buildChildren(of: element, where: { child in
65+
if case let .element(element) = child.data,
66+
element.namespace == namespace,
67+
element.tag == tagName
68+
{
69+
return true
70+
} else {
71+
return false
72+
}
73+
})
74+
}
75+
76+
public func buildChildren(of element: ElementNode, defaultSlotFor tagName: String) -> some View {
77+
buildChildren(of: element, where: {
78+
if case let .element(element) = $0.data {
79+
return element.namespace != "menu"
80+
} else {
81+
return true
82+
}
83+
})
84+
}
4885
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//
2+
// Menu.swift
3+
//
4+
//
5+
// Created by Carson Katri on 1/19/23.
6+
//
7+
8+
import SwiftUI
9+
10+
struct Menu<R: CustomRegistry>: View {
11+
@ObservedElement private var element: ElementNode
12+
let context: LiveContext<R>
13+
14+
@FormState(default: false) var value: Bool
15+
16+
init(element: ElementNode, context: LiveContext<R>) {
17+
self.context = context
18+
}
19+
20+
public var body: some View {
21+
SwiftUI.Menu {
22+
context.buildChildren(of: element, withTagName: "content", namespace: "menu")
23+
} label: {
24+
context.buildChildren(of: element, defaultSlotFor: "menu")
25+
context.buildChildren(of: element, withTagName: "label", namespace: "menu")
26+
}
27+
}
28+
}
29+
30+
fileprivate enum MenuStyle: String {
31+
case automatic
32+
case borderlessButton = "borderless-button"
33+
case button
34+
}
35+
36+
fileprivate extension View {
37+
@ViewBuilder
38+
func applyMenuStyle(_ style: MenuStyle) -> some View {
39+
switch style {
40+
case .automatic:
41+
self.menuStyle(.automatic)
42+
case .borderlessButton:
43+
self.menuStyle(.borderlessButton)
44+
case .button:
45+
self.menuStyle(.button)
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)