GithubHelp home page GithubHelp logo

anp / moxie Goto Github PK

View Code? Open in Web Editor NEW
828.0 23.0 29.0 2.46 MB

lightweight platform-agnostic tools for declarative UI

Home Page: https://moxie.rs

License: Apache License 2.0

Rust 94.22% CSS 0.07% HTML 2.40% JavaScript 3.30%
rust ui declarative-ui incremental

moxie's Introduction

moxie logo

moxie

crates.io License codecov

More Information

For more information about the moxie project, see the website.

Contributing and Code of Conduct

See CONTRIBUTING.md for overall contributing info and CONDUCT.md for the project's Code of Conduct. The project is still early in its lifecycle but we welcome anyone interested in getting involved.

License

Licensed under either of

at your option.

moxie's People

Contributors

anp avatar dependabot-preview[bot] avatar dependabot[bot] avatar m-r-r avatar pfugate avatar simon-bourne avatar tiffany352 avatar zetanumbers 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

moxie's Issues

Element attributes should use a `memo!(make_handle)` API

This should be like the existing produce macro(s), but separating the memoization from the mounting/unmounting. I'm not sure that it's necessary for moxie to have a notion of parent nodes in the core runtime -- relating those is complex and perhaps topo env + memoization is the right level of abstraction?

dom: Conditional Rendering + dynamic data

I've come across a situation where dynamically generated strings are not rendered .

I'm not sure if I misunderstand how conditional rendering is supposed to work, or this is an issue with the xml macro.

The rendered content correctly switches from Loading to "Loaded", but the {count} is not displayed. The <span /> is inserted into the dom, but is empty.

#[topo::nested]
#[illicit::from_env(state: &Key<State>)]
pub fn list() {

    moxie::once!{
        || {
            log::info!("LOADING");
            // ... send fetch request
        }
    };

    if state.loading {
        mox!( <p> "Loading..." </p> );
    } else if let Some(err) = &state.error {
        mox!( <p> {format!("Error: {}", err)} </p> );
    } else {
        let items = &state.data.items;
        let count = items.len().to_string();
        mox!( 
            <p class="x"> 
                "Loaded"
                <span>{count}</span>
            </p> 
        );
    }
}

Dom references and mount/unmount handlers

Moxie is looking very promising.

I often (and concretely for something I'm working on) need something similar to Reacts useEffect and dom references to interact with dom nodes like <video>, <audio>, ...

I assume this is not yet implemented?

Would be highly appreciated.

If you give some pointers on where to start I could maybe find the time to work on this myself.

Dependabot can't resolve your Rust dependency files

Dependabot can't resolve your Rust dependency files.

As a result, Dependabot couldn't update your dependencies.

The error Dependabot encountered was:

This project is part of a Rust workspace but is not the workspace root.Please update your settings so Dependabot points at the workspace root instead of /dom/examples/todo.

If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.

You can mention @dependabot in the comments below to contact the Dependabot team.

Dependabot can't resolve your Rust dependency files

Dependabot can't resolve your Rust dependency files.

As a result, Dependabot couldn't update your dependencies.

The error Dependabot encountered was:

This project is part of a Rust workspace but is not the workspace root.Please update your settings so Dependabot points at the workspace root instead of /dom/examples/todo.

If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.

You can mention @dependabot in the comments below to contact the Dependabot team.

mox documentation needs examples

Right now the mox docs are in the moxie crate, which means that they can't use the dom definitions to demonstrate and test the mox macro.

Would be useful to define some test/docs-only builders in the core moxie crate that can be used in cases like this.

todos

  • check for unused deps in cargo.toml
  • abstract away non-web-compat things if possible

Second 'on' handler ignored

Tried to update two state variables on the same button press:

let total = state!(|| 10);
let current = state!(|| 10);
element!("button", |e| e
  .attr("type", "button")
  .on(|_: ClickEvent, _| Some(0), current)
  .on(|_: ClickEvent, _| Some(0), total)
  .inner(|| text!("Reset")));

Seems like only the first one is getting updated (I even swapped the order and tried again to double check haha).

ICE when Key not accessed

I stumbled on the following peculiar situation:

When not accessing a key injected via illicit::from-env, building results in a ICE.
The ICE goes away when any access to the key occurs.

moxie: master
nightly: 2019-11-16

#[topo::nested]
#[illicit::from_env(state: &Key<State>)]
pub fn whatever() {
    // UNcommenting this line removes the ICE
    // let _ = state.field;
    mox!( <p> "Loading..." </p> );
}
thread 'rustc' panicked at 'called `Result::unwrap()` on an `Err` value: DistinctSources(DistinctSources { begin: (Real("src/lib.rs"), BytePos(0)), end: (Real("src/views/some_view.rs"), BytePos(1831)) })', src/libcore/result.rs:1187:5
stack backtrace:

Boolean attributes are broken in jsx

Boolean attributes should create dom nodes that either include the key or exclude it rather than always including it and setting to the Boolean value. For example, try using disabled on buttons.

Document topo::Id's thread-local behavior

Further to discussions on Discord. With caller tracking being possibly implemented in rustc it is important to understand what this means for spawned threads and parallelism in general.

In the below by execution context I mean the environment associated with the callsite generated by either topos::root! , topos::call! or [topos::nested]. This includes the topos::current() Id.

Questions include:

  1. What, if any, should the default behaviour be for the execution context in a spawned thread?

For instance thread with Id:4 spawns a thread, should that new thread have any particularly Id.

  1. What guarantees, if any, should there be regarding subsequent calls to callsite tracking methods in a new thread.

For instance thread with Id:4 spawns a thread, if it has also by default has Id:4 can there be any guarantee that the id of the first new callsite in that thread would be invariant over consecutive thread spawns.

  1. Should there be explicit control over the above behaviour and execution context via some kind of spawn threading api.

  2. if a thread is spawned and then executes a loop which in turn executes several call-site tracked methods (with a revisit to each call-site intended). How does one ensure that this happens. Would a topo::root! be sufficient to guarantee this.

I.e. will the below be sufficent to ensure that a and b always refer to the same Id.

thread::spawn(move || {
    for i in 0..10 {
        topo::root!(
            topo::call!( let a = topo::current() );
            topo::call!( let b = topo::current() );
        )
    }
});

idea: mvcc state storage

Right now it looks like we'll need to block all stateful operations every frame to let the state store settle down and generate a consistent view of the world.

I suspect we'll want to support concurrent writers & readers who "care about" different frames. A single state store should be able to support running composition for frame N, layout for the previous frame, etc, just like a database.

Expose relevant web-sys types from Element types

As we move towards having "properly" typed support for all elements we can also offer an extension API to recover the typed wrappers from augdom. For example, instead of having access to only the raw node of a button, a moxie_dom::elements::forms::Button could also have an API to return a web_sys::Button.

Add `-Ztimings=info` to CI

It would be nice to have a ready-made breakdown of where build time is being spent in the dependency graph.

`ToOwned`-based memoization?

Right now memoization always needs to receive an owned argument, even if the argument hasn't changed. This results in a number of inefficiencies, like cloning strings on every revision just so they can be compared to the previous revision's and then discarded when they're in fact equal.

I think the API probably looks something a bit like this:

memo_ref<Ref, Arg, Output>(reference: Ref, init: impl FnOnce(Arg) -> Output)
where Ref: ToOwned<Owned=Arg> + PartialEq, ...

Mox builder API RFC

I want to propose a more explicitly defined interface that the mox macro
consumes. Some of this is based on my own local fork I'm using for
moxie-native.

Everything I'm talking about here is based on my own requirements for
moxie-native, and I'd like to know if any of these requirements are too
strict for other implementations, or if there are other ways of
improving this.

I'll start off with suggesting that as much as possible be moved into a
module named mox_impl, so that we don't pollute the namespace of
programs and require a blob import like use moxie_native::prelude::*;.

Inside of this module, there will be another namespace for host elements
(which we will distinguish from user components, as I'll detail below).
There will also be one for attribute names, and for event names.

API Sketch

None of the types used here are literal, but are just to name the return
values so you can match them up to where they get plumbed into.

mod mox_impl {
    mod elements {
        // Note that this is not a macro.
        fn element_name_here(
            with_builder: impl FnOnce(builder: Builder) -> Builder
        ) -> Node;
    }

    mod attributes {
        fn attr_name_here() -> Attribute;
    }

    mod events {
        fn on_event_name_here() -> Event;
    }
}

The builder API has these methods on it (again, the types are not actual types):

trait Builder {
    fn set_attr(self, key: Attribute, value: Attribute::Value) -> Self;
    fn on_event(self, event: Event, callback: impl FnMut(event)) -> Self;
    fn set_data(self, key: &'static str, value: DataValue) -> Self;
    fn add_child(self, child: Node) -> Self;
    fn enter_fragment(self, with_builder: impl FnOnce(builder: Self) -> Self) -> Self;
}

Changes to syntax

  1. User components need to be written in a way that lets them be
    differentiated from host components. This is already true of
    components that take arguments, since you have to use the <element _=(...)> syntax. Zero argument components need to be written
    differently from <element /> though. <element _=() /> would work
    if it didn't fail to parse.
  2. Instead of <element on={func} />, events actually have names, so
    <element on_foo={func} /> turns into
    .on(mox_impl::events::on_foo(), func).
  3. Add a concept of data attributes (not currently present) which are
    not statically declared. <element data_foo=4 /> -> .data("foo", 4)

Implementation

Implementation here is pretty straightforward, the biggest unknown is if
this new scheme will be difficult for other users of mox.

Simple implementations can define attribute functions as just a function
that returns a string, but this might be more manual than desired for
something like moxie-dom.

Some implementation hints from moxie-native that can come in handy here:

  • The builder trait can be implemented per element with a Builder<T>
    generic. The element functions can create an instance of this builder
    and pass it to the input function.
  • set_attr can be implemented using a trait like this:
    trait HasAttribute<Attr> where Attr: Attribute {
        fn set_attribute(&mut self, value: Attr::Value);
    }
  • on_event can be implemented the same way using a HasEvent trait.
  • The element function and the enter_fragment method are both good
    places to insert topo calls.

Examples

Simple with attributes

<foo some_attr=4 />
mox_impl::elements::foo(|builder| {
    builder
    .set_attr(mox_impl::attributes::some_attr(), 4)
})

User components

<bar>
    <user_component _=(1, "foo") />
</bar>
mox_impl::elements::bar(|builder| {
    builder
    .add_child(user_component!(1, "foo"))
})

Events and data attributes

<button on_click={func} data_foo=4 />
mox_impl::elements::button(|builder| {
    builder
    .on_event(mox_impl::events::on_click(), func)
    .data("foo", 4)
})

Children

<foo>
    <bar />
    "text"
    {children}
</foo>
mox_impl::elements::foo(|builder| {
    builder
    .add_child(mox_impl::elements::bar(|builder| builder))
    .add_child("text")
    .add_child(children)
})

Fragments

<foo>
    <>
        <fragment_child />
    <>
</foo>
mox_impl::elements::foo(|builder| {
    builder
    .enter_fragment(|builder| {
        builder
        .add_child(mox_impl::elements::fragment_child(|builder| builder))
    })
})

Bare fragments

Behavior here isn't super clear, but adding a create_fragment function
to mox_impl to handle this case seems flexible enough.

<>
    <fragment_child />
</>
mox_impl::create_fragment(|builder|
    builder
    .add_child(mox_impl::elements::fragment_child(|builder| builder))
)

Iterators

This one is tricky to support, and I currently can't handle it correctly
in moxie-native without trait specialization. I haven't thought of any
workarounds that don't require modifying the syntax to be like
..{iterator} or something like that. Any ideas here would be nice.

<foo>
    {[1, 2, 3].iter().map(|index| mox!(
        <number value={index} />
    ))}
</foo>
mox_impl::elements::foo(|builder| {
    builder
    .add_child(
        [1, 2, 3].iter().map(|index| 
            mox_impl::elements::number(|builder| {
                builder
                .set_attr(mox_impl::attributes::value(), index)
            })
        )
    )
})

Dependabot can't resolve your Rust dependency files

Dependabot can't resolve your Rust dependency files.

As a result, Dependabot couldn't update your dependencies.

The error Dependabot encountered was:

This project is part of a Rust workspace but is not the workspace root.Please update your settings so Dependabot points at the workspace root instead of /dom.

If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.

You can mention @dependabot in the comments below to contact the Dependabot team.

Typo in README

This project is written in Rust, but readme says "go". Please, fix it.

Audit mox against Rust API guidelines

  • Naming (crate aligns with Rust naming conventions)
    • Casing conforms to RFC 430 (C-CASE)
    • Ad-hoc conversions follow as_, to_, into_ conventions (C-CONV)
    • Getter names follow Rust convention (C-GETTER)
    • Methods on collections that produce iterators follow iter, iter_mut, into_iter (C-ITER)
    • Iterator type names match the methods that produce them (C-ITER-TY)
    • Feature names are free of placeholder words (C-FEATURE)
    • Names use a consistent word order (C-WORD-ORDER)
  • Interoperability (crate interacts nicely with other library functionality)
    • Types eagerly implement common traits (C-COMMON-TRAITS)
      • Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug,
        Display, Default
    • Conversions use the standard traits From, AsRef, AsMut (C-CONV-TRAITS)
    • Collections implement FromIterator and Extend (C-COLLECT)
    • Data structures implement Serde's Serialize, Deserialize (C-SERDE)
    • Types are Send and Sync where possible (C-SEND-SYNC)
    • Error types are meaningful and well-behaved (C-GOOD-ERR)
    • Binary number types provide Hex, Octal, Binary formatting (C-NUM-FMT)
    • Generic reader/writer functions take R: Read and W: Write by value (C-RW-VALUE)
  • Macros (crate presents well-behaved macros)
  • Documentation (crate is abundantly documented)
    • Crate level docs are thorough and include examples (C-CRATE-DOC)
    • All items have a rustdoc example (C-EXAMPLE)
    • Examples use ?, not try!, not unwrap (C-QUESTION-MARK)
    • Function docs include error, panic, and safety considerations (C-FAILURE)
    • Prose contains hyperlinks to relevant things (C-LINK)
    • Cargo.toml includes all common metadata (C-METADATA)
      • authors, description, license, homepage, documentation, repository,
        readme, keywords, categories
    • Crate sets html_root_url attribute "https://docs.rs/CRATE/X.Y.Z" (C-HTML-ROOT)
    • Release notes document all significant changes (C-RELNOTES)
    • Rustdoc does not show unhelpful implementation details (C-HIDDEN)
  • Predictability (crate enables legible code that acts how it looks)
    • Smart pointers do not add inherent methods (C-SMART-PTR)
    • Conversions live on the most specific type involved (C-CONV-SPECIFIC)
    • Functions with a clear receiver are methods (C-METHOD)
    • Functions do not take out-parameters (C-NO-OUT)
    • Operator overloads are unsurprising (C-OVERLOAD)
    • Only smart pointers implement Deref and DerefMut (C-DEREF)
    • Constructors are static, inherent methods (C-CTOR)
  • Flexibility (crate supports diverse real-world use cases)
    • Functions expose intermediate results to avoid duplicate work (C-INTERMEDIATE)
    • Caller decides where to copy and place data (C-CALLER-CONTROL)
    • Functions minimize assumptions about parameters by using generics (C-GENERIC)
    • Traits are object-safe if they may be useful as a trait object (C-OBJECT)
  • Type safety (crate leverages the type system effectively)
    • Newtypes provide static distinctions (C-NEWTYPE)
    • Arguments convey meaning through types, not bool or Option (C-CUSTOM-TYPE)
    • Types for a set of flags are bitflags, not enums (C-BITFLAG)
    • Builders enable construction of complex values (C-BUILDER)
  • Dependability (crate is unlikely to do the wrong thing)
  • Debuggability (crate is conducive to easy debugging)
  • Future proofing (crate is free to improve without breaking users' code)
  • Necessities (to whom they matter, they really matter)
    • Public dependencies of a stable crate are stable (C-STABLE)
    • Crate and its dependencies have a permissive license (C-PERMISSIVE)

Add crates.io link to readme

Since there's no badge yet linking to it.

[![Crates.io](https://img.shields.io/crates/v/moxie)](https://crates.io/crates/moxie)

Crates.io

Dependabot can't resolve your Rust dependency files

Dependabot can't resolve your Rust dependency files.

As a result, Dependabot couldn't update your dependencies.

The error Dependabot encountered was:

info: syncing channel updates for 'nightly-2019-08-12-x86_64-unknown-linux-gnu'
info: latest update on 2019-08-12, rust version 1.38.0-nightly (00ee1b47f 2019-08-11)
info: downloading component 'rustc'
info: downloading component 'rust-std'
info: downloading component 'cargo'
info: downloading component 'rust-docs'
info: installing component 'rustc'
info: installing component 'rust-std'
info: installing component 'cargo'
info: installing component 'rust-docs'
    Updating crates.io index
error: no matching package named `topo` found
location searched: /home/dependabot/dependabot-updater/dependabot_tmp_dir/topo
prerelease package needs to be specified explicitly
topo = { version = "0.8.2-pre" }
required by package `moxie v0.1.1-alpha.1-pre (/home/dependabot/dependabot-updater/dependabot_tmp_dir

If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.

You can mention @dependabot in the comments below to contact the Dependabot team.

Dependabot can't resolve your Rust dependency files

Dependabot can't resolve your Rust dependency files.

As a result, Dependabot couldn't update your dependencies.

The error Dependabot encountered was:

This project is part of a Rust workspace but is not the workspace root.Please update your settings so Dependabot points at the workspace root instead of /dom/examples/hacking.

If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.

You can mention @dependabot in the comments below to contact the Dependabot team.

Dependabot can't resolve your Rust dependency files

Dependabot can't resolve your Rust dependency files.

As a result, Dependabot couldn't update your dependencies.

The error Dependabot encountered was:

This project is part of a Rust workspace but is not the workspace root.Please update your settings so Dependabot points at the workspace root instead of /dom/examples/hacking.

If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.

You can mention @dependabot in the comments below to contact the Dependabot team.

Dependabot can't resolve your Rust dependency files

Dependabot can't resolve your Rust dependency files.

As a result, Dependabot couldn't update your dependencies.

The error Dependabot encountered was:

This project is part of a Rust workspace but is not the workspace root.Please update your settings so Dependabot points at the workspace root instead of /dom.

If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.

You can mention @dependabot in the comments below to contact the Dependabot team.

Create GitHub account for publishing crates

Currently the cargo published command ensures that all workspace crates which are appropriately versioned have been published to crates.io. This uses an auth token for my crates.io account (attached to this github account) but this is at odds with goals of the project:

  • providing a scalable workspace for others' experiments and moxie-related crates, allowing the core runtime's CI to be gated on closely associated projects and removing a little bit of activation energy required to try one's own thing out
  • actively sharing attribution and credit with community members

The most obvious short-term fix is to start publishing the current crates under an organizational account.

Coverage

What's working on my Windows machine right now:

  • using cargo-cov to generate gcda/gcno files in my target dir
  • using cargo-cov to produce an html report, but its contents are iffy
  • using grcov to produce lcov output (both from my own -Zprofile run as suggested on the grcov readme, and from cargo cov test output)

I have a codecov token, but am going to defer tying all of this together with a CI config until after publishing some releases.

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.