Code Monkey home page Code Monkey logo

purescript-flame's People

Contributors

asvanberg avatar chekoopa avatar dependabot[bot] avatar easafe avatar justinwatt avatar niklas avatar timdeputter avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

purescript-flame's Issues

Spago configuration additions

Good job on converting to Spago. But I'm afraid there're old versions of Argonaut dependencies in the current package set. It would be fair to pin them for the moment, like:

let overrides =
  { argonaut = upstream.argonaut // { version = "v7.0.0" }
  , argonaut-codecs = upstream.argonaut-codecs // { version = "v7.0.0" }
  , argonaut-traversals = upstream.argonaut-traversals // { version = "v8.0.0" }
  , argonaut-generic = upstream.argonaut-generic // { version = "v6.0.0" }
  }

Also, there are two lines to add in spago.dhall:

, license = "MIT"
, repository = "https://github.com/easafe/purescript-flame"

I wouldn't interfere with my own PR right now, as I'm now working with the library using symlinks into my src. 😅

Snabbdom dependency

Currently, the library outsources dom patching to snabbdom. This has a few issues (that may or may not be worth being worked on):

  • As an external npm dependency, it adds friction to the development process

  • We can't update snabbdom at all since newer versions use ES modules which the PureScript compiler doesn't support yet

  • These might be eased by the latest changes (e.g., keyed), somehow managing to upgrade snabbdom, or just some work around code in our part, but there are many things that the current snabbdom implementation doesn't play nice with. From the top of my head: externally modifying nodes (in cases where hooks don't apply, usually with server side rendering), conditional rendering (e.g., if and else in views), content editable usage...

  • There is something to be said about improving bundle size and performance, but I am still looking into these (and snabbdom doesn't really maintain benchmarks)

A couple solutions come to mind:

  1. Simply wait out on the PS compiler, and then upgrade snabbdom

This is the easiest course of action, for obvious reasons. There is no time frame guarantee, though, or that all points will improve.

  1. Fork snabbdom and iron it out for usage with the library

This one could solve most of the outlined problems. I don't know how much the associated maintenance cost would increase, however.

  1. Use something else

Likely a lot of work. We can just fork any other JavaScript library -- as long the library current user facing API stays the same -- no need to go full NIHS. Feature matching might be a concern (e.g., if the new implementation doesn't use a virtual dom), specially given all of @chekoopa recent work 🙃.

Internationalisation

Right now the user-facing elements/attributes text, alt, placeholder, and any others are hard-coded to String.

If you want to localise an application you need access to the current language everywhere to make the proper translation. It would be better if Html had a second type hole so you can define your views something like Html message text. Then a Flame provided function localise :: (text -> a) -> Html message text -> Html message a can be used to translate everything into Html message String which can be returned from the view function of the application. If you do not need internationalisation you can just keep using String and no changes are required.

Fix documentation website

I can't afford to renew flamepurs.org which has now expired. Github does not accept projects to use username.github.io/project if a custom domain is enabled for the user, so the likely best solution is just to create an organization.

impossible to execute the ssr example

Hello,

I'm trying the ServerSide Rendering example but I have multiple problems. I tried to fix them, now I can build but I still have an error:

npm run server-side-rendering

> server-side-rendering
> npm run example-server-side-rendering && node examples/ServerSideRendering/dist/server-side-rendering-server.js


> example-server-side-rendering
> npm run example-server-side-rendering-server && npm run example-server-side-rendering-client


> example-server-side-rendering-server
> parcel build examples/ServerSideRendering/Server/server-side-rendering-server.js --dist-dir examples/ServerSideRendering/dist

✨ Built in 148ms

examples/ServerSideRendering/dist/server-side-rendering-server.js    178.73 KB    2.01s

> example-server-side-rendering-client
> parcel build examples/ServerSideRendering/Client/server-side-rendering-client.js --dist-dir examples/ServerSideRendering/dist

✨ Built in 115ms

examples/ServerSideRendering/dist/server-side-rendering-client.js    43.69 KB    1.41s
/Users/tcy/Documents/dev/workspaces/purescript/purescript-flame/examples/ServerSideRendering/dist/server-side-rendering-server.js:2
[...]
{return jc(i)(e)}))}(),Uc=function(e){return Mc(e.path)([Pc])?Ic:Lc};pc(3e3)(Uc)(Go("Server running on http://localhost:3000"))()})();


TypeError: n(...).createServer is not a function
    at /Users/tcy/Documents/dev/workspaces/purescript/purescript-flame/examples/ServerSideRendering/dist/server-side-rendering-server.js:2:159278
    at /Users/tcy/Documents/dev/workspaces/purescript/purescript-flame/examples/ServerSideRendering/dist/server-side-rendering-server.js:2:159320
    at /Users/tcy/Documents/dev/workspaces/purescript/purescript-flame/examples/ServerSideRendering/dist/server-side-rendering-server.js:2:161358
    at Object.<anonymous> (/Users/tcy/Documents/dev/workspaces/purescript/purescript-flame/examples/ServerSideRendering/dist/server-side-rendering-server.js:2:161362)
    at Module._compile (node:internal/modules/cjs/loader:1103:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
    at node:internal/main/run_main_module:17:47

Few informations:

spago --version
0.20.9

node --version
v16.14.2

Thanks a lot for this project, I'm looking forward to be able to play with the SSR :)

Make Flame.Types.Html a real type

Having Html a it be a real type will enable traversing the hierarchy and make modifications to it.

For example;

  • All a tags can be hijacked to use a custom on click handler to trigger a message that uses pushState and some internal routing state instead of reloading the entire page
  • All img tags can be modified to add the loading="lazy" attribute
  • Or any other type of transformation you may want to apply globally.

Package set publication

As Flame becomes mature, it should be published at least in the registry and, ideally, in package sets.

The only concern is unstable API, but right now the framework is pretty usable to be declared about.

UPD: I've double-checked, Flame is already in registry as Bower-published. Still, the point about package sets is up.

Grouping elements in SVG

Trying to render the example from https://developer.mozilla.org/en-US/docs/Web/SVG/Element/g using;

svg
  [ viewBox "0 0 100 100"
  , createAttribute "xmlns" "http://www.w3.org/2000/svg"
  ]
  [ g
    [ fill "white", stroke "green", strokeWidth "5" ]
    [ circle' [ cx "40", cy "40", r "25" ]
    , circle' [ cx "60", cy "60", r "25" ]
    ]
  ]

Fails and gives back a blank SVG. The problem appears to be the nesting of the circles inside the g tag, without the grouping the circles render fine.

HTML elements with empty array of attributes and/or children

Hi, thank you for this neat framework. I’m coming from Elm and I’m currently evaluating Flame to rewrite an Elm app in PureScript.

Is there a way to have HTML elements with an empty array of attributes and/or children?

  • p [] […children…] must be replaced by p_ […children…]
  • p […attributes…] [] must be replaced by p' […attributes…]
  • p [] [] is impossible to obtain (am I wrong?)

For readability reasons I want to avoid the HE. prefix everywhere before my tags so I import my elements one by one, and having to import p, p', p_ etc. is redundant.

For the same readability reason I really wish we could use explicit empty arrays rather than one character suffixes that completely change the usage of the element. Is there a way to do that without monkey-patching Flame? If not then you can consider this issue as a feature request 😉

Cheers,
Laurent

Suggestion: external custom events

As it is, raising an external event (i.e., not originated from the view) demands having the Channel created by mount or resumeMount.

This suffices for document or window events (or anything that can be set up right after mounting an application). It might be cleaner however to ditch channels altogether in favor of something like CustomEvent that would allows us to raise arbitrary messages from anywhere. One scenario where this is useful is having several mount points in a single app.

Question about Stale model in `AffUpdate`

I am studying the example at https://github.com/easafe/purescript-flame/blob/master/examples/EffectfulAffjax/Affjax.purs
and I think there is a racing condition which concerns model being stale while there are multiple model update in AffUpdate using display.

I have created a short video to capture this racing condition:

Screen.Recording.2023-06-09.at.5.21.04.PM.mov

So when user click Fetch for https://hub.dummyapis.com/delay?seconds=10 and then before the response is returned,
user changed it to https://hub.dummyapis.com/delay?seconds=1 and click Fetch again.
Second request is resolved first and displayed
then first request gets resolved and displayed as an outdated state now

Looking at the code

update AffUpdate Model Message
update { display, model, message } =
case message of
UpdateUrl url → FAE.diff { url, result: NotFetched }
Fetchdo
display $ FAE.diff' { result: Fetching }
response ← A.get AR.string model.url
FAE.diff <<< { result: _ } $ case response of
Left error → Error $ A.printError error
Right payload → Ok payload.body

At line 40, we would need to check the latest model to see if model.url is still the same as what we have requested.
Hence, we have the adjust the code to

update ∷ AffUpdate Model Message
update { display, model, message } =
  case message of
    UpdateUrl url → FAE.diff { url, result: NotFetched }
    Fetch → do
      display $ FAE.diff' { result: Fetching }
      response ← A.get AR.string model.url
      pure $ \m ->
        if m.url /= model.url then
          m
        else
          m { result = _ } $ case response of
            Left error → Error $ A.printError error
            Right payload → Ok payload.body

Is this idiomatic in this package?
Did I miss out anything?
Anyway to make this easier?

Styles should merge (or do they?)

Current Flame's behaviour on styles is overwriting, so the latter style or even styleAttr property only matters.
On other hand, Hedwig and Elm merge style attributes, giving us a single style list.

So, we should have that too. The most rational implementation is utilizing style module of Snabbdom. It also would enable us delayed, destroy and remove properties for basic animation features (not transitions, it would require more tinkering). And also, a challenge about CSS variables (such as --colorPrimary).

The only concerns are:

  • styleAttr behaviour on module-based styles (would it still overwrite these styles?)
  • static style rendering, like in tests

I'm on trying style module implementation. The current test case for this feature looks like:

test "style merging" do
        let html = HE.a [ HA.style { mystyle: "test", mylife: "good" }, HA.style { mystyle: "check" } ] [HE.text "TEST"]
        html' <- liftEffect $ FRS.render html
        TUA.equal """<a style="mystyle:check;mylife:good">TEST</a>""" html'

        let html2 = HE.a [HA.style { width: "23px", display: "none" }, HA.style { height: "10px" } ] [HE.text "TEST"]
        html2' <- liftEffect $ FRS.render html2
        TUA.equal """<a style="width:23px;display:none;height:10px">TEST</a>""" html2'

Integrating external element

Thank you very much for this package.

When I play around this package, I stumbled upon this case.

  • I have this beautiful element (drop down with dynamic autocomplete that updated realtime on change...) Heavily javascript powered.

Can I use this "widget" without reimplementing the JavaScript code? Where should I start?

At some point, I was wondering about server-side rendering examples. Is this a good start?

What options do I have for this case?

Thank you.

impossible to build examples

Hello,

Maybe I did something wrong, but it seams that is not possible anymore to compile examples.

spago build
npm ci
npm run build-examples

There is no output/Examples.* so parcel can't build. And I have a lot of errors like this:

 Build failed.

@parcel/core: Failed to resolve '../../output/Examples.EffectList.Affjax.Main' from './examples/Affjax/affjax.js'

  /private/tmp/purescript-flame/examples/Affjax/affjax.js:1:22
  > 1 | import { main } from '../../output/Examples.EffectList.Affjax.Main';
  >   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    2 | main();

I updated the spago.dhall to add the examples folder to try to fix the problem.


purs --version
0.15.6

spago --version
0.20.9

node --version
v18.12.0

Doctype

Currently, there is no way to specify a doctype. This mainly affects server side rendered applications, which end up in quirks mode.

A doctype tag could be added, but it either would have to allow children or always be used with a fragment.

Suggestion: Maybe type for event handlers

Now handleRawEvent under Flame.Renderer.toVNode just calls handler and gives its result to updater function, so when you're writing event handlers you have to return message regardless of the event's content.

For example, we would want to have a conditional event, like "on Enter key pressed", which now is implemented like this:

{- ... -}
import Flame.HTML.Attribute (createRawEvent)
import Web.Event.Event as Event

-- | Tries to extract a keycode from the event.
keyCode :: Event -> Maybe Int

onEnterPressed ::  msg. msg -> msg -> NodeData msg
onEnterPressed onFail onEnter = HA.createRawEvent "keyup" $ \event -> do
  Event.preventDefault event
  case keyCode event of
    Just 13 -> pure $ onEnter
    _ -> pure $ onFail  -- notice we can't just suppress it

The only possible alternative is just using onKeyup and filtering the pressed key in update function, but it mostly adds bloat in the application's logic (if you need to catch only one particular key).
One could try throwing an error to break the event handling, but it also breaks toVNode execution, too. Yes, we could just wrap handler into try, but it either prevents us from handling real errors or forces unpleasant trace messages in the console.

Therefore, the proposal is to change event handler's type to Event -> Effect (Maybe msg), so we could filter the event right in the handler. Also, it would look more consistent considering how EffectList update function deals with events (using Aff (Maybe msg)) and channel message types (either Array msg or Maybe msg).

The updated example code would look like this:

onEnterPressed ::  msg. msg -> NodeData msg
onEnterPressed onEnter = HA.createFilteredEvent "keyup" $ \event -> do
  Event.preventDefault event
  case keyCode event of
    Just 13 -> pure $ Just onEnter
    _ -> pure $ Nothing

The proposed changes wouldn't break existing API, as already placed event constructors only get an additional Just wrapper under the hood. But additionally, we'd get a createRawEvent' or createFilteredEvent (the naming is a point of discussion).

Runtime error when input element uses the `list` attribute

I was attempting to build a view function that included an <input>. That <input> made use of a <datalist> so it would autocomplete. Here's a cut down example of what I was trying to do:

view :: Model -> Html Message
view model =
  HE.main "main"
    $ [ HE.label [ HA.for "broken-input" ] "Broken input"
      , HE.input [ HA.type' "search", HA.name "broken-input", HA.id "broken-input", HA.list "search-results", HA.value model.searchResult, HA.onInput SearchStuff ]
      , HE.datalist [ HA.id "search-results" ] [ HE.option_ "Search..." ]
      ]

On Chrome this generates a runtime error: Uncaught TypeError: Cannot set property list of #<HTMLInputElement> which has only a getter
On Firefox this generates the same error (with a different message): Uncaught TypeError: setting getter-only property "list"

Seems the problem is Flame creates the Input and attempts to set the list attribute after, but since it's read-only this cannot work.

Examples or documentation for real-world applications

Hello. The examples in the aptly-named folder are great and very useful, but they're all kind of toy examples. Same can be said for the documentation. Ideal to grasp the general concepts but not quite enough to understand what would it be to build a life-scale front-end application, with dozens of views/pages, dozens of state elements synchronized with a backend API, complex interactions between "components" etc.

Would there be anything available that demonstrates (or documents) the recommended way to structure Flame applications in a more real-life fashion?

I'd be particularly interested in:

  • how to handle different views/pages based on routing (e.g. login, settings, posts, dashboard...)
    • should we use purescript-routing for this? how to integrate it with purescript-flame?
  • how to handle global application state (sort-of the equivalent of a Vuex/Redux "store")
    • e.g. subscribe/emit are fine for a few items but things become unbearable quickly without a global store
  • how to handle synchronization between backend API and application state
  • user authorization/authentication
  • integration with a full-blown UI library like Foundations, Bootstrap or Bulma
  • basically anything that showcases a real-life, complex application built with Flame

Many thanks.

Build failed

I have initialized a new project with pulp init and added flame with bower install purescript-flame.
Doing pulp build produces these errors:

[1/9 ModuleNotFound] bower_components/purescript-flame/src/Flame/Application/EffectList.purs:19:1

  19  import Data.Argonaut.Decode.Generic.Rep (class DecodeRep)
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  
  Module Data.Argonaut.Decode.Generic.Rep was not found.
  Make sure the source file exists, and that it has been provided as an input to the compiler.

[2/9 ModuleNotFound] bower_components/purescript-flame/src/Flame/Application/Effectful.purs:20:1

  20  import Data.Argonaut.Decode.Generic.Rep (class DecodeRep)
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  
  Module Data.Argonaut.Decode.Generic.Rep was not found.
  Make sure the source file exists, and that it has been provided as an input to the compiler.

[3/9 ModuleNotFound] bower_components/purescript-flame/src/Flame/Application/NoEffects.purs:14:1

  14  import Data.Argonaut.Decode.Generic.Rep (class DecodeRep)
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  
  Module Data.Argonaut.Decode.Generic.Rep was not found.
  Make sure the source file exists, and that it has been provided as an input to the compiler.

[4/9 ModuleNotFound] bower_components/purescript-flame/src/Flame/Application/PreMount.purs:7:1

  7  import Data.Argonaut.Core as DAC
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  
  Module Data.Argonaut.Core was not found.
  Make sure the source file exists, and that it has been provided as an input to the compiler.

[5/9 ModuleNotFound] bower_components/purescript-flame/src/Flame/Application/PreMount.purs:8:1

  8  import Data.Argonaut.Decode.Generic.Rep (class DecodeRep)
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  
  Module Data.Argonaut.Decode.Generic.Rep was not found.
  Make sure the source file exists, and that it has been provided as an input to the compiler.

[6/9 ModuleNotFound] bower_components/purescript-flame/src/Flame/Application/PreMount.purs:9:1

  9  import Data.Argonaut.Decode.Generic.Rep as DADEGR
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  
  Module Data.Argonaut.Decode.Generic.Rep was not found.
  Make sure the source file exists, and that it has been provided as an input to the compiler.

[7/9 ModuleNotFound] bower_components/purescript-flame/src/Flame/Application/PreMount.purs:10:1

  10  import Data.Argonaut.Encode.Generic.Rep (class EncodeRep)
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  
  Module Data.Argonaut.Encode.Generic.Rep was not found.
  Make sure the source file exists, and that it has been provided as an input to the compiler.

[8/9 ModuleNotFound] bower_components/purescript-flame/src/Flame/Application/PreMount.purs:11:1

  11  import Data.Argonaut.Encode.Generic.Rep as DAEGR
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  
  Module Data.Argonaut.Encode.Generic.Rep was not found.
  Make sure the source file exists, and that it has been provided as an input to the compiler.

[9/9 ModuleNotFound] bower_components/purescript-flame/src/Flame/Application/PreMount.purs:12:1

  12  import Data.Argonaut.Parser as DAP
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  
  Module Data.Argonaut.Parser was not found.
  Make sure the source file exists, and that it has been provided as an input to the compiler.

           Src   Lib   All
Warnings   0     0     0  
Errors     0     9     9  
* ERROR: Subcommand terminated with exit code 1

Am I doing something wrong?

Bug when using a function as the type of a message

The minimal reproducible example would be this.

module Main where

import Prelude

import Effect (Effect)
import Flame.Application.NoEffects (mount_)
import Flame.Html.Element as HE
import Flame.Types (Html, Subscription)
import Flame.Html.Attribute as HA
import Flame (QuerySelector(..))

type Model = Int
type Message = Model -> Model

init :: Model
init = 0

subscribe :: Array (Subscription Message)
subscribe = []

view :: Model -> Html Message
view model = HE.button [HA.onClick ((+) 1)] (show model)

update :: Model -> Message -> Model
update model message = message model

main :: Effect Unit
main = do
  mount_ (QuerySelector "body") { init, subscribe, view, update}

I get that the point of messages is to limit the type of mutations one can do on the model. But I was playing around with that, since it allows me to try some things faster while i decide how to structure the state and its mutations. Trying this however fails, and when the button is clicked the following error is logged

caught TypeError: h(...) is not a function
    at F.runHandlers (index.js:2273:51)
    at F.runEvent (index.js:2264:14)

Is this known?

Feature proposal: vnode hooks

Snabbdom has a really powerful feature to inject functions into VNodes (https://github.com/snabbdom/snabbdom#hooks), and we use hooks in Hedwig (I even had to fork it to add them) for some tricks, such as Markdown rendering.

We consider switching to Flame (as Hedwig seems to be discontinued), but for now, it misses some low-level features, such as hooks, keyed, and thunks (however, we don't use it, but laziness is a great perk).

hooks attribute is situated in VNodeData, so it seems to enable hooks being treated as a NodeData, like NodeHook string (VNode -> Effect message) (but it actually needs an additional for update hooks with two VNode parameters), and therefore being used as a node attribute (like, ToNodeHook1 and ToNodeHook2, or something more static).

The `tabindex` attribute does not work due to capitalization

The tabIndex attribute does not do anything because Flame spells it with a lowercase i.

By "does not do anything" I mean that when I inspect the generated HTML in the browser, the attribute does not appear at all (disregarding capitalization). For some reason, it worked fine after I replaced all occurrences of tabindex with tabIndex in src/Flame/Html/Attribute.purs and src/Flame/Html/Attribute/Internal.purs.

friction at running examples

Currently if one wants to check out this library and isn't familiar with spago, the readme inside the examples folder is not too helpful:

Build all examples with
```bash
npm run build-examples
```

This command doesn't actually build the purs files and running it without installing and building with spago results in an error. Maybe the readme could contain all the steps to build the examples or the npm run scripts should be setup differently like

"example-counter" : "spago build -p examples/Counter/Counter.purs && parcel build examples/Counter/counter.js --dist-dir examples/Counter/dist && parcel serve examples/Counter/counter.html"

to build and serve an example for an effortless setup.

I understand this exact solution wouldn't work with `npm run build-examples' and tests, just making a general suggestion.

How to use with spago?

Hello,
I'm coming from elm and scala and I'm just trying out purescript and found this library. I'm quite lost with all the build tools used in purescript. So I'm sorry if this sounds completely stupid: The tutorials I went through made me use spago. Now this lib mentions bower. Can I install this lib via spago somehow? Or can I use both togehter?
Thank you!

`lazy` with mutliple html composition layers appears to cause runtime errors / other odd behavior

Heya! I've been looking into this issue for a bit and it has stumped me, but I've narrowed it down to a reasonably small example.

In this example I have a "counter component" with it's own model, update, view, etc. I wrap the view function of this component in lazy. As this component is nested deep in a large application, the CounterMsg is lifted up multiple layers via PageMsg <$> CounterMsg <$> counterView model.counter.

However, it appears when a lazy node is mapped in this way (specifically two layers upwards), it will error in response to any event that dispatches a message within that node. In this case I see v is undefined (upon further inspection, "v" being the message type passed to updateCounter), though in our larger application we see Failed pattern match

import Flame.Application.NoEffects (mount_)
import Flame.Html.Element (lazy)
import Flame.Html.Element as H
import Flame.Html.Event as E

data CounterMsg
  = Increment Int

type CounterModel
  = { count :: Int }

initCounter :: CounterModel
initCounter = { count: 1 }

updateCounter :: CounterModel -> CounterMsg -> CounterModel
updateCounter model (Increment val) = model { count = model.count + val }

counterView :: CounterModel -> Html CounterMsg
counterView = lazy Nothing counterView_

counterView_ :: CounterModel -> Html CounterMsg
counterView_ model =
  H.div_
    [ H.button
        [ E.onClick $ Increment 1000 ]
        [ H.text $ "Current Value: " <> show model.count ]
    ]

data Msg
  = PageMsg PageMsg

data PageMsg
  = CounterMsg CounterMsg

type Model
  = { counter :: CounterModel }

init :: Model
init = { counter: initCounter }

update :: Model -> Msg -> Model
update model (PageMsg (CounterMsg msg)) = model { counter = updateCounter model.counter msg }

view :: Model -> Html Msg
view model =
  H.div_
    [ PageMsg <$> CounterMsg <$> counterView model.counter
    ]

main :: Effect Unit
main =
  mount_ (QuerySelector "#app")
    { subscribe: []
    , init
    , update
    , view
    }

Removing a layer of mapping in the view fixes this problem. If I redefine

data Msg
  = PageMsg PageMsg

data PageMsg
  = CounterMsg CounterMsg

to

data Msg
  = CounterMsg CounterMsg

And remove the extraneous mapping then things work as expected

Trivial ToClassList instance

We already have ToClassList instances for string and record, both of which are implemented by transforming them into Array String. Meanwhile, it seems that it could be good idea to add a trivial instance ToClassList (Array String) so that we can save time while avoid long lines when handling with libraries like TailwindCSS. Alternatively, we can add a classList attribute to handle things.

To be exact, we could add

instance ToClassList (Array String) where
    to = identity

here for the former idea.

What would you think?

`ReferenceError: document is not defined` on `spago run`

Minimal reproducible example:

spago init
spago install flame
cd flame micro
# counter example from https://github.com/easafe/purescript-flame to src/Main.purs
spago run

Output:

[501 of 501] Compiling Main
[info] Build succeeded.
file:///Users/benjamin/repos/experiments/flame-micro/output/Flame.Application.Internal.Dom/foreign.js:3
    return document.querySelector(selector);
    ^

ReferenceError: document is not defined
    at Module.querySelector_ (file:///Users/benjamin/repos/experiments/flame-micro/output/Flame.Application.Internal.Dom/foreign.js:3:5)
    at __do (file:///Users/benjamin/repos/experiments/flame-micro/output/Flame.Application.Internal.Dom/index.js:9:33)
    at __do (file:///Users/benjamin/repos/experiments/flame-micro/output/Flame.Application.EffectList/index.js:144:87)
    at file:///Users/benjamin/repos/experiments/flame-micro/.spago/run.js:3:1
    at ModuleJob.run (node:internal/modules/esm/module_job:192:25)
    at async DefaultModuleLoader.import (node:internal/modules/esm/loader:228:24)
    at async loadESM (node:internal/process/esm_loader:40:7)
    at async handleMainPromise (node:internal/modules/run_main:66:12)

Node.js v20.5.0
[error] Running failed; exit code: 1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.