Detalhes do pacote

@benev/frog

benevolent-games57MIT0.6.0-dev.5

frontend web stuff

frog, framework, component-framework, state

readme (leia-me)

🐸 frog – frontend web framework

🕹️ live demo: https://frog.benev.gg/
📦 frog is an npm package: @benev/frog
📜 documentation coming sooner or later..
❤️ frog is free and open source



🥞 Flatstate

flatstate helps you create state objects and reaction functions which are called when properties change.

flatstate is inspired by mobx and snapstate, but designed to be really simple: flatstate only works on flat state objects, only the direct properties of state objects are tracked for reactivity.

flatstate basics

  • create a flatstate tracking context

    import {Flat} from "@benev/frog"
    
    const flat = new Flat()
  • make a flat state object
    const state = flat.state({count: 0})
  • setup a reaction

    flat.reaction(() => console.log(state.count))
      //-> 0
    
    state.count++
      //-> 1
    • flatstate records which state properties your reaction reads
    • flatstate calls your reaction whenever those specific properties change
    • your reaction can listen to more than one state object

flatstate details

  • reactions are debounced -- so you may have to wait to see state changes

    const flat = new Flat()
    const state = flat.state({amount: 100})
    
    state.amount = 101
    console.log(state.amount) //-> 100 (old value)
    
    await flat.wait
    console.log(state.amount) //-> 101 (now it's ready)
  • you can stop a reaction

    const stop = flat.reaction(() => console.log(state.count))
    
    stop() // end this particular reaction
  • clear all reactions on a flatstate instance
    // clear all reactions on this flat instance
    flat.clear()

flatstate reactions

  • so first, there's a simple one-function reaction:
    flat.reaction(() => console.log(state.count))
    • flatstate immediately runs the function, and records which properties it reads
    • then, anytime one of those properties changes, it runs your function again
  • you can also do a two-function reaction:
    flat.reaction(
      () => ({count: state.count}),
      ({count}) => console.log(count),
    )
    • now there's a separation between your "collector" and your "responder"
    • the collector "passes" relevant data to the responder function
    • flatstate calls the responder whenever that data changes
  • there's also this helper called "collectivize" if you prefer the syntax sugar:

    const c = Flat.collectivize(state)
    
    flat.reaction(
      c(({count}) => ({count})),
      ({count}) => console.log(count)
    )
  • there's also something called "deepReaction"
    flat.deepReaction(() => console.log(state.count))
    • it's the same as "reaction", but it has "discovery" enabled
    • discovery means the collector is checked again for every responder call
    • it's less efficient, but allows you to respond to deeply nested recursive structures
  • there's also .auto and .manual reactions
    • these allow you to set options like discovery and debounce (you can turn off the debouncer)
    • but that's bigbrain stuff that you'll have to read the sourcecode about

flatstate advanced

  • multiple flatstate instances are totally isolated from each other
    const flat1 = new Flat()
    const flat2 = new Flat()
  • create readonly access to a state object

    const state = flat.state({count: 0})
    const rstate = Flat.readonly(state)
    
    state.count = 1
    await flat.wait
    console.log(rstate.count) //-> 1
    
    rstate.count = 2 // !! ReadonlyError !!
    • btw, you can use readonly on anything, not just flatstate

flatstate integration with frontend elements

  • let your components rerender on flat state changes

    import {flatstate_reactivity} from "@benev/frog"
    
    const elements = flatstate_reactivity(flat)(elements)



🪈 Pipe

  • pipe data through a series of functions
  • maybe you've done silly nesting like this:
    // bad
    register_to_dom(
      mixin_flatstate_reactivity(flat)(
        apply_theme(theme)(
          provide_context(context)(elements)
        )
      )
    )
  • now you can do this instead:

    import {Pipe} from "@benev/frog"
    
    // good
    Pipe.with(elements)
      .to(provide_context(context))
      .to(apply_theme(theme))
      .to(flatstate_reactivity(flat))
      .to(register_to_dom)



💫 Op

utility for ui loading/err/ready states.

useful for implementing async operations that involve loading indicators.

  • ops are just plain objects, and they have a mode string (loading/err/ready)

    import {Op} from "@benev/frog"
    
    console.log(Op.make.loading())
      //-> {mode: "loading"}
    
    console.log(Op.make.err("a fail occurred"))
      //-> {mode: "err", reason: "a fail occurred"}
    
    console.log(Op.make.ready(123))
      //-> {mode: "ready", payload: 123}
  • you can run an async operation that will update your op accordingly

    let my_op = Op.make.loading()
    
    await Op.run(op => my_op = op, async() => {
      await nap(1000)
      return 123
    })
  • functions to interrogate an op

      //        type for op in any mode
      //                 v
    function lol(op: Op.Any<number>) {
    
      // branching based on the op's mode
      Op.select(op, {
        loading: () => console.log("op is loading"),
        err: reason => console.log("op is err", reason),
        ready: payload => console.log("op is ready", payload)
      })
    
      const payload = Op.payload(op)
        // if the mode=ready, return the payload
        // otherwise, return undefined
    }

changelog (log de mudanças)

  • (!) flipview
    • views now have simpler syntax
      DemoView(settings)(prop1, prop2)(content)
      DemoView({settings, props: [prop1, prop2], content})
    • reworked use.setup hook
      • now use.setup must return {result, setdown}
      • use.setup actually returns the result
      • thus allowing you to setup a reusable object
    • renames
      • BaseContext -> PrepperContext
      • Render -> PrepperRender
      • FlippyOptions -> PrepperOptions
      • flipview_context_prepper -> flipview_prepper
  • (!) base addon attributes deprecated in favor of new Attrs
  • (!) rework requirement types and names
  • (!) rename almost every flipview type
    • FlipviewOptions becomes FlipOptions
    • a bunch more renames along those same lines
  • add LightElement (lightdom)
  • add standardized frontend prepare system

v0.5.0 - 2023-08-17

  • (!) introducing flipview
    • deleted flatview
    • deleted flapjack
    • flipview is our new view system

v0.4.0 - 2023-08-03

  • flatview
    • (!) flatview usage syntax changed:
      • used to be like DemoView("hello")
      • is now like DemoView()("hello")
      • you can pass exportparts and part into the first parens
      • like this DemoView({part: "button", exportparts: "a"})("hello")
    • (!) add tag option to flatview
      • default is now div (was span)
    • add name option to flatview
      • it appears on the element as data-view
  • op
    • (!) rename stuff in Op
      • err renamed to error
      • Op.Any<any> renamed to Op.For<any>
  • add flapjack as flatview-alternative

v0.3.0 – 2023-07-23

  • (!) flatview signature changes
    • flat now comes first, like flatview(flat, {strict: true})
    • strict is now true by default (was false)
  • (!) gutted QuickElement
    • cues ripped out of QuickElement
    • attributes addon ripped out QuickElement
    • goal is to make quickelement agnostic about state management etc
    • added add_setup method, which make it easy to create setups/setdowns
    • added overridable init() {} method, runs in constructor
  • export Elements type
  • export attributes addon for base elements
  • add apply_styles_to_shadow

v0.2.0 – 2023-07-22

  • (!) rename Flatstate to Flat
  • add flatview
  • add requirement tool

v0.1.0 – 2023-07-19

  • (!) rework and rename all the base element helpers
    • now they all use curry syntax, intended to be used with Pipe
      • old syntax:
        theme_elements(theme, pass_context_to_elements(context, elements))
      • new syntax:
        apply_theme(theme)(provide_context(context)(elements))
      • but you should really use pipes now:
        Pipe.with(elements)
          .to(provide_context(context))
          .to(apply_theme(theme))
    • renames
      • mix_flatstate_reactivity_into_elements 🡪 flatstate_reactivity
      • pass_context_to_elements 🡪 provide_context
      • register_elements 🡪 register_to_dom
      • theme_elements 🡪 apply_theme
      • update_elements_on_cue_changes 🡪 cue_reactivity
      • update_elements_on_snap_changes 🡪 snap_reactivity
  • (!) remove Op.make
    • Op.make.loading is now just Op.loading
    • Op.make.err is now just Op.err
    • Op.make.ready is now just Op.ready

v0.0.1 - 2023-07-18

  • add flatstate
  • add op
  • add pipe