Giter Site home page Giter Site logo

tokamakui / tokamak Goto Github PK

View Code? Open in Web Editor NEW
2.5K 44.0 101.0 3.45 MB

SwiftUI-compatible framework for building browser apps with WebAssembly and native apps for other platforms

License: Apache License 2.0

Swift 92.99% Ruby 0.01% Shell 0.05% Makefile 0.04% C 0.04% HTML 6.89%
swift data-binding swiftui webassembly wasi swiftwasm dom ui-components hacktoberfest

tokamak's Introduction

Tokamak logo

SwiftUI-compatible framework for building browser apps with WebAssembly

CI status Discord

At the moment Tokamak implements a very basic subset of SwiftUI. Its DOM renderer supports a few view types and modifiers (you can check the current list in the progress document), and a new HTML view for constructing arbitrary HTML. The long-term goal of Tokamak is to implement as much of SwiftUI API as possible and to provide a few more helpful additions that simplify HTML and CSS interactions.

If there's some SwiftUI API that's missing but you'd like to use it, please review the existing issues and PRs to get more details about the current status, or create a new issue to let us prioritize the development based on the demand. We also try to make the development of views and modifiers easier (with the help from the HTML view, see the example below), so pull requests are very welcome! Don't forget to check the "Contributing" section first.

If you'd like to participate in the growing SwiftWasm community, you're also very welcome to join our Discord server, or the #webassembly channel in the SwiftPM Slack.

Example code

Tokamak API attempts to resemble SwiftUI API as much as possible. The main difference is that you use import TokamakShim instead of import SwiftUI in your files. The former makes your views compatible with Apple platforms, as well as platforms supported by Tokamak (currently only WebAssembly/WASI with more coming in the future):

import TokamakShim

struct Counter: View {
  @State var count: Int
  let limit: Int

  var body: some View {
    if count < limit {
      VStack {
        Button("Increment") { count += 1 }
        Text("\(count)")
      }
      .onAppear { print("Counter.VStack onAppear") }
      .onDisappear { print("Counter.VStack onDisappear") }
    } else {
      VStack { Text("Limit exceeded") }
    }
  }
}

@main
struct CounterApp: App {
  var body: some Scene {
    WindowGroup("Counter Demo") {
      Counter(count: 5, limit: 15)
    }
  }
}

Arbitrary HTML

With the HTML view you can also render any HTML you want, including inline SVG:

struct SVGCircle: View {
  var body: some View {
    HTML("svg", ["width": "100", "height": "100"]) {
      HTML("circle", [
        "cx": "50", "cy": "50", "r": "40",
        "stroke": "green", "stroke-width": "4", "fill": "yellow",
      ])
    }
  }
}

HTML doesn't support event listeners, and is declared in the TokamakStaticHTML module, which TokamakDOM re-exports. The benefit of HTML is that you can use it for static rendering in libraries like TokamakVapor and TokamakPublish.

Another option is the DynamicHTML view provided by the TokamakDOM module, which has a listeners property with a corresponding initializer parameter. You can pass closures that can handle onclick, onmouseover and other DOM events for you in the listeners dictionary. Check out MDN docs for the full list.

An example of mouse events handling with DynamicHTML would look like this:

struct MouseEventsView: View {
  @State var position: CGPoint = .zero
  @State var isMouseButtonDown: Bool = false

  var body: some View {
    DynamicHTML(
      "div",
      ["style": "width: 200px; height: 200px; background-color: red;"],
      listeners: [
        "mousemove": { event in
          guard
            let x = event.offsetX.jsValue.number,
            let y = event.offsetY.jsValue.number
          else { return }

          position = CGPoint(x: x, y: y)
        },
        "mousedown": { _ in isMouseButtonDown = true },
        "mouseup": { _ in isMouseButtonDown = false },
      ]
    ) {
      Text("position is \(position), is mouse button down? \(isMouseButtonDown)")
    }
  }
}

Arbitrary styles and scripts

While JavaScriptKit is a great option for occasional interactions with JavaScript, sometimes you need to inject arbitrary scripts or styles, which can be done through direct DOM access:

import JavaScriptKit

let document = JSObject.global.document
let script = document.createElement("script")
script.setAttribute("src", "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.27.0/moment.min.js")
document.head.appendChild(script)

_ = document.head.insertAdjacentHTML("beforeend", #"""
<link
  rel="stylesheet"
  href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css">
"""#)

This way both Semantic UI styles and moment.js localized date formatting (or any arbitrary style/script/font added that way) are available in your app.

Fiber renderers

A new reconciler modeled after React's Fiber reconciler is optionally available. It can provide faster updates and allow for larger View hierarchies. It also includes layout steps that can match SwiftUI layouts closer than CSS approximations.

You can specify which reconciler to use in your App's configuration:

struct CounterApp: App {
  static let _configuration: _AppConfiguration = .init(
    // Specify `useDynamicLayout` to enable the layout steps in place of CSS approximations.
    reconciler: .fiber(useDynamicLayout: true)
  )

  var body: some Scene {
    WindowGroup("Counter Demo") {
      Counter(count: 5, limit: 15)
    }
  }
}

Note: Not all Views and ViewModifiers are supported by Fiber renderers yet.

Requirements

For app developers

  • macOS 11 and Xcode 13.2 or later when using VS Code. macOS 12 and Xcode 13.3 or later are recommended if you'd like to use Xcode for auto-completion, or when developing multi-platform apps that target WebAssembly and macOS at the same time.
  • Swift 5.6 or later and Ubuntu 18.04/20.04 if you'd like to use Linux. Other Linux distributions are currently not supported.
  • carton 0.15.x (carton is our build tool, see the "Getting started" section for installation steps)

For users of apps depending on Tokamak

Any recent browser that supports WebAssembly and required JavaScript features should work, which currently includes:

  • Edge 84+
  • Firefox 79+
  • Chrome 84+
  • Desktop Safari 14.1+
  • Mobile Safari 14.8+

If you need to support older browser versions, you'll have to build with JAVASCRIPTKIT_WITHOUT_WEAKREFS flag, passing -Xswiftc -DJAVASCRIPTKIT_WITHOUT_WEAKREFS flags when compiling. This should lower browser requirements to these versions:

  • Edge 16+
  • Firefox 61+
  • Chrome 66+
  • (Mobile) Safari 12+

Not all of these versions are tested on regular basis though, compatibility reports are very welcome!

Getting started

Tokamak relies on carton as a primary build tool. As a part of these steps you'll install carton via Homebrew on macOS (unfortunately you'll have to build it manually on Linux). Assuming you already have Homebrew installed, you can create a new Tokamak app by following these steps:

  1. Install carton:
brew install swiftwasm/tap/carton

If you had carton installed before this, make sure you have version 0.15.0 or greater:

carton --version
  1. Create a directory for your project and make it current:
mkdir TokamakApp && cd TokamakApp
  1. Initialize the project from a template with carton:
carton init --template tokamak
  1. Build the project and start the development server, carton dev can be kept running during development:
carton dev
  1. Open http://127.0.0.1:8080/ in your browser to see the app running. You can edit the app source code in your favorite editor and save it, carton will immediately rebuild the app and reload all browser tabs that have the app open.

You can also clone this repository and run carton dev --product TokamakDemo in its root directory. This will build the demo app that shows almost all of the currently implemented APIs.

If you have any questions, pleaes check out the FAQ document, and/or join the #tokamak channel on the SwiftWasm Discord server.

Security

By default, the DOM renderer will escape HTML control characters in Text views. If you wish to override this functionality, you can use the _domTextSanitizer modifier:

Text("<font color='red'>Unsanitized Text</font>")
  ._domTextSanitizer(Sanitizers.HTML.insecure)

You can also use custom sanitizers; the argument to _domTextSanitizer is simply a String -> String closure. If _domTextSanitizer is applied to a non-Text view, it will apply to all Text in subviews, unless overridden.

If you use user-generated or otherwise unsafe strings elsewhere, make sure to properly sanitize them yourself.

Troubleshooting

unable to find utility "xctest" error when building

This error can only happen on macOS, so make sure you have Xcode installed as listed in the requirements. If you do have Xcode installed but still get the error, please refer to this StackOverflow answer.

Syntax highlighting and autocomplete don't work in Xcode

Open Package.swift of your project that depends on Tokamak with Xcode and build it for macOS. As Xcode currently doesn't support cross-compilation for non-Apple platforms, your project can't be indexed if it doesn't build for macOS, even if it isn't fully function on macOS when running. If you need to exclude some WebAssembly-specific code in your own app that doesn't compile on macOS, you can rely on #if os(WASI) compiler directives.

All relevant modules of Tokamak (including TokamakDOM) should compile on macOS. You may see issues with TokamakShim on macOS Catalina, where relevant SwiftUI APIs aren't supported, but replacing import TokamakShim with import TokamakDOM should resolve the issue until you're able to update to macOS Big Sur.

If you stumble upon code in Tokamak that doesn't build on macOS and prevents syntax highlighting or autocomplete from working in Xcode, please report it as a bug.

Syntax highlighting and autocomplete don't work in VSCode

Make sure you have the SourceKit LSP extension installed. If you don't trust this unofficial release, please follow the manual building and installation guide. Apple currently doesn't provide an official build of the extension on the VSCode Marketplace unfortunately.

Contributing

All contributions, no matter how small, are very welcome. You don't have to be a web developer or a SwiftUI expert to meaningfully contribute. In fact, by checking out how some of the simplest views are implemented in Tokamak you may learn more how SwiftUI may work under the hood.

Updating our documentation and taking on the starter bugs is also appreciated. Don't forget to join our Discord server to get in touch with the maintainers and other users. See CONTRIBUTING.md for more details.

Code of Conduct

This project adheres to the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to [email protected].

Sponsorship

If this library saved you any amount of time or money, please consider sponsoring the work of its maintainers on their sponsorship pages: @carson-katri, @kateinoigakukun, and @MaxDesiatov. While some of the sponsorship tiers give you priority support or even consulting time, any amount is appreciated and helps in maintaining the project.

Maintainers

In alphabetical order: Carson Katri, Ezra Berch, Jed Fox, Morten Bek Ditlevsen, Yuta Saito.

Acknowledgments

  • Thanks to the Swift community for building one of the best programming languages available!
  • Thanks to everyone who developed React with its reconciler/renderer architecture that inspired Tokamak in the first place.
  • Thanks to the designers of the SwiftUI API who showed us how to write UI apps in Swift declaratively (arguably even in a better way than React did).
  • Thanks to SwiftWebUI for reverse-engineering some of the bits of SwiftUI and kickstarting the front-end Swift ecosystem for the web.
  • Thanks to Render, ReSwift, Katana UI and Komponents for inspiration!

SwiftUI is a trademark owned by Apple Inc. Software maintained as a part of the Tokamak project is not affiliated with Apple Inc.

License

Tokamak is available under the Apache 2.0 license. 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 file for more info.

tokamak's People

Contributors

agg23 avatar ahti avatar andrewbarba avatar benedictst avatar carson-katri avatar ezraberch avatar filip-sakel avatar foscomputerservices avatar gregcotten avatar hodovani avatar j-f1 avatar joannis avatar kateinoigakukun avatar literalpie avatar mattpolzin avatar maxdesiatov avatar mbrandonw avatar mortenbekditlevsen avatar outcue avatar regexident avatar snowy1803 avatar twof avatar yonihemi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tokamak's Issues

Add ListView host component

I find it confusing that UITableView is named that way in UIKit, while it has no support for columns whatsoever, compare it to NSTableView in AppKit. I think it would be more fitting to name the corresponding host component in Gluon as ListView.

UICollectionView's component could keep that name, it's doing fine πŸ˜„

Image host component

Most of Image.Props should mirror properties of UIImage, but the actual target would be UIImageView. Properties that are read-only on UIImage would need to create a new instance when changed, one prominent example being renderingMode.

I imagine we could start with Image.Props looking like this:

public struct Props {
  public enum RenderingMode {
    // ...
  }
  public enum Source {
    case name(String)
    case data(Data)
  }
  // when changed initializes new image with `UIImage(named:)` or `UIImage(data:)`
  public let source: Source
  // when changed creates new image with `withRenderingMode`
  public let renderingMode: RenderingMode 
  // when changed initializes new image with given scale
  public let scale: Double 
  // mirrors `flipsForRightToLeftLayoutDirection`
  public let flipsForRTL: Bool
}

Add `hooks.reducer`

This would allow Gluon to manage complex state without requiring additional libraries like Redux

Implement all main layout constraints

Currently the only available auto layout constraint available is Edges.equal, we need to make all basic auto layout constraints available, working and tested with this new DSL, e.g. Width.equal, Height.equal, Leading.equal etc

Add Tokamak project linter

Create command-line util to lint projects that use Tokamak.

Todo:

  • Add Linter.md for linter documentation
  • Verify that SwiftSyntax 0.5 is able to parse the Example project
  • Add lint error Props is not Equatable
  • Add unit-tests to lint functions
  • Add lintFile -> [LintError]
  • Make lintFolder use lintFile
  • Make error output more user readable
  • Fix TokamakLint types access scope: remove public from TokenVisitor, Rule, Reporter, PropsIsEquatableRule
  • Fix TokenVisitor handling of Range, start and end are always equal to each other:
    node.range.startRow = row
    node.range.startColumn = column
    node.range.endRow = row
    node.range.endColumn = column
  • Fix processToken, kind variable is unused:
  private func processToken(_ token: TokenSyntax) {
    var kind = "\(token.tokenKind)"
    if let index = kind.firstIndex(of: "(") {
      kind = String(kind.prefix(upTo: index))
    }
    if kind.hasSuffix("Keyword") {
      kind = "keyword"
    }

    column += token.text.count
  }
  • Fix walkAndGrab, make it private, remove if node.children.count > 0 condition
  • Investigate if SwiftCLI package can be used in TokamakCLI module
  • Rename TokamakCLI to tokamak in Package.swift for Swift 5.0 and 4.2
.executable(name: "tokamak", targets: ["TokamakCLI"])
  • Lint "Only one render in component"
  • One render function rule should check all components, not only hooked components.
  • Lint "Rules of Hooks"
  • Lint "Components can only be declared as structs"
  • Integrate swift-log package
  • Remove direct usage of print, implement configurable output for stdout or files with a custom LogHandler implementation for swift-log

Long-term:

  • Lint "Arguments order"
  • Lint "Unused argument: hooks, children"
  • Lint "Declare non-static properties and functions in component"
  • Lint Rules of Hooks within extensions for all Hooks, not just state

Logo for the project

If you know of a suitable logo, or know anyone who could produce one, or can propose one yourself, please do. I've used stock images for the previous release with the React API, you can see them on the Twitter profile. If you're not familar with tokamaks, please use the Wikipedia page for inspirations. The whole idea was (and still is) to make a pun on React's atomic logo πŸ˜„

Getting value of type 'String' has no member 'components'

Try to build with Swiftwasm in wasm-DEVELOPMENT-SNAPSHOT-2020-04-07-a.
Getting following error

.build/checkouts/Runtime/Sources/Runtime/Metadata/TupleMetadata.swift:33:68: error: value of type 'String' has no member 'components' var labels = String(cString: pointer.pointee.labelsString).components(separatedBy: " ")

Implement UserInterfaceSizeClass with media queries support

Shame that there are only two size classes in SwiftUI: compact and regular. Also not sure what the default breakpoint for these should be. Even if we decide on one, I think that users should be able redefine it, or maybe even add their own size classes with new breakpoints.

0.2.0 release

Just kickstarting a possible discussion here of what you'd like to see in the first release with the SwiftUI API subset supporting WebAssembly. I am personally a fan of "release early and often" idea and wouldn't mind tagging a release with whatever API coverage we already have. It's more about letting people know that this thing exists and it can do basic stuff.

These seem to be release blockers, let me know if you think anything's missing:

  • Basic documentation
    The existing progress.md should be enough for this first release, I guess? We can integrate TokamakDocs somehow in later versions, unless @carson-katri has any objections.
  • Cleaning up the demo example
    I think even without NavigationView and friends, I'll just add some padding and headers to describe what's what
  • Updated CHANGELOG.md
  • Tagging and sharing on Twitter

What are your thoughts @carson-katri @j-f1?

Verify `.next` target for all layout constraints

Not sure if next sibling is correctly passed from the renderer/reconciler to auto layout extensions in TokamakUIKit, this needs to be verified and fixed if broken. Good to have some demo screens in the Example project for verification.

View has - by default - a Body of type Never.

This introduces bugs and almost defeats the purpose of compile-time errors. To prevent the program compiling successfully without producing an error for a type like Foo:

struct Foo: View {
    
}

There are two options - that I can think of:

  1. Add another _Never conditional conformances - to a dummy type like _Never that will require disambiguating when omitting the body:

    enum _Never: View {
        var body: Never { fatalError() }
    }
    
    extension View where Body == _Never {
        var body: _Never {
            fatalError("Can't access body of Never View.")
        }
    }

    That is a hack though and the error ("Type 'H' does not conform to protocol 'Block'") doesn't provide a fix possibly leaving a novice developer confused.

  2. Remove the extension that provides an automatic conformance when Body is of type Never and move that behaviour to the ViewDeferredToRenderer protocol - or to an underlying view protocol such as _StuctureView, _View, _FatalView:

    protocol _StuctureView: View where Body == Never {}
    
    extension _StuctureView {
         var body: Never {
            fatalError("Can't access body of Structure View.")
        }
    }

    That IMO is the best option, as it avoids automatic type-inference altogether and provides a useful error message - that offers a fix.

Some primitive Views cannot access @Environment

For instance, the Text element inside of EnvironmentDemo will never get any Environment injected. You can see this by putting the following print after // Inject @Environment values in StackReconciler.swift:

print(compositeView.view.type)

The Text element is never logged.

I'm not sure how to fix this. Do you have any ideas @MaxDesiatov ?

NavigationView/NavigationLink

Having this view ready would clean up the demo page and make it easier to add or fix just one view. It’s probably good to start with the 2-column iPad style and maybe expand later on to an iPhone style on narrower viewports.

Rename `EventHandlerProps` to `ControlProps`

Looks like there is an important property available on subclasses of UIControl that we need to make available on related control-like host components, namely isEnabled. It would make sense to add it on EventHandlerProps since that one is available for props of all control-like components. But then it would also make sense to rename it to ControlProps as the addition makes its purpose more general.

TextField host component

In TokamakUIKit this would be rendered to UITextField. This is a subclass of UIControl, so for the first version TextField should conform to the UIControlComponent protocol. Essential props that would be great to have in the initial version are:

  • textColor (that uses Tokamak type Color)
  • textAlignment (there's probably already an existing enum TextAlignment from Label that can be reused here?)
  • placeholder
  • clearsOnBeginEditing
  • clearsOnInsertion
  • borderStyle
  • clearButtonMode
  • autocapitalizationType
  • autocorrectionType
  • spellCheckingType
  • keyboardType
  • keyboardAppearance
  • returnKeyType
  • secureTextEntry

all adding new enums to the Tokamak module where required.

Server-side rendering and static websites support

It would be great if Tokamak supported rendering to a static HTML string without requiring DOM access, similar to what React already can do (and numerous other JS libraries probably too). There are many use cases for this, the most beneficial would be to pre-render your Tokamak app into a static HTML, serve that by default, and then hydrate that after the WebAssembly binary is loaded. This is beneficial for performance and usability as a user wouldn't need to wait for the WebAssembly module to be loaded and compiled before they can see anything useful on a web page.

Additionally, many static websites (such as blogs) wouldn't need components that utilize @State, those wouldn't need a WebAssembly binary at all, pre-rendered HTML would be enough. Of course, you could write your HTML by hand, but the abundance of React-based static websites generators (such as Gatsby) proves that it is nice to be able to reuse your existing code. Additionally, views described with Tokamak (even without any @State and other stateful property wrappers) clearly compose better than plain HTML.

I think this could look like a separate TokamakHTML module that doesn't depend on JavaScriptKit and could be compiled for any platform, not just WebAssembly. Then you'd supply any view to this HTML renderer and get an HTML string as an output. I hope that TokamakHTML could then be reused in the TokamakDOM module.

Add `hooks.context`

This would allow Tokamak to create contexts for passing values conforming to Equatable through deep component trees without needlessly updating all levels of the tree

Implement basic AppKit renderer

AppKit renderer would be a great proof of concept for cross-platform Tokamak and also would make reconciler testing much easier without requiring iOS simulator overhead.

Implement `hooks.effect`

The only standard hook currently available is state, which isn't enough to schedule and finalise side effects from components. Gluon should support hooks.effect corresponding to useEffect in React.

Stepper missing props

Properties that should be added to Stepper.Props and be rendered in the UIKit renderer: autorepeat, wraps, minimumValue, maximumValue, stepValue, all are documented in UIStepper docs.

ZStack?

What about ZStack? Have you plans to implements it?

Implement a test renderer

This renderer should use a new simple TestView class as a target, which stores references to subviews, also directly stores given props and is able to trigger events with a function like TestView.trigger(event: Event).

It would make sense to keep this renderer and TestView class in a separate module/subspec/target. This would make the core module smaller and allow importing the test renderer only in test targets. I imagine GluonTest is an ok name for the module.

Custom CSS styles

I've been thinking about CSS-specific styles that one might want to add to further customize generated styles, somewhat similar in principle to the HTML view that allows injecting arbitrary HTML. I'm still not sure if there should be a modifier that allows adding arbitrary HTML attributes to a rendered HTML node, or specialized modifiers like cssStyle() for specifying styles and cssClassName() for specifying a class name.

I also had in mind something like protocol CustomCSSAttributes which would allow any user to conform their views (or existing views provided by Tokamak) to this protocol, providing their custom global attributes. The use case for this are popular styling libraries (and obviously proprietary design systems that people may use) that have existing CSS code. For example, Semantic UI requires buttons to have ui button classes on them:

<button class="ui button">
  Button
</button>

Tokamak could allow achieving that for all buttons globally like this:

extension Button: CustomCSSAttributes {
  var customAttributes: [String: String] { ["class": "ui button"] }
}

The protocol approach and the modifiers approach would not be mutually exclusive, the reasoning is that modifiers would apply tweaks only locally, while protocol conformance would be visible globally. There's some bikeshedding needed here, but overall what are your thoughts?

Don't know if creating a separate issue for this proposal would be more suitable.

Set target refs in UIKitRenderer

Currently refs passed to nodes won't be initialized during rendering with UIKitRenderer. It's important to get targets stored in refs to enable usage of those targets in effects.

Add scroll properties to `ListView`/`CollectionView` props

As both of these components are rendered to UIScrollView and NSScrollView subclasses on iOS and macOS respectively, it would make sense to create a structure for props of all of these components to be shared and handled uniformly in the renderers code.

Add DatePicker component

This component should be rendered to UIDatePicker with UIKitRenderer. This is a subclass of UIControl, so it could reuse a lot of infrastructure from UIControlComponent protocol in GluonUIKit module.

ScrollView host component

Implementation of this component in TokamakUIKit would need special care to make it work with auto layout. The approach I would try is to copy width constraint of a scroll view and its parent to the root subview. This would automatically do the same what people need to do manually when working with programmatic UIScrollView and auto layout. We should also provide a flag in props to turn off these additional helper constraints if a user would like to avoid that. We also need to support both vertical and horizontal scrolling and inference of those additional constraints for both cases.

Add style support

Many views support some kind of .fooStyle() method that takes one of a variety of XFooStyle() objects. I took a quick look and it seems like this kind of thing has not been implemented for any of the views. Ideally having one implementation of this would provide a base from which to implement similar methods for other views.

Expose priorities on auto layout constraints

Currently there's no way to customise priority of a constraint. This probably should be exposed as an optional argument to equal function, but different approaches could be explored.

Important caveat:

Priorities may not change from nonrequired to required, or from required to nonrequired. An exception will be thrown if a priority of required in macOS or UILayoutPriorityRequired in iOS is changed to a lower priority, or if a lower priority is changed to a required priority after the constraints is added to a view. Changing from one optional priority to another optional priority is allowed even after the constraint is installed on a view.

Production readiness?

Hello,
I would like to ask you about confidence of using Tokamak in production applications for e-commerce.

Implement SubscriptionView compatible with OpenCombine

This is required for view subscriptions such as onReceive:

extension View {
  public func onReceive<P>(
    _ publisher: P, 
    perform action: @escaping (P.Output) -> ()
  ) -> some View where P : OpenCombine.Publisher, P.Failure == Never {
    SubscriptionView(content: self, publisher: publisher, action: action)
  }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.