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

[wip] Implement special builder method for html-svg transition tags #70

Closed
wants to merge 6 commits into from

Conversation

busti
Copy link
Contributor

@busti busti commented Sep 9, 2021

This change implements a special builder method in the HtmlTagBuilder and SvgTagBuilder traits.
There are (as far as I am aware) two tags in browsers whose children use another xml namespace as the tags themselves. They are the <svg> tag and the <foreignObject> tag.

  • <svg> is a html tag, but it's children are svg tags.
  • foreignObject is a svg tag, but it's children are html tags.

    any xml namespace really, but for our purposes html should be enough, right?

In theory this would allow us to have a tag builder that whose html tags only allow for html attrs and so on. I.e.

private[outwatch] trait TagBuilder extends HtmlTagBuilder[HtmlTag, dom.html.Element] with SvgTagBuilder[SvgTag, dom.svg.Element] {
  @inline protected override def htmlTag[Ref <: dom.html.Element](tagName: String, void: Boolean): TypedVNode[Html, Html] = ???
  @inline protected override def svgTag[Ref <: dom.svg.Element](tagName: String, void: Boolean): TypedVNode[Svg, Svg] = ???
  @inline protected override def htmlToSvgTag[Ref <: dom.html.Element](tagName: String): TypedVNode[Html, Svg] = ??? 
  @inline protected override def svgToHtmlTag[Ref <: dom.svg.Element](tagName: String): TypedVNode[Svg, Html] = ???
}

That way div( stroke := "green" ) or svg( section ) would not compile.

This change also deprecates the svg tag definition inside the SvgTags trait.
Initially I thought that the svg tag would only be a relevant part of the svg namespace when being used as the top level tag of the document, but I have looked further into it while writing this and I have found some examples of people using multiple svg tags inside the same element.
I am not sure anymore if it should really be deprecated.

@busti busti requested a review from raquo as a code owner September 9, 2021 02:11
@busti
Copy link
Contributor Author

busti commented Sep 9, 2021

Looks like a PR on scalajs-dom is needed before this can work. Somehow I did not catch that earlier.

@busti
Copy link
Contributor Author

busti commented Sep 9, 2021

Turns out there is no HtmlSVGElement that inherits from HTMLElement after all.
The standard says it should, but I can imagine how that would be a pain to implement in browsers.

I have moved the definition back to SVGTagBuilder

@busti busti changed the title Implement special builder method for html-svg transition tags [wip] Implement special builder method for html-svg transition tags Sep 11, 2021
svgTag(tagName)
}

@inline protected def htmlToSvgTag[Ref <: DomSvgElement](tagName: String): T[Ref] = {
@inline protected def svgSvgTag[Ref <: DomSvgElement](tagName: String): T[Ref] = {
svgTag(tagName)
Copy link
Contributor Author

@busti busti Sep 13, 2021

Choose a reason for hiding this comment

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

Since we only use the methods for two tags anyways we can also name them for what they are.

Which makes the implementation look like this

private [lookout] trait SvgTagBuilder extends builders.SvgTagBuilder[CommonSvgTag, dom.svg.Element] {
  import VDomModifierTypes._

  override protected def svgTag[Ref <: svg.Element](tagName: String, void: Boolean): TypedVNode[Svg, Svg, Ref] = ???
  override protected def svgSvgTag[Ref <: svg.Element](tagName: String): TypedVNode[Both, Svg, Ref] = ???
  override protected def svgForeignObjectTag[Ref <: svg.Element](tagName: String): TypedVNode[Svg, Html, Ref] = ???
}

@@ -59,52 +59,55 @@ trait SvgTags[T[_ <: SvgElement], SvgElement,
] {
this: SvgTagBuilder[T, SvgElement] =>

type TPure <: T
type TSvg <: T[Svg]
type TForeignObject <: T[SvgElement]

Copy link
Contributor Author

@busti busti Sep 14, 2021

Choose a reason for hiding this comment

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

These could probably be named differently, I especially dislike TPure but I couldn't think of anything better.

@busti
Copy link
Contributor Author

busti commented Sep 14, 2021

I had to add some type aliases to support narrowing the types of tags.
All have default implementations and do not break existing APIs

@raquo
Copy link
Owner

raquo commented Nov 6, 2021

Sorry for the delay! I just looked at this, and for Laminar it would require changes there too. I'm not yet sure what the exact scope of those changes would be, but I have quite a few complex and high impact features in Airstream that I want to implement first. I'm working on the assumption that this change is simply to improve type safety, as I was able to construct SVGs with foreign objects with them just fine. In this regard it relates (somewhat) to #13.

@busti
Copy link
Contributor Author

busti commented Nov 7, 2021

No worries. I must admit that, after implementing this into outwatch as a proof of concept we have decided on not pursuing the concept any further since it would add too much complexity to for the safety it adds.
It does work, but it requires having two extra types on each VNode which is not very nice when using those types in user code.
The way I implemented this in outwatch could be expanded to resolve #13 but that would require major changes to scala-dom-types, which is something I wanted to avoid here.
At first the changes in this PR were supposed to be non-breaking for other libraries, but I had to make a few changes to types here and there to make the concept work on our side.

@raquo
Copy link
Owner

raquo commented Nov 7, 2021

Ah, thanks for confirming this. I had a suspicion that the required complexity would be prohibitive. Shall we close this then? (Keeping #13 alive as the entry point to this general issue).

@busti
Copy link
Contributor Author

busti commented Nov 7, 2021

Yeah, I am fine with closing this.
Since we referenced #13 it is still possible to easily find this in case anyone ever want's to work on that again.

@busti busti closed this Nov 7, 2021
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.

2 participants