8
8
import SwiftUI
9
9
import LiveViewNativeCore
10
10
11
+ /// Describes a View that is used as an element in a LiveView Native template.
12
+ ///
13
+ /// Any properties of the ``SwiftUI/View`` will be decoded from element attributes.
14
+ ///
15
+ /// - Precondition: A generic argument named `Root` conforming to ``RootRegistry`` must be included on the struct.
16
+ /// - Precondition: All properties should have a default value, or be marked optional.
17
+ ///
18
+ /// ```swift
19
+ /// @LiveElement
20
+ /// struct MyTag<Root: RootRegistry>: View {
21
+ /// private var label: String?
22
+ /// private var count: Int = 0
23
+ ///
24
+ /// var body: some View {
25
+ /// Text(label ?? "")
26
+ /// Text("Value: \(count)")
27
+ /// }
28
+ /// }
29
+ /// ```
30
+ ///
31
+ /// ```html
32
+ /// <MyTag label="Cookies" count="3" />
33
+ /// ```
34
+ ///
35
+ /// By default, the property name is used verbatim as the attribute name.
36
+ /// Use the ``LiveAttribute(_:)`` macro to customize the name of an attribute.
37
+ ///
38
+ /// Use the ``LiveElementIgnored()`` macro to disable decoding of a property.
39
+ /// This is useful when interfacing with SwiftUI property wrappers, such as ``SwiftUI/State`` and ``SwiftUI/Environment``.
11
40
@attached ( member, names: named ( liveElement) , named ( _TrackedContent) )
12
41
@attached ( memberAttribute)
13
42
public macro LiveElement( ) = #externalMacro( module: " LiveViewNativeMacros " , type: " LiveElementMacro " )
14
43
44
+ /// Marks a property as an attribute on a ``LiveElement()``.
45
+ ///
46
+ /// By default, the property name is used verbatim as the attribute name.
47
+ /// Provide the `name` argument to customize the namespace/name of the attribute.
48
+ ///
49
+ /// ```swift
50
+ /// @LiveAttribute(.init(namespace: "item", name: "count"))
51
+ /// private var count: Int = 0
52
+ /// ```
53
+ ///
54
+ /// ```html
55
+ /// <MyTag item:count="3" />
56
+ /// ```
15
57
@attached ( accessor, names: named ( get) )
16
58
public macro LiveAttribute( _ name: AttributeName ? = nil ) = #externalMacro( module: " LiveViewNativeMacros " , type: " LiveAttributeMacro " )
17
59
60
+ /// Disables attribute decoding for a property on a ``LiveElement()``.
61
+ ///
62
+ /// By default, all properties are treated as attributes by ``LiveElement()``.
63
+ /// This macro disables attribute decoding for a property.
64
+ ///
65
+ /// This can used with SwiftUI property wrappers, such as ``SwiftUI/State`` and ``SwiftUI/Environment``,
66
+ /// which should only be handled client-side.
67
+ ///
68
+ /// ```swift
69
+ /// @LiveElementIgnored
70
+ /// @State private var isExpanded = false
71
+ /// ```
18
72
@attached ( accessor, names: named ( willSet) )
19
73
public macro LiveElementIgnored( ) = #externalMacro( module: " LiveViewNativeMacros " , type: " LiveElementIgnoredMacro " )
20
74
@@ -24,7 +78,9 @@ public protocol _LiveElementTrackedContent {
24
78
}
25
79
26
80
@propertyWrapper public struct _LiveElementTracked < R: RootRegistry , T: _LiveElementTrackedContent > : DynamicProperty {
81
+ /// The ``ElementNode`` used to build a live element.
27
82
@ObservedElement public var element
83
+ /// The ``LiveContext`` for a live element.
28
84
@LiveContext < R > public var context
29
85
30
86
public var wrappedValue : T
@@ -52,12 +108,22 @@ public protocol _LiveElementTrackedContent {
52
108
}
53
109
54
110
public extension _LiveElementTracked {
111
+ /// Builds all child elements into a View hierarchy.
112
+ ///
113
+ /// By default, elements with a `template` are filtered out.
114
+ /// You can provide a custom `predicate` to filter different elements.
115
+ ///
116
+ /// - Parameter predicate: The filter used to select child nodes for render.
55
117
func children( _ predicate: ( Node ) -> Bool = { node in
56
118
!node. attributes. contains ( where: { $0. name. namespace == nil && $0. name. name == " template " } )
57
119
} ) -> some View {
58
120
context. coordinator. builder. fromNodes ( _element. children. filter ( predicate) , context: context. storage)
59
121
}
60
122
123
+ /// Builds all children with a given `template` attribute.
124
+ ///
125
+ /// - Parameter template: The ``Template`` used to filter child elements. A String literal can be provided for simple template values.
126
+ /// - Parameter includeDefault: Whether elements without a `template` attribute should be included in the filter. Defaults to `false`.
61
127
func children( in template: Template , default includeDefault: Bool = false ) -> some View {
62
128
children {
63
129
$0. attributes. contains ( where: {
@@ -66,6 +132,10 @@ public extension _LiveElementTracked {
66
132
}
67
133
}
68
134
135
+ /// Check whether one or more children have a matching `template` attribute.
136
+ ///
137
+ /// - Parameter template: The ``Template`` used to filter child elements. A String literal can be provided for simple template values.
138
+ /// - Parameter includeDefault: Whether elements without a `template` attribute should be included in the filter. Defaults to `false`.
69
139
func hasTemplate( _ template: Template , default includeDefault: Bool = false ) -> Bool {
70
140
_element. children. contains ( where: {
71
141
for attribute in $0. attributes {
@@ -83,11 +153,33 @@ public extension _LiveElementTracked {
83
153
hasTemplate ( . init( name, value: value) )
84
154
}
85
155
156
+ /// Array containing children of the ``ElementNode``.
86
157
var childNodes : [ LiveViewNativeCore . Node ] {
87
158
_element. children
88
159
}
89
160
}
90
161
162
+ /// A value passed to the `template` attribute, used for filtering children.
163
+ ///
164
+ /// A string literal can be used to create a simple template.
165
+ ///
166
+ /// ```swift
167
+ /// $liveElement.children(in: "label")
168
+ /// ```
169
+ ///
170
+ /// ```html
171
+ /// <Element template="label" />
172
+ /// ```
173
+ ///
174
+ /// When a `value` is passed, the `template` attribute should match the scheme `name.value`.
175
+ ///
176
+ /// ```swift
177
+ /// $liveElement.children(in: Template("phase", value: "success"))
178
+ /// ```
179
+ ///
180
+ /// ```html
181
+ /// <Element template="phase.success" />
182
+ /// ```
91
183
public struct Template : RawRepresentable , ExpressibleByStringLiteral {
92
184
let name : String
93
185
let value : String ?
0 commit comments