Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: directives #1821

Merged
merged 31 commits into from
Oct 19, 2023
Merged

feat: directives #1821

merged 31 commits into from
Oct 19, 2023

Conversation

maccesch
Copy link
Contributor

@maccesch maccesch commented Oct 1, 2023

Fixes #1668.

This isn't finished yet but I think it makes the idea clear.

You'd define your directives as functions.

// This doesn't take an attribute value
fn my_directive(el: HtmlElement<AnyElement>) {
    // do sth
}

// This requires an attribute value
fn another_directive(el: HtmlElement<AnyElement>, params: i32) {
    // do sth
}

Then in the view template:

<!-- no attribute value -->
<div use:my_directive></div>

<!-- with value -->
<SomeComponent use:another_directive=5 />

Should I finish this? Should I do sth different?

leptos_dom/src/lib.rs Outdated Show resolved Hide resolved
@gbj
Copy link
Collaborator

gbj commented Oct 2, 2023

This looks very good to me, and thanks for taking it on!

The only question I have is whether implementing it using NodeRef and a create_effect makes more sense, as on_mount is a bit heavy in terms of its implementation. on_mount is designed to check whether the element is literally mounted to the DOM, whereas node_ref would just run when it's created and then create_effect on the next tick (at which point in 99% of cases it will be attached to the DOM). i.e., there may be edge cases (like if someone creates an element and stores it in a Vec for later but doesn't mount it yet) where on_mount is more accurate but in general node refs should probably be preferred.

@maccesch
Copy link
Contributor Author

maccesch commented Oct 2, 2023

Ok I see. I guess in combination with the only-run-once of on_mount a NodeRef would be better indeed. I wonder if sth like a MutationObserver could be used to cover all the edge cases as well? Could maybe even be used to "lighten" the on_mount implementation?

@maccesch
Copy link
Contributor Author

maccesch commented Oct 5, 2023

So I did a bit more research how Solid does directives and they even say in the docs that it's just syntactic sugar for a node ref. They execute them before mounted.

So I think it makes sense to make our directives just syntactic sugar for

let the_ref = create_node_ref();

create_effect(move || {
    if let Some(the_ref) = the_ref.get() {
        directive_func(the_ref, possibly_some_param);
    }
});

That makes the implementation rather straight forward, is easy to understand for the user and we're 100% covered because we don't guarantee mounted and let users do whatever they want. Do you agree?

@gbj
Copy link
Collaborator

gbj commented Oct 5, 2023

Do you agree?

Agreed, this implementation looks good to me! create_effect now runs on the next tick so in 99% of cases it's already mounted in any case.

gbj and others added 23 commits October 7, 2023 10:25
```
The following actions uses node12 which is deprecated and will be forced to run
   on node16: actions-rs/toolchain@v1. For more info:
   https://github.blog/changelog/2023-06-13-github-actions-all-actions-will-run-on-node16-instead-of-node12-by-default/
```

In other places @3 was being used, so for consitency I have bumped everything up to @4

-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
@maccesch maccesch marked this pull request as ready for review October 19, 2023 12:34
@maccesch maccesch changed the title Directives feat: directives Oct 19, 2023
@maccesch
Copy link
Contributor Author

@gbj I think this is ready

@gbj
Copy link
Collaborator

gbj commented Oct 19, 2023

This looks really great! My only question was about whether it made sense to have Directive also generic over E: ElementDescriptor so that typed element could be used rather than only HtmlElement<AnyElement>. However, I can imagine it's also useful to have directives exist that can be used with any element, and the view macro wouldn't have an indicator as to whether it should convert them. For now, I think this is the right design, and people can downcast as needed in the directive, if they need a particular type.

Thanks for this really useful PR!

@gbj gbj merged commit c87328f into leptos-rs:main Oct 19, 2023
58 checks passed
@maccesch
Copy link
Contributor Author

Thanks!

@maccesch maccesch deleted the directive branch October 20, 2023 01:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Directives in leptos