Pewarta Proxy

📋 Server Request & Proxy Logs

Loading active proxy settings...
Developed by Khairul Adha (adhexa.id)
Mengambil log server...

⚙️ Pengaturan Proxy Target

Skip to content

withStyles #9

Open
Open

Description

@paluh

What do you think about this inherently unsafe API for withStyles:

foreign import withStylesImpl ∷ ∀ props
  . (Theme → JSS)
  → ({ | props } → JSX)
  → ReactComponent { | props }

withStyles ∷ ∀ props
  . (Theme → JSS)
  → ({ | props } → JSX)
  → ({ | props } → JSX)
withStyles t c = element (withStylesImpl t c)
exports.withStyles = require("@material-ui/core/styles/withStyles").default;

Usage:

withStyles (const $ jss { root: { padding: "20px" }}) MUI.Paper.paper
  { elevation: 0.0, children: [ DOM.text "test" ]}

It seems that we can do better by using classes type (PaperClassKeyOptions in this case) and turning them into some constraint maybe by using this lib:

https://github.com/natefaubion/purescript-typelevel-eval

For sure there will be a problem with media queries as keys. We could provide the above as unsafeWithStyles and type safe (but too constrained) version as withStyles to cover these all cases.

Activity

  1. paluh commented on Jul 29, 2019

    @paluh
    CollaboratorAuthor

    I'm not sure why but the above rerenders to much. I've tried to put constant JSS instead of a function Theme -> JSS as argument but is still unmounting I think (for example it looses focus in forms etc.) Even when elementKeyed is used this bad behavior is preserved and even when to whole styled component is created statically up front.

    Do you have any idea what is wrong with the above?

  2. dwhitney commented on Jul 29, 2019

    @dwhitney
    Collaborator

    It seems that we can do better by using classes type (PaperClassKeyOptions in this case) and turning them into some constraint maybe by using this lib:

    Yes, and in fact there needs to be a function that convert the *ClassKeyOptions to something that changes the value type from String to JSS to make Overrides work properly. I'll ask in slack if there is some existing way of doing this, but otherwise, it'll have to be one of those recursive typelevel brain f*cks that I only do often enough to forget how every time :)

    I'm not sure why but the above rerenders to much.

    have you tried memo from the lumi React Hooks lib?

  3. dwhitney commented on Jul 29, 2019

    @dwhitney
    Collaborator

    ok I've added the JSS types mentioned above

  4. paluh commented on Jul 29, 2019

    @paluh
    CollaboratorAuthor

    ok I've added the JSS types mentioned above

    Wow! Cool!

    Regarding rerendering it seems that we have to work with ReactComponents directly (to be honest I don't understand mui docs related to HOC and withStyles). Given this untyped bindings:

    foreign import withStyles ∷ ∀ props
      . (Theme → JSS)
      → ReactComponent { | props }
      → ReactComponent { | props }
    
    
    foreign import styled ∷ ∀ a props
      . ReactComponent a
      → JSS
      → ReactComponent a
    exports.withStyles = require("@material-ui/core/styles/withStyles").default;
    exports.styled = require("@material-ui/core/styles/styled").default;

    This works fiine without unnecessary unmounting:

    element (withStyles (const $ jss { root: { padding: "100px" }}) MUI.Core.Paper._Paper)
  5. dwhitney commented on Jul 29, 2019

    @dwhitney
    Collaborator
  6. paluh commented on Jul 29, 2019

    @paluh
    CollaboratorAuthor

    The problem is that we have only untyped versions of ReactComponent values in the lib. If we provide types for ReactComponent values something like:

    foreign import _Paper ∷ ∀ props props_
      . Union props props_ (PaperProps Props_div)
      ⇒ ReactComponent { | props }

    related *_component functions probably won't type check. Likepaper_component function (which is also a bit unclear to me - I have to reread your explanation ;-)) doesn't typecheck in this case.

  7. dwhitney commented on Jul 29, 2019

    @dwhitney
    Collaborator
  8. paluh commented on Jul 29, 2019

    @paluh
    CollaboratorAuthor

    Please, don't rush on my account. I'm one foot offline already ;-)

  9. paluh commented on Jul 30, 2019

    @paluh
    CollaboratorAuthor

    I've tried to turn row of String into row of JSS with purescript-typelevel-eval (which I've updated on my fork to use new purs). It is quite straightforward. Just copy and paste from README.md:

    type ToJSS = ToRow <<< Map (Const JSS) <<< FromRow

    Usage as constraint:

    ...
      ⇒ Eval (ToJSS (RProxy PaperClassKeyOptions)) (RProxy jssProps)

    Using the above and explicite types - this works fine:

    type ToJSS = ToRow <<< Map (Const JSS) <<< FromRow
    
    foreign import withStyles ∷ ∀ jss jss_ jssProps props props_
      . Union props props_ (PaperProps Props_div)
      ⇒ Eval (ToJSS (RProxy PaperClassKeyOptions)) (RProxy jssProps)
      ⇒ Union jss jss_ jssProps
      ⇒ (Theme → { | jss })
      → ReactComponent { | props }
      → ReactComponent { | props }

    Let's assume that we introduce something like:

    foreign import data MUIComponent ∷ # Type → Type

    to talk about components which use subset of a given field set. I was not able using this type to provides constraints which are usable without annotation. I've tried this flow:

    • take classes record from this phantom type (assuming that classes contains record value with Strings like PaperClassKeyOptions
    • compute type of a record with JSS values from the above
    • use this type inside callback type (I mean this: (Theme → { | jss }))

    Maybe the above attempt is irrelevant as I'm not "compiler guy" and I'm usually lost when compilers tells me about his inference problems ;-) But maybe we should tag MUIComponent with props but also with JSS rows to avoid this Eval stuff and then this function type signature will be much easier to write. I know that there will be redundancy of information in types but we probably gain usability by improving all related error messages ;-)

  10. paluh commented on Nov 13, 2019

    @paluh
    CollaboratorAuthor

    @srghma
    Thanks for suggestion! For sure we have to cover that as well. I have not experience with hooks and react-basic-hooks yet (@dwhitney do you use hooks already? ;-))

    Regarding current status of withStyles I allow myself to copy comment from the other thread here:

    There are *WithStyles functions in every component module which allow styling. For example:

    https://github.com/dwhitney/purescript-react-basic-mui/blob/codegen-read-dts/src/MUI/Core/Fab.purs#L71

    We can build restyled component with it:

    myStyledFabButton = MUI.Core.Fab.fabWithStyles \theme →
      { root: MUI.Core.jss
        { background: "white"
        , bottom: theme.spacing(4.0)
        , position: "fixed"
        , left: "50%"
        , transform: "translateX(-50%)"
        }
      }

    and use it:

    render _ = myStyledFabButton { children: [ DOM.text "TEST" ]}
  11. dwhitney commented on Nov 13, 2019

    @dwhitney
    Collaborator

    hey @paluh and @srghma

    yes I use hooks for styling. I put something together with react-basic-hooks. Someone else also asked for an example. I'm going to be working all day again on this project, so I'll put together an example.

  12. dwhitney commented on Nov 13, 2019

    @dwhitney
    Collaborator

    I'm not going to have time to put together an example today, so I'll leave some sample code here, which may help you.

    how to create a hook for styles:

    FFI

    exports.makeStyles = require("@material-ui/core/styles/makeStyles").default;
    foreign import data UseStyles :: Type -> Type
    foreign import makeStyles :: ∀ props . (Theme -> { | props }) -> Hook UseStyles (Object String)

    Usage:

    useStyles :: Hook UseStyles (Object String)
    useStyles = makeStyles \theme -> 
      { root:
          { display: "flex"
          , padding: theme.spacing(2.0)
          , backgroundColor: solarized.base02
          }
      }
    
    mkSearch :: CreateComponent SearchProps
    mkSearch = do
      searchResultsTable  <- SearchResultsTable.mkSearchResultsTable
      component "Search" \props -> React.do
         classes  <- useStyles
    ...

    The classes value above is of type Object String where the keys are the keys of the record defined in the useStyles function (root in this example) and the value is whatever class name JSS creates (something like root_1234).

    I use the above hook all over my codebase and it has worked well. We should probably ship it with this lib.

  13. dwhitney commented on Nov 13, 2019

    @dwhitney
    Collaborator
  14. paluh commented on Nov 13, 2019

    @paluh
    CollaboratorAuthor

    Probably we should be able to add layer of our *ClassKeyOptionsJSS type safety to it somehow too.

  15. dwhitney commented on Nov 13, 2019

    @dwhitney
    Collaborator

    yeah there is probably a useful idea in there somewhere, but in general what I posted above is independent of the *ClassKey because you can use the values from the classes object along with the className attribute that exists in most react elements.

  16. dwhitney commented on Jan 11, 2020

    @dwhitney
    Collaborator
  17. paluh commented on Jan 12, 2020

    @paluh
    CollaboratorAuthor

    @srghma I just want to add that I've not tested or used API hooks yet with useStyles etc. We are using functions like MUI.Core.Grid.gridWithStyles with react-basic components so I'm not able to help at the moment.

    P.S.
    I think you should not use my PR branch but codegen-read-dts branch from this repo which contains all changes from the PR.
    @dwhitney Do you think that we should close this PR to clarify current status?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions