Skip to content

Commit 0bb4027

Browse files
committed
Merge branch 'main' of github.com:liveviewnative/liveview-client-swiftui into macos
2 parents 1ae3fb7 + a2a18c2 commit 0bb4027

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+481
-133
lines changed

.github/workflows/ci.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches: [master]
7+
8+
jobs:
9+
test:
10+
runs-on: macos-latest
11+
steps:
12+
- uses: actions/checkout@v2
13+
- name: Run tests on iOS Simulator
14+
shell: bash
15+
run: |
16+
sudo xcode-select --switch /Applications/Xcode_14.2.app
17+
xcodebuild test -scheme LiveViewNative -sdk iphonesimulator16.2 -destination "OS=16.2,name=iPhone 14 Pro"

Package.resolved

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/LiveViewNative/BuiltinRegistry.swift

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,46 +14,48 @@ struct BuiltinRegistry {
1414
@ViewBuilder
1515
static func lookup<R: CustomRegistry>(_ name: String, _ element: ElementNode, context: LiveContext<R>) -> some View {
1616
switch name {
17-
case "textfield":
17+
case "text-field":
1818
TextField<R>(element: element, context: context)
19-
case "securefield":
19+
case "secure-field":
2020
SecureField<R>(element: element, context: context)
2121
case "text":
2222
Text(context: context)
23-
case "hstack":
23+
case "h-stack", "hstack":
2424
HStack<R>(element: element, context: context)
25-
case "vstack":
25+
case "v-stack", "vstack":
2626
VStack<R>(element: element, context: context)
27-
case "zstack":
27+
case "z-stack", "zstack":
2828
ZStack<R>(element: element, context: context)
2929
case "button":
3030
Button<R>(element: element, context: context, action: nil)
3131
case "image":
3232
Image(element: element, context: context)
33-
case "asyncimage":
33+
case "async-image":
3434
AsyncImage(element: element, context: context)
35-
case "scrollview":
35+
case "scroll-view":
3636
ScrollView<R>(element: element, context: context)
3737
case "spacer":
3838
Spacer(element: element, context: context)
39-
case "navigationlink":
39+
case "navigation-link":
4040
NavigationLink(element: element, context: context)
4141
case "list":
4242
List<R>(element: element, context: context)
4343
case "rectangle":
4444
Shape(element: element, context: context, shape: Rectangle())
45-
case "roundedrectangle":
45+
case "rounded-rectangle":
4646
Shape(element: element, context: context, shape: RoundedRectangle(from: element))
4747
case "circle":
4848
Shape(element: element, context: context, shape: Circle())
4949
case "ellipse":
5050
Shape(element: element, context: context, shape: Ellipse())
5151
case "capsule":
5252
Shape(element: element, context: context, shape: Capsule(from: element))
53-
case "containerrelativeshape":
53+
case "container-relative-shape":
5454
Shape(element: element, context: context, shape: ContainerRelativeShape())
5555
case "lvn-link":
5656
Link(element: element, context: context)
57+
case "progress-view":
58+
ProgressView(element: element, context: context)
5759
case "divider":
5860
Divider()
5961
#if os(iOS)
@@ -62,6 +64,10 @@ struct BuiltinRegistry {
6264
#endif
6365
case "toggle":
6466
Toggle(element: element, context: context)
67+
case "menu":
68+
Menu(element: element, context: context)
69+
case "slider":
70+
Slider(element: element, context: context)
6571
case "phx-form":
6672
PhxForm<R>(element: element, context: context)
6773
case "phx-submit-button":

Sources/LiveViewNative/Coordinators/LiveViewCoordinator.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ public class LiveViewCoordinator<R: CustomRegistry>: ObservableObject {
133133
if let channel {
134134
guard !channel.isJoined, !channel.isJoining else { return }
135135
}
136+
internalState = .startingConnection
136137
do {
137138
try await connectLiveView()
138139
} catch {

Sources/LiveViewNative/CustomRegistry.swift

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,8 @@ public protocol CustomRegistry {
4848
/// }
4949
/// ```
5050
///
51-
/// If your registry does not support any custom tags, you can set this type alias to the ``EmptyRegistry/None`` type:
52-
/// ```swift
53-
/// struct MyRegistry: CustomRegistry {
54-
/// typealias TagName = EmptyRegistry.None
55-
/// }
56-
/// ```
57-
associatedtype TagName: RawRepresentable where TagName.RawValue == String
51+
/// This will default to the ``EmptyRegistry/None`` type if you don't support any custom tags.
52+
associatedtype TagName: RawRepresentable = EmptyRegistry.None where TagName.RawValue == String
5853
/// A type represnting the custom modifier types that this registry can handle.
5954
///
6055
/// This type must be `RawRepresentable` and its raw values must be strings.
@@ -69,21 +64,16 @@ public protocol CustomRegistry {
6964
/// }
7065
/// ```
7166
///
72-
/// If your registry does not support any custom modifiers, you can set this type alias to the ``EmptyRegistry/None`` type:
73-
/// ```swift
74-
/// struct MyRegistry: CustomRegistry {
75-
/// typealias ModifierType = EmptyRegistry.None
76-
/// }
77-
/// ```
78-
associatedtype ModifierType: RawRepresentable where ModifierType.RawValue == String
67+
/// This will default to the ``EmptyRegistry/None`` type if you don't support any custom modifiers.
68+
associatedtype ModifierType: RawRepresentable = EmptyRegistry.None where ModifierType.RawValue == String
7969
/// The type of view this registry returns from the `lookup` method.
8070
///
8171
/// Generally, implementors will use an opaque return type on their ``lookup(_:element:context:)-895au`` implementations and this will be inferred automatically.
82-
associatedtype CustomView: View
72+
associatedtype CustomView: View = Never
8373
/// The type of view this registry produces for loading views.
8474
///
8575
/// Generally, implementors will use an opaque return type on their ``loadingView(for:state:)-2uoy9`` implementations and this will be inferred automatically.
86-
associatedtype LoadingView: View
76+
associatedtype LoadingView: View = Never
8777

8878
/// This method is called by LiveView Native when it needs to construct a custom view.
8979
///

Sources/LiveViewNative/LiveContext.swift

Lines changed: 51 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,54 @@ 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+
private static func elementWithName(
51+
_ tagName: String,
52+
namespace: String?
53+
) -> (NodeChildrenSequence.Element) -> Bool {
54+
{ child in
55+
if case let .element(element) = child.data,
56+
element.namespace == namespace,
57+
element.tag == tagName
58+
{
59+
return true
60+
} else {
61+
return false
62+
}
63+
}
64+
}
65+
66+
public func hasChild(
67+
of element: ElementNode,
68+
withTagName tagName: String,
69+
namespace: String? = nil
70+
) -> Bool {
71+
element.children().contains(where: Self.elementWithName(tagName, namespace: namespace))
72+
}
73+
74+
public func buildChildren(
75+
of element: ElementNode,
76+
withTagName tagName: String,
77+
namespace: String? = nil,
78+
includeDefaultSlot: Bool = false
79+
) -> some View {
80+
let children = element.children()
81+
let namedSlotChildren = children.filter(Self.elementWithName(tagName, namespace: namespace))
82+
if namedSlotChildren.isEmpty && includeDefaultSlot {
83+
let defaultSlotChildren = children.filter({
84+
if case let .element(element) = $0.data {
85+
return element.namespace != tagName
86+
} else {
87+
return true
88+
}
89+
})
90+
return ForEach(defaultSlotChildren.map({ ($0.id, $0.children()) }), id: \.0) { subChildren in
91+
coordinator.builder.fromNodes(subChildren.1, context: self)
92+
}
93+
} else {
94+
return ForEach(namedSlotChildren.map({ ($0.id, $0.children()) }), id: \.0) { subChildren in
95+
coordinator.builder.fromNodes(subChildren.1, context: self)
96+
}
97+
}
98+
}
4899
}

Sources/LiveViewNative/LiveViewNative.docc/Elements/AsyncImage.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# AsyncImage
22

3-
`<asyncimage>`, displays images loaded from a remote URL.
3+
`<async-image>`, displays images loaded from a remote URL.
44

55
## Attributes
66

Sources/LiveViewNative/LiveViewNative.docc/Elements/HStack.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# HStack
22

3-
`<hstack>`, lays out children in a horizontal line.
3+
`<h-stack>`, lays out children in a horizontal line.
44

55
## Attributes
66

Sources/LiveViewNative/LiveViewNative.docc/Elements/NavigationLink.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# NavigationLink
22

3-
`<navigationlink>`, links to another live view page.
3+
`<navigation-link>`, links to another live view page.
44

55
## Attributes
66

Sources/LiveViewNative/LiveViewNative.docc/Elements/RoundedRectangle.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# RoundedRectangle
22

3-
`<roundedrectangle>`, a rectangle shape with rounded corners.
3+
`<rounded-rectangle>`, a rectangle shape with rounded corners.
44

55
## Attributes
66

0 commit comments

Comments
 (0)