npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@rbxts/hotfusion

v0.3.0-hotfusion.1

Published

Fork of Fusion with improvements used by Team Fireworks

Downloads

11

Readme

Team Fireworks Fork

It's the Fusion reactive state library, done at 150 million degrees Celsius and a lethal amount of Thorium.

The following are changes from upstream:

  • Comprehensive roblox-ts types for Types.luau and init.luau. Enjoy writing declarative GUI with useful hints and autocomplete you've come to love
  • Value constructor now exports the object and a setter callback, as in (Value<T, S = T>, ValueSetter)
    • Deprecated Value:set()
    • Out now requires a setter function
  • Implements Observer:onlyOnce(callback) which behaves a single run onChange
  • Implements a bevy of built-in utilities:
    • expect(watching) yields the current running thread until the given state object changes, effectively a yielding Use callback
    • methodsOf(scope, constructors) allows silently passing in a scope parameter, hugely useful for the Roblox TypeScript world as you cannot specify a callback nor a method
    • queueScope(...Task) allows queuing tasks to a scope. We find this far more favorable than table.insert calls, as this is not only less verbose, but also guards against adding multiple tasks, accepts a variadic number of tasks, and returns the tasks you insert, allowing you to use it in declarations
  • Implements NewJSX constructor which behaves like New with JSX markup syntax
  • doCleanup has been extended to work with Promises, signals, threads, and and generic disconnect object methods
  • The library is renamed to Hotfusion to avoid conflicts with the original Fusion
  • Errors have been modified to separate Hotfusion specific errors

Install this fork with your preferred package manager of choice:

# Wally
wally add znotfireman/hotfusion
# npm
npm i rbxts/hotfusion
# pnpm
pnpm i rbxts/hotfusion

JSX

Hotfusion implements JSX-style New constructors. To use it, configure the jsx option in your tsconfig.json:

"compilerOptions": {
  "jsx": "react",
  "jsxFactory": "NewJSX"
}

[!IMPORTANT] Custom JSX factories are available in an unreleased version of roblox-ts, which can be installed by running npm install -D roblox-ts@next.

You can then import NewJSX from Hotfusion into a .tsx file:

import Hotfusion, {type Constructors, type Child, type Scope, NewJSX, ctorsOf, peek} from "@rbxts/hotfusion"

export function Counter(props: {Scope: Scope<object>}): Child {
  const scope = props.Scope
  const {Computed, Value} = ctorsOf(props.Scope, Hotfusion) as Constructors
  const [counter, setCounter] = Value(0)
  return (
    <textbutton
      Scope={scope}
      Text={Computed((use, scope) => {
        return `${use(counter)} clicks`
      })}
      OnEvent:Activated={() => setCounter(peek(counter) + 1)}
    ></textbutton>
  )
}

Scopes

For limitations with JSX, you need to pass a scope as the Scope property for all instances. For components, it may be favorable to have Scope as a property instead of a separate parameter:

// New
declare type Counter(
  scope: Scope<typeof Hotfusion>,
  props: {
    Counter: Value<number>
  }
): Child

// NewJSX
declare function Counter(props: {
  Scope: Scope<typeof Hotfusion>,
  Counter: Value<number>
}): Child

SpecialKeys

Given this code, how do we translate it into NewJSX syntax?

local OnHover: SpecialKey = {
  type = "SpecialKey",
  kind = "OnHover",
  stage = "observer",
  apply = function(scope, value, applyTo)
    -- do something with applyTo
  end
}
return scope:New "Frame" {
  [Children] = scope:New "TextLabel" {
    [OnHover] = true,
    [OnEvent "Activated"] = print()
  }
}

JSX disallows using objects as keys. Therefore, SpecialKeys cannot be specified as property keys. For this, Hotfusion implements the Uses property allowing you to use special keys.

Either pass in a tuple of [SpecialKey, value], or an Array<[SpecialKey, value]>:

const OnHover: SpecialKey = {
  type: "SpecialKey",
  kind: "OnHover",
  stage: "observer",
  apply(scope, value, applyTo) {
    // do something with applyTo
  }
}
return (
  <frame>
    <textbutton Uses={[OnHover, true]} />
    <textbutton
      Uses={[
        [OnEvent("Activated"), () => print("clicked")],
        [OnHover, true],
      ]}
    />
  </frame>
)

Some built-in special keys can be specified directly:

  • OnEvent("eventName") = function can be written as OnEvent:eventName={() => {}}
  • OnChange("propertyName") = function can be written as OnChange:propertyName={() => {}}
  • Out("propertyName") = setValue can be written as Out:propertyName={setValue}

Constructors

Fusion 0.3 employs a greater focus on manual memory management via the use of scopes. You'd use constructors as methods on a scope.

Working with scopes in roblox-ts can be cumbersome, as you will often be passing in the scope directly. Hotfusion provides the methodsOf function to make scoped constructors less verbose.

Pass in a table of constructors, and Hotfusion will omit the first scope parameter for you. Under the hood, Hotfusion will pass the scope directly to the constructor:

import * as Hotfusion from "@rbxts/hotfusion"
import {scoped, ctorsOf} from "@rbxts/hotfusion"

const scope = scoped()
const {Computed, Value} = ctorsOf(scope, Hotfusion)

// no scope parameter needed :)
const lib = Value("Hotfusion")
const message = Computed((use) => `i LOVE ${use(lib)}!!`)

[!WARNING] Typescript fumbles with inferring function generics. As such, constructors emitted by methodsOf loses its generics, becoming unknown.

You will see this if you try to use a Hotfusion constructor:

const {Computed} = ctorsOf(scope, Hotfusion)
//     ^^^^^^^^ 
//     expected Computed to be inferred as <T, S>(processor: (use: Use, scope: S) => T): Computed<T>
//     actually inferred as (processor: (use: Use, scope: unknown) => unknown): Computed<unknown>

For now, if you're using just Hotfusion as your constructors, cast the result of ctorsOf to the Constructors type:

const {Computed} = ctorsOf(scope, Hotfusion) as BuiltinConstructors
//     ^^^^^^^^
//     correctly inferred as <T, S>(processor: (use: Use, scope: S) => T): Computed<T>

Errors

invalidOutType

[Out] properties must be given a Value setter function. Value objects differs from Fusion - see Hotfusion README.",

Thrown by: Out, New, NewJSX

Out expected you to give it a value setter function, but you gave it something else.

Commonly, you may have tried providing a value object directly.

missingSpecialKeyValue

Special key OnEvent needs a value, but none was provided. Provide one with `OnEvent:myValue={...}`.

Thrown by: NewJSX

You've tried to specify one of the built-in special key generators, but forgot to provide a value. Use a colon to identify as such.

queuedTwice

Attempted to queue a task for destruction multiple times.

Thrown by: queueScope

Either you've specified the same object twice in queueScope, or an earlier queueScope has been called on the object and scope. As Fusion discourages repeated destruction, Hotfusion will disallow repeated queues.

valueSetWasRemoved

`Value:set()` has been deprecated. Capture the setter as a second return value from the constructor instead (e.g. `local value, setValue = Value(\"Foo\")`).

Thrown by: Value

Fusion lets you call :set() directly on value objects to set their current value and notify dependencies.

With Hotfusion, this has been moved as a second return argument for Value().

Original README

Rediscover the joy of coding.

Code is more dynamic, complex and intertwined than ever before. Errors cascade out of control, things update in the wrong order, and it's all connected by difficult, unreadable spaghetti.

No longer. Fusion introduces modern 'reactive' concepts for managing code, so you can spend more time getting your logic right, and less time implementing buggy boilerplate code connections.

Starting from simple roots, concepts neatly combine and build up with very little learning curve. At every stage, you can robustly guarantee what your code will do, and when you come back in six months, your code is easy to pick back up.

Piqued your interest? Get going in minutes with our on-rails tutorial.

Issues & contributions

Have you read our contribution guide? It's a real page turner!

We highly recommend reading it before opening an issue or pull request.

License

Fusion is licensed freely under MIT. Go do cool stuff with it, and if you feel like it, give us a shoutout!