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

Change html-macro's checked attribute to specify checkedness #206

Merged
merged 9 commits into from
Sep 29, 2024

Conversation

SFBdragon
Copy link
Contributor

This PR changes the meaning of checked as specified in the html! macro.

Originally, specifying checked would add or remove the checked HTML attribute. This changed the default checkedness of the input element, but may or may not actually change the rendered state of the element.

Now, specifying checked directly specifies the rendered state of the element. (The default checkedness is not modified, and can be set manually.)


Motivation

This change makes it easier to do the more commonly-desired task of specifying the rendered state of the checkbox (likely according to application state) rather than merely the default checkedness.

This change mitigates shooting ourselves in the foot by assuming checked sets a rendered checkbox's checkedness.


Further discussion is available in the issue #205 as well as in the new book entry and tests

https://github.com/SFBdragon/percy/tree/checked_sets_checkedness/book/src/html-macro/special-attributes

https://github.com/SFBdragon/percy/blob/checked_sets_checkedness/crates/percy-dom/tests/checked_attribute.rs

This resolves #205 for the time being.

Copy link
Owner

@chinedufn chinedufn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding a new book chapter.
Thanks for getting this working.

Minor feedback around tweaking the language in the book chapter.
Minor feedback around adding a diff.rs test.

Other than that looks good to me. Thanks for putting this together. Very solid.

book/src/html-macro/special-attributes/README.md Outdated Show resolved Hide resolved
book/src/html-macro/special-attributes/README.md Outdated Show resolved Hide resolved
book/src/html-macro/special-attributes/README.md Outdated Show resolved Hide resolved
book/src/html-macro/special-attributes/README.md Outdated Show resolved Hide resolved
crates/percy-dom/src/diff.rs Show resolved Hide resolved
crates/percy-dom/src/patch/apply_patches.rs Show resolved Hide resolved
crates/percy-dom/tests/checked_attribute.rs Outdated Show resolved Hide resolved
@SFBdragon
Copy link
Contributor Author

SFBdragon commented Sep 24, 2024 via email

@SFBdragon
Copy link
Contributor Author

Update, should submit the changes tomorrow. Currently getting a small append-my-checkbox-with-default-checkedness-to-dom example working, everything else has been changed/rectified.

@SFBdragon
Copy link
Contributor Author

@chinedufn This commit addresses the above review items.

There are some new elements worth reviewing here

  • The added example demonstrating appending a non-percy-managed element to the DOM.
  • The example also demonstrated maintaining a checkbox that has a fixed default checkedness.
  • I rewrote the book chapter.

I'm anticipating that you'd like some changes to the example but I'm not sure what those would be.

Copy link
Owner

@chinedufn chinedufn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for implementing this and big thanks for putting together an example.
Would be great for us to gradually accumulate more examples over time.

Minor feedback on the docs then we can merge.

examples/append-to-dom/README.md Outdated Show resolved Hide resolved
examples/append-to-dom/README.md Outdated Show resolved Hide resolved
crates/percy-dom/tests/checked_attribute.rs Outdated Show resolved Hide resolved
crates/percy-dom/tests/checked_attribute.rs Outdated Show resolved Hide resolved
book/src/html-macro/special-attributes/README.md Outdated Show resolved Hide resolved
examples/append-to-dom/README.md Outdated Show resolved Hide resolved
Comment on lines 7 to 8
#[wasm_bindgen_test]
pub fn main() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make sure to demonstrate the following:

  • Doing all of this using the html! macro
  • Doing all of this without using the html! macro
  • Using .special_attributes.on_create_element to demonstrate how to ensure that the unmanaged element gets inserted after percy creates the DOM node.
    • useful when you aren't appending to the root node since you won't have a div_elem: web_sys::Element on hand like you do in this example

Let's make the example append the input to a non-root node. This is the more common scenario. Or, feel free to demonstrate both.

I'm imagining that this fn main can call some different functions that each demonstrate some subset of the above list + the things that you are already demonstrating.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make the example append the input to a non-root node

Turns out this forces a mix of the above points such that there's only really one good way of doing it... sort of. Not using html! at all is possible and isn't demonstrated, but I don't think showing the example without html! is adding anything but verbosity, as html! currently isn't being used for anything that can't be easily manually constructed with VElements.

I can remove the use of html! if you feel strongly about it, or alternatively add another version of the function that doesn't use html!.

I recommend checking the new example first and seeing if you feel its necessary, once I commit it. (I'm not exactly sure why you want two versions.)

Copy link
Owner

@chinedufn chinedufn Sep 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only using html! sounds good. Hybrid approach sounds okay.

Agree that we shouldn't mix concepts unless it truly demonstrates something important.

We can always have a future example that shows how to create nodes with the macro.

@chinedufn
Copy link
Owner

Done reviewing. Nice work. Left a bunch of minor feedback.


---

### Why Does `percy` Override Default Checkedness?
Copy link
Contributor Author

@SFBdragon SFBdragon Sep 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, if you're using percy-dom strictly for server-side rendering, with no client-side logic, this would be a regression.

I'm having doubts that this was the right direction. Why would anyone ever use percy-dom for server-side rendering? The server shouldn't be manipulating a DOM server-side. That should be actively discouraged, right?

Therefore percy-dom has no reason to be overriding the default checkedness except to match virtual-node's behavior, but why should it? They're doing two different things. One is encoding a virtual node tree as HTML, the other is creating, diffing, and patching DOM nodes based on two different virtual node trees.

At this point, this example seems like a whole lot of faffing because we're doing the wrong thing.

Proposal:

  • Let's be explicit that percy-dom is not for server-side rendering.
  • Let's have percy-dom explicitly do what makes sense for the context of the browser: checked manipulates the HTMLInputElement.checked property - it doesn't mess around with default checkedness as there's no reason to do so. People writing typical/idiomatic percy apps should never need to worry about it. And if for some reason they do, they shouldn't have to work around this strange behavior.

What we gain from keeping this behavior:

  • percy-dom maintains closer HTML in the browser as it does to if you were to call virtual_node.to_string() (I don't see why this is useful, and can't think of a way this would cause issues. Can you?)

What is gained from tossing this behavior:

  • Nobody needs to worry about what percy-dom does to default checkedness: nothing.
  • percy-dom can avoid dealing with default checkedness entirely, as it's not useful for application-state-driven GUIs (which should always specify checkedness according to app state).
  • percy-dom doesn't have an expectation of being used for something it shouldn't be used for.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't remember where I wrote that quote, so I don't understand what you're referring to.


The server shouldn't be manipulating a DOM server-side.

A DOM does require on the browser in any way. We should not couple these unrelated concepts.

Whether percy can manipulate a DOM should never depend on whether it is running in a browser.

I'll name some reasons:

  • testing. It is an eventual goal that to be able to test the vast majority of your percy application outside of a browser. So, instead of using web-sys, we would use generic-dom-traits that used web-sys in a browser and
    something else outside of the browser.
    This would enable fast testing of things like "what happens when we click on this element but the onclick handler calls event.prevent_default()".
    For instance, we might use in-process-memory DOM implementation that was reliable enough that you trusted the results, and fast enough that one wouldn't hesitate to write as many test cases as they wanted

    • then a majority of an application's tests could be fast, and a minority that really needed to be in a browser could bear that overhead
  • simulation / benchmarking / etc

    • if you want to run your application in an environment that has a DOM, you should be able to. We should not arbitrarily limit your application to only be able to run inside of probably-slow, and probably-cumbersome-to-use web browser

it doesn't mess around with default checkedness as there's no reason to do so

It comes down to the framing. You're framing it as being about "default checkedness".
In that context, yes we currently have no reason to believe that we need percy-dom to do anything to the "default checkedness".

However, if this is framed around "setting the checked attribute" and "the user thinks that they're setting the checked attribute", then that changes things.

So, the question becomes, would a user ever want to set the "checked" attribute?

If <input foo="bar" /> sets the foo attribute, a user might expect <input checked=true /> to set the "checked" attribute.

If we pointed the user at an application and asked "what do you think happens when we render <input checked=true /> they should probably say "The checked attribute gets set".

In practice this would only impact the user if they were doing input.getAttribute('checked') and got back null instead of "true".

It's entirely possible that roughly 0 people will ever do this.

And, if they do, they can open an issue and we can do further design work.

So, I'm okay with, for now, having percy-dom only control the checked property, and not the checked attribute.

Proposal

Let's be explicit that percy-dom is not for server-side rendering.

Don't do this. Instead, we can say that if a user truly wants to set the "checked" attribute they can use .setAttribute on the node themselves https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute .

checked manipulates the HTMLInputElement.checked property - it doesn't mess around with default checkedness checked attribute (words swapped by me)

Sounds good.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good.

Neat.

I'll delete the example as it's no longer illustrative of doing something reasonable. If users want to set the default checkedness of an element, they should just get the DOM element and add/remove the attribute. It can be grabbed from the commit history if its useful later?

It's also worth mentioning that the situation with value is exactly the same as with checked, and having different behavior for them would be strange, at least long-term. If nothing explodes by releasing this change out into the wild, I think changing how percy-dom treats value should be changed to match checked. For now, the book entries reflect the difference.

Let's be explicit that percy-dom is not for server-side rendering.

I will leave it out. It was only in service of motivating the checked VDOM attribute behavior.

However, if this is framed around "setting the checked attribute" and "the user thinks that they're setting the checked attribute", then that changes things.

It's unfortunate.

  1. The core issue is the HTML standard. The checked HTML attribute should be called defaultChecked or something to distinguish it.
  2. Secondly, using a macro called html! with a HTML-like format to manipulate a DOM. It's misleading because an HTML document and a DOM have aliased but distinct concepts, such as the checked attribute and the checked property. ...It's a small enough issue that the choice might be worth the benefit of the intuitive markup.

Unless we remove the checked attribute from percy (and use something like is_checked and default_checked just to make it harder to assume what they mean) I think we're going to need to bite the bullet that devs will sometimes assume that percy-dom does the wrong thing - with respect to percy's intended utility.

But at least percy-dom will be doing the sensible thing (as far as we can tell, at least), so it's "just" a learning speed bump. At least percy isn't hard to use once the dev (hopefully) reads the book section to figure out what's going on.


Some leftover thoughts:

A DOM does require on the browser in any way. We should not couple these unrelated concepts.

Whether percy can manipulate a DOM should never depend on whether it is running in a browser.

I agree. We're talking past each other though. I don't think this is relevant to what I'm proposing.

Testing, simulation, benchmarking, etc. in environments without a browser seem neat. I just don't see what this has to do with server-side rendering though.

Server-side rendering is: generating a static HTML document and sending it off to the client. Manipulating a DOM is not useful in this process. Manipulating a virtual DOM is useful. But percy already has a distinction between virtual-node+html-macro and percy-dom such that manipulating a virtual DOM server-side to generate HTML has no dependency on the idea of actually manipulating a real or simulated or mocked DOM.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll delete the example

Unless it would be hard, let's just change it to be a embed-non-percy-node example where we show you how to create your own node that percy doesn't touch.

Can just delete all of the checkedness stuff and instead just make the example create a <div hello="world" /> or something using web-sys and insert that into
a percy contain .on_create_element.

If nothing explodes by releasing this change out into the wild, I think changing how percy-dom treats value should be changed to match checked

Sounds good.

Secondly, using a macro called html! with a HTML-like format to manipulate a DOM

html! macro is describing the DOM that you want.

Then percy-dom manipulates it.

The macro isn't manipulating the DOM, just declaring one.

So, it's designed to stay close to how a user would expect to be able to declare a DOM tree. Since HTML is likely the most common way to way to define a DOM tree, it's designed to feel like HTML.

This lets users avoid learning percy and instead just learn common specs/concepts. Transferable knowledge.

Unless we remove the checked attribute from percy (and use something like is_checked and default_checked just to make it harder to assume what they mean)
I think we're going to need to bite the bullet that devs will sometimes assume that percy-dom does the wrong thing - with respect to percy's intended utility.

rough idea

I could see a potential future (would require design work) where the html! macro gave a compile time error if you used checked.

It would tell you to use is_checked or how to set the attribute if you really wanted to do that.

That wouldn't help users that use VirtualNode directly, however.

But at least percy-dom will be doing the sensible thing (as far as we can tell, at least), so it's "just" a learning speed bump

Yeah, especially if the macro compile time error points you to the docs.

I agree. We're talking past each other though

Yeah I only realized that after I continued reading your comment

Server-side rendering is: generating a static HTML document and sending it off to the client. Manipulating a DOM is not useful in this process.

Here's what I had in mind:

  • user starts some sort of simulation application where they are running their percy application in an emulated browser

  • users triggers a bunch of clicks / input events / etc

  • user now wants to take the DOM tree from that emulated browser and turn it into a string

If you're really on default checkedness that DOM tree will be different from your virtual tree. Your virtual tree doesn't know whether the element is checked. Only the emulated DOM has info about whether the input is checked.

I haven't thought enough about this to know if it relates to our convo, so I'm more so communicating that I'm not certain that we should operate as if server-side rendering of a "real DOM" will never be useful.

@SFBdragon
Copy link
Contributor Author

SFBdragon commented Sep 28, 2024

If it's decided that #206 (comment) is a misguided take, then this is ready for a review of the new example and README, as they've been entirely rewritten.

Copy link
Owner

@chinedufn chinedufn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two tiny pieces of feedback.

Then you can address the open conversation about the checked attribute however you want #206 (comment)

Then just tell me to merge and I'll merge.

Thanks for nailing this all down.

examples/input-element-default-checkedness/README.md Outdated Show resolved Hide resolved
examples/input-element-default-checkedness/src/lib.rs Outdated Show resolved Hide resolved
@SFBdragon
Copy link
Contributor Author

SFBdragon commented Sep 29, 2024

All done. Removed setting default checkedness, deleted the example. I have not removed the behavior of setting the default value (regarding the value virtual dom attribute situation). I discussed all this in my reply here #206 (comment)

Double checked the PR, looks good to merge.

Thank you very much for your responsiveness and assistance!

@chinedufn
Copy link
Owner

chinedufn commented Sep 29, 2024

I replied suggesting that we keep the example but tweak it to only show embedding a non-percy node. #206 (comment)

If you're up for it an think it's a good idea, let's do that then merge.

If you're tired of this PR, or think it's a bad idea, we can merge.

You can tell me when to merge.

Thanks.

@SFBdragon
Copy link
Contributor Author

Changing the example, shouldn't take long 👍

@chinedufn
Copy link
Owner

chinedufn commented Sep 29, 2024

Cool. I'll merge after that without reading it so that we don't go back and forth on what I can only imagine would be trivial feedback at this point.

I'll release this as a patch release since the number of people relying on default checked-ness is very likely to be 0.

If you have a strong issue with that, let me know. Otherwise, I'll proceed with a patch release.


Reason for patch is that I consider this to be a bug and think it better for users' applications to pick up this fix whenever they update their Cargo.lock.

Some risk that there's someone out there that is truly relying on the current behavior. I'm essentially accessing that risk at roughly 0%.


Hmm... I started thinking about how to justify my "roughly 0%" claim and I didn't have a good justification.

So, let's just do a minor release.

If this was impacting an existing users' applications then we would've heard of it by now.

So, no good reason to risk breaking someone's application without them intentionally upgrading to the latest percy-dom.

I'll publish this as percy-dom = 0.10.0

@SFBdragon
Copy link
Contributor Author

Don't merge yet.

@SFBdragon
Copy link
Contributor Author

I'll publish this as percy-dom = 0.10.0

Sounds best to me. I've bumped the version in this PR.

@SFBdragon
Copy link
Contributor Author

Done making changes. Ready to merge 👍

@chinedufn chinedufn merged commit b3a3eec into chinedufn:master Sep 29, 2024
@chinedufn
Copy link
Owner

Published as percy-dom = 0.10.0 https://crates.io/crates/percy-dom/0.10.0

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.

Providing better way(s) to control the checkedness of a checkbox
2 participants