mikesol / purescript-deku

A PureScript web UI framework
https://purescript-deku.surge.sh/
Apache License 2.0
123 stars 12 forks source link

`width` and `height` attributes can't be set for `SVGRectElement` #111

Open Ebmtranceboy opened 6 months ago

Ebmtranceboy commented 6 months ago

This code doesn't compile as soon as either one of the two commented lines is uncommented:

module Main where

import Prelude

import Deku.DOM.SVG as DS
import Deku.DOM.SVG.Attributes as SA
import Deku.Toplevel (runInBody)
import Effect (Effect)

main :: Effect Unit
main = runInBody
  ( 
      DS.svg [ SA.height_ "1000", SA.width_ "1000" ]
          [ DS.circle
                [ SA.cx_ "50"
                , SA.cy_ "50"
                , SA.r_ "40"
                , SA.stroke_ "black"
                , SA.strokeWidth_ "3"
                , SA.fill_ "red"
                ]
                []
          , DS.rect
              [ SA.x_ "250"
              , SA.y_ "250"
              , SA.rx_ "10" 
              , SA.ry_ "10" 
              , SA.stroke_ "red"
              , SA.strokeWidth_ "3"
              , SA.fill_ "black"
              --, SA.width_ "500" 
              --, SA.height_ "250" 
              ]
              []
          ]
  )
Ebmtranceboy commented 6 months ago

Of course, customization is possible with elementify2 but I think those two attributes should be accessible by default.

smilack commented 5 months ago

I ran into this issue too and found some related problems and a workaround for fixed-size rects.

Workaround for fixed-size rects

Instead of:

, SA.width_ "500"
, SA.height_ "250"

Give it a class:

, SA.klass_ "my-rect"

And set the size in CSS:

.my-rect {
  width: 500px;
  height: 250px;
}

This should give the same result because width and height are Presentation Attributes:

These are attributes whose name matches (or is similar to) a given CSS property and whose value is parsed as a value of that property.

The px unit is necessary because nonzero CSS lengths require units, but it should be equivalent because SVG interprets unitless numbers as pixels anyway.

Related problems

  1. The workaround should be possible to do in code, like this:

    , SA.style_ "width: 500px; height: 250px;"

    but despite Deku.DOM.SVG.Attributes exporting a style attribute, it doesn't appear that any element in Deku.DOM.SVG can use it!

  2. There are several other elements (foreignObject, image, rect, svg, symbol, and use) listed in the Presentation Attributes table that should also have access to width and height, but only svg does.

  3. There are some other discrepancies between presentation attributes listed in the SVG spec and their usage in Deku. For example, alignment-baseline should be available to all elements but Deku limits it to text-related elements. Deku makes pathLength available to all elements but the Regular Attributes table says it only applies to circle, ellipse, line, path, polygon, polyline, and rect.

Fixes?

(With the caveat that I don't really know how the codegen works)

The quickest solution would probably be to add width and height to svgPresentationMembers in codegen/src/Main.purs, but it wouldn't really be correct.

Adding width and height directly to foreignObject, image, rect, symbol, and use like it's currently done with svg should also work.

I don't know why no SVG elements have access to the style attribute or where that should be fixed. That may be a separate issue.

mikesol commented 2 weeks ago

@jterbraak , would a good place to tackle this be in the fixSVG function in the codegen? Reading it over now, that seems to be the spot where you're fixing the broken spec. Lemme know, if so I can take a stab at adding it there.