Merge branch main
This commit is contained in:
commit
4b05fd8523
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
protocol AppearanceActionProtocol {
|
||||
protocol AppearanceActionType {
|
||||
var appear: (() -> ())? { get }
|
||||
var disappear: (() -> ())? { get }
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ struct _AppearanceActionModifier: ViewModifier {
|
|||
typealias Body = Never
|
||||
}
|
||||
|
||||
extension ModifiedContent: AppearanceActionProtocol
|
||||
extension ModifiedContent: AppearanceActionType
|
||||
where Content: View, Modifier == _AppearanceActionModifier {
|
||||
var appear: (() -> ())? { modifier.appear }
|
||||
var disappear: (() -> ())? { modifier.disappear }
|
||||
|
|
|
@ -43,7 +43,10 @@ extension _BackgroundModifier: Equatable where Background: Equatable {
|
|||
}
|
||||
|
||||
extension View {
|
||||
public func background<Background>(_ background: Background, alignment: Alignment = .center) -> some View where Background: View {
|
||||
public func background<Background>(
|
||||
_ background: Background,
|
||||
alignment: Alignment = .center
|
||||
) -> some View where Background: View {
|
||||
modifier(_BackgroundModifier(background: background, alignment: alignment))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,19 +22,34 @@ final class MountedCompositeView<R: Renderer>: MountedCompositeElement<R> {
|
|||
override func mount(with reconciler: StackReconciler<R>) {
|
||||
let childBody = reconciler.render(compositeView: self)
|
||||
|
||||
if let appearanceAction = view.view as? AppearanceActionProtocol {
|
||||
if let appearanceAction = view.view as? AppearanceActionType {
|
||||
appearanceAction.appear?()
|
||||
}
|
||||
|
||||
let child: MountedElement<R> = childBody.makeMountedView(parentTarget, environmentValues)
|
||||
mountedChildren = [child]
|
||||
child.mount(with: reconciler)
|
||||
|
||||
// `_TargetRef` is a composite view, so it's enough to check for it only here
|
||||
if var targetRef = view.view as? TargetRefType {
|
||||
// `_TargetRef` body is not always a host view that has a target, need to traverse
|
||||
// all descendants to find a `MountedHostView<R>` instance.
|
||||
var descendant: MountedElement<R>? = child
|
||||
while descendant != nil && !(descendant is MountedHostView<R>) {
|
||||
descendant = descendant?.mountedChildren.first
|
||||
}
|
||||
|
||||
guard let hostDescendant = descendant as? MountedHostView<R> else { return }
|
||||
|
||||
targetRef.target = hostDescendant.target
|
||||
view.view = targetRef
|
||||
}
|
||||
}
|
||||
|
||||
override func unmount(with reconciler: StackReconciler<R>) {
|
||||
mountedChildren.forEach { $0.unmount(with: reconciler) }
|
||||
|
||||
if let appearanceAction = view.view as? AppearanceActionProtocol {
|
||||
if let appearanceAction = view.view as? AppearanceActionType {
|
||||
appearanceAction.disappear?()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public final class MountedHostView<R: Renderer>: MountedElement<R> {
|
|||
private let parentTarget: R.TargetType
|
||||
|
||||
/// Target of this host view supplied by a renderer after mounting has completed.
|
||||
private var target: R.TargetType?
|
||||
private(set) var target: R.TargetType?
|
||||
|
||||
init(_ view: AnyView, _ parentTarget: R.TargetType, _ environmentValues: EnvironmentValues) {
|
||||
self.parentTarget = parentTarget
|
||||
|
|
|
@ -83,7 +83,11 @@ extension Shape {
|
|||
OffsetShape(shape: self, offset: .init(width: x, height: y))
|
||||
}
|
||||
|
||||
public func scale(x: CGFloat = 1, y: CGFloat = 1, anchor: UnitPoint = .center) -> ScaledShape<Self> {
|
||||
public func scale(
|
||||
x: CGFloat = 1,
|
||||
y: CGFloat = 1,
|
||||
anchor: UnitPoint = .center
|
||||
) -> ScaledShape<Self> {
|
||||
ScaledShape(shape: self,
|
||||
scale: CGSize(width: x, height: y), anchor: anchor)
|
||||
}
|
||||
|
@ -122,7 +126,10 @@ extension Shape {
|
|||
}
|
||||
|
||||
extension Shape {
|
||||
public func fill<S>(_ content: S, style: FillStyle = FillStyle()) -> some View where S: ShapeStyle {
|
||||
public func fill<S>(
|
||||
_ content: S,
|
||||
style: FillStyle = FillStyle()
|
||||
) -> some View where S: ShapeStyle {
|
||||
_ShapeView(shape: self, style: content, fillStyle: style)
|
||||
}
|
||||
|
||||
|
|
|
@ -16,24 +16,35 @@
|
|||
//
|
||||
|
||||
extension InsettableShape {
|
||||
public func strokeBorder<S>(_ content: S, style: StrokeStyle, antialiased: Bool = true) -> some View where S: ShapeStyle {
|
||||
public func strokeBorder<S>(
|
||||
_ content: S,
|
||||
style: StrokeStyle,
|
||||
antialiased: Bool = true
|
||||
) -> some View where S: ShapeStyle {
|
||||
inset(by: style.lineWidth / 2)
|
||||
.stroke(style: style)
|
||||
.fill(content, style: FillStyle(antialiased: antialiased))
|
||||
}
|
||||
|
||||
@inlinable public func strokeBorder(style: StrokeStyle, antialiased: Bool = true) -> some View {
|
||||
@inlinable
|
||||
public func strokeBorder(style: StrokeStyle, antialiased: Bool = true) -> some View {
|
||||
inset(by: style.lineWidth / 2)
|
||||
.stroke(style: style)
|
||||
.fill(style: FillStyle(antialiased: antialiased))
|
||||
}
|
||||
|
||||
@inlinable public func strokeBorder<S>(_ content: S, lineWidth: CGFloat = 1, antialiased: Bool = true) -> some View where S: ShapeStyle {
|
||||
@inlinable
|
||||
public func strokeBorder<S>(
|
||||
_ content: S,
|
||||
lineWidth: CGFloat = 1,
|
||||
antialiased: Bool = true
|
||||
) -> some View where S: ShapeStyle {
|
||||
strokeBorder(content, style: StrokeStyle(lineWidth: lineWidth),
|
||||
antialiased: antialiased)
|
||||
}
|
||||
|
||||
@inlinable public func strokeBorder(lineWidth: CGFloat = 1, antialiased: Bool = true) -> some View {
|
||||
@inlinable
|
||||
public func strokeBorder(lineWidth: CGFloat = 1, antialiased: Bool = true) -> some View {
|
||||
strokeBorder(style: StrokeStyle(lineWidth: lineWidth),
|
||||
antialiased: antialiased)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2020 Tokamak contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
protocol TargetRefType {
|
||||
var target: Target? { get set }
|
||||
}
|
||||
|
||||
public struct _TargetRef<V: View, T>: View, TargetRefType {
|
||||
let binding: Binding<T?>
|
||||
|
||||
let view: V
|
||||
|
||||
var target: Target? {
|
||||
get { binding.wrappedValue as? Target }
|
||||
|
||||
set { binding.wrappedValue = newValue as? T }
|
||||
}
|
||||
|
||||
public var body: V { view }
|
||||
}
|
||||
|
||||
extension View {
|
||||
/** Allows capturing target instance of aclosest descendant host view. The resulting instance
|
||||
is written to a given `binding`. */
|
||||
public func _targetRef<T: Target>(_ binding: Binding<T?>) -> _TargetRef<Self, T> {
|
||||
.init(binding: binding, view: self)
|
||||
}
|
||||
}
|
|
@ -48,10 +48,7 @@ public struct EdgeInsets: Equatable {
|
|||
public var bottom: CGFloat
|
||||
public var trailing: CGFloat
|
||||
|
||||
public init(top: CGFloat,
|
||||
leading: CGFloat,
|
||||
bottom: CGFloat,
|
||||
trailing: CGFloat) {
|
||||
public init(top: CGFloat, leading: CGFloat, bottom: CGFloat, trailing: CGFloat) {
|
||||
self.top = top
|
||||
self.leading = leading
|
||||
self.bottom = bottom
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2020 Tokamak contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import JavaScriptKit
|
||||
import TokamakCore
|
||||
|
||||
extension View {
|
||||
/** Allows capturing DOM references of host views. The resulting reference is written
|
||||
to a given `binding`.
|
||||
*/
|
||||
public func _domRef(_ binding: Binding<JSObjectRef?>) -> some View {
|
||||
// Convert `Binding<JSObjectRef?>` to `Binding<DOMNode?>` first.
|
||||
let targetBinding = Binding(
|
||||
get: { binding.wrappedValue.map(DOMNode.init) },
|
||||
set: { binding.wrappedValue = $0?.ref }
|
||||
)
|
||||
return _targetRef(targetBinding)
|
||||
}
|
||||
}
|
|
@ -63,7 +63,7 @@ let document = global.document.object!
|
|||
let body = document.body.object!
|
||||
let head = document.head.object!
|
||||
|
||||
let timeoutScheduler = { (closure: @escaping () -> ()) in
|
||||
private let timeoutScheduler = { (closure: @escaping () -> ()) in
|
||||
let fn = JSClosure { _ in
|
||||
closure()
|
||||
return .undefined
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright 2020 Tokamak contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#if os(WASI)
|
||||
import JavaScriptKit
|
||||
import TokamakShim
|
||||
|
||||
struct DOMRefDemo: View {
|
||||
@State var button: JSObjectRef?
|
||||
|
||||
var body: some View {
|
||||
Button("Click me") {
|
||||
button?.innerHTML = "This text was set directly through a DOM reference"
|
||||
}._domRef($button)
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -95,8 +95,15 @@ var redactDemo: NavItem {
|
|||
}
|
||||
}
|
||||
|
||||
var links: [NavItem] {
|
||||
[
|
||||
var domRefDemo: NavItem {
|
||||
#if os(WASI)
|
||||
return NavItem("DOM reference", destination: DOMRefDemo())
|
||||
#else
|
||||
return NavItem(unavailable: "DOM reference")
|
||||
#endif
|
||||
}
|
||||
|
||||
let links = [
|
||||
NavItem("Counter", destination:
|
||||
Counter(count: Count(value: 5), limit: 15)
|
||||
.padding()
|
||||
|
@ -125,8 +132,8 @@ var links: [NavItem] {
|
|||
appStorageDemo,
|
||||
gridDemo,
|
||||
redactDemo,
|
||||
domRefDemo,
|
||||
]
|
||||
}
|
||||
|
||||
struct TokamakDemoView: View {
|
||||
var body: some View {
|
||||
|
|
Loading…
Reference in New Issue