mirror of
https://github.com/littensy/charm.git
synced 2026-10-22 21:01:38 +00:00
refactor: replace all references to molecules
This commit is contained in:
parent
5eacec70ff
commit
7152f21129
12 changed files with 69 additions and 56 deletions
29
src/charm-sync/src/index.d.ts
vendored
29
src/charm-sync/src/index.d.ts
vendored
|
|
@ -1,4 +1,4 @@
|
|||
import { Atom, Molecule } from "@rbxts/charm";
|
||||
import { Atom, Selector } from "@rbxts/charm";
|
||||
|
||||
export = CharmSync;
|
||||
export as namespace CharmSync;
|
||||
|
|
@ -8,13 +8,18 @@ type Cleanup = () => void;
|
|||
declare namespace CharmSync {
|
||||
type AtomMap = Record<string, Atom<any>>;
|
||||
|
||||
type MoleculeMap = Record<string, Molecule<any>>;
|
||||
/**
|
||||
* @deprecated Use `SelectorMap` instead.
|
||||
*/
|
||||
type MoleculeMap = Record<string, Selector<any>>;
|
||||
|
||||
type SelectorMap = Record<string, Selector<any>>;
|
||||
|
||||
/**
|
||||
* Recursively infers the type of the state produced by a map of molecules.
|
||||
* Infers the type of the return values produced by a map of functions.
|
||||
*/
|
||||
type StateOfMap<T> = {
|
||||
[P in keyof T]: T[P] extends Molecule<infer State> ? State : never;
|
||||
[P in keyof T]: T[P] extends Selector<infer State> ? State : never;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -45,7 +50,7 @@ declare namespace CharmSync {
|
|||
* @param options The atoms to synchronize with the client.
|
||||
* @returns A `ServerSyncer` object.
|
||||
*/
|
||||
function server<Molecules extends MoleculeMap>(options: ServerOptions<Molecules>): ServerSyncer<Molecules>;
|
||||
function server<Selectors extends SelectorMap>(options: ServerOptions<Selectors>): ServerSyncer<Selectors>;
|
||||
|
||||
/**
|
||||
* Checks whether a value is `None`. If `true`, the value is scheduled to be
|
||||
|
|
@ -90,9 +95,9 @@ declare namespace CharmSync {
|
|||
* A payload that can be sent from the server to the client to synchronize
|
||||
* state between the two.
|
||||
*/
|
||||
type SyncPayload<Molecules extends MoleculeMap> =
|
||||
| { type: "init"; data: StateOfMap<Molecules> }
|
||||
| { type: "patch"; data: SyncPatch<StateOfMap<Molecules>> };
|
||||
type SyncPayload<Selectors extends SelectorMap> =
|
||||
| { type: "init"; data: StateOfMap<Selectors> }
|
||||
| { type: "patch"; data: SyncPatch<StateOfMap<Selectors>> };
|
||||
|
||||
interface ClientOptions<Atoms extends AtomMap> {
|
||||
/**
|
||||
|
|
@ -106,11 +111,11 @@ declare namespace CharmSync {
|
|||
ignoreUnhydrated?: boolean;
|
||||
}
|
||||
|
||||
interface ServerOptions<Molecules extends MoleculeMap> {
|
||||
interface ServerOptions<Selectors extends SelectorMap> {
|
||||
/**
|
||||
* The atoms to synchronize with the client.
|
||||
*/
|
||||
atoms: Molecules;
|
||||
atoms: Selectors;
|
||||
/**
|
||||
* The interval at which to send patches to the client, in seconds.
|
||||
* Defaults to `0` (patches are sent up to once per frame). Set to a
|
||||
|
|
@ -139,7 +144,7 @@ declare namespace CharmSync {
|
|||
sync(...payloads: SyncPayload<Atoms>[]): void;
|
||||
}
|
||||
|
||||
interface ServerSyncer<Molecules extends MoleculeMap> {
|
||||
interface ServerSyncer<Selectors extends SelectorMap> {
|
||||
/**
|
||||
* Sets up a subscription to each atom that schedules a patch to be sent to
|
||||
* the client whenever the state changes. When a change occurs, the `callback`
|
||||
|
|
@ -151,7 +156,7 @@ declare namespace CharmSync {
|
|||
* @param callback The function to call when the state changes.
|
||||
* @returns A cleanup function that unsubscribes all listeners.
|
||||
*/
|
||||
connect(callback: (player: Player, ...payloads: SyncPayload<Molecules>[]) => void): Cleanup;
|
||||
connect(callback: (player: Player, ...payloads: SyncPayload<Selectors>[]) => void): Cleanup;
|
||||
/**
|
||||
* Hydrates the client's state with the server's state. This should be
|
||||
* called when a player joins the game and requires the server's state.
|
||||
|
|
|
|||
8
src/charm/src/index.d.ts
vendored
8
src/charm/src/index.d.ts
vendored
|
|
@ -37,6 +37,14 @@ declare namespace Charm {
|
|||
*/
|
||||
type Selector<State> = () => State;
|
||||
|
||||
/**
|
||||
* A function that depends on one or more atoms and produces a value. Can be
|
||||
* used to derive state from atoms.
|
||||
*
|
||||
* @returns The current state.
|
||||
*/
|
||||
type Molecule<State> = Selector<State>;
|
||||
|
||||
/**
|
||||
* Infers the type of the state produced by the given function.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ local subscribe = require(script.subscribe)
|
|||
local types = require(script.types)
|
||||
|
||||
export type Atom<State> = types.Atom<State>
|
||||
export type Molecule<State> = types.Selector<State>
|
||||
export type Selector<State> = types.Selector<State>
|
||||
export type Molecule<State> = types.Selector<State>
|
||||
export type SyncPayload = types.SyncPayload
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -9,15 +9,15 @@ local function noop() end
|
|||
cleans up the instance when the item is removed. Returns a cleanup function
|
||||
that unsubscribes all instances.
|
||||
|
||||
@param molecule The atom or molecule to observe.
|
||||
@param callback The atom or selector to observe.
|
||||
@param factory The function that tracks the lifecycle of each item.
|
||||
@return A function that unsubscribes all instances.
|
||||
]=]
|
||||
local function observe<K, V>(molecule: Selector<{ [K]: V }>, factory: (value: V, key: K) -> (() -> ())?): () -> ()
|
||||
local function observe<K, V>(callback: Selector<{ [K]: V }>, factory: (value: V, key: K) -> (() -> ())?): () -> ()
|
||||
local connections: { [K]: () -> () } = {}
|
||||
|
||||
local unsubscribe = effect(function()
|
||||
local state = molecule()
|
||||
local state = callback()
|
||||
|
||||
for key, disconnect in next, connections do
|
||||
if state[key] == nil then
|
||||
|
|
|
|||
|
|
@ -100,8 +100,8 @@ end
|
|||
Returns the result of the function without subscribing to changes. If a
|
||||
non-function value is provided, it is returned as is.
|
||||
|
||||
@param molecule The atom or molecule to get the state of.
|
||||
@param args Arguments to pass to the molecule.
|
||||
@param callback The atom or selector to get the state of.
|
||||
@param args Arguments to pass to the function.
|
||||
@return The current state.
|
||||
]=]
|
||||
local function peek<T, U...>(callback: ((U...) -> T) | T, ...: U...): T
|
||||
|
|
@ -128,12 +128,12 @@ end
|
|||
Captures all atoms that are read during the function call and returns them
|
||||
along with the result of the function. Useful for tracking dependencies.
|
||||
|
||||
@param molecule The function to run.
|
||||
@param callback The function to run.
|
||||
@return A tuple containing the captured atoms and the result of the function.
|
||||
]=]
|
||||
local function capture<T>(molecule: () -> T): (Set<Atom<any>>, T)
|
||||
if listeners[molecule] then
|
||||
return { [molecule] = true }, peek(molecule)
|
||||
local function capture<T>(callback: () -> T): (Set<Atom<any>>, T)
|
||||
if listeners[callback] then
|
||||
return { [callback] = true }, peek(callback)
|
||||
end
|
||||
|
||||
local dependencies: Set<Atom<any>> = {}
|
||||
|
|
@ -141,7 +141,7 @@ local function capture<T>(molecule: () -> T): (Set<Atom<any>>, T)
|
|||
capturing.index += 1
|
||||
capturing.stack[capturing.index] = dependencies
|
||||
|
||||
local result = try(molecule, function()
|
||||
local result = try(callback, function()
|
||||
capturing.stack[capturing.index] = nil
|
||||
capturing.index -= 1
|
||||
end)
|
||||
|
|
|
|||
|
|
@ -3,39 +3,39 @@ local types = require(script.Parent.types)
|
|||
type Selector<T> = types.Selector<T>
|
||||
|
||||
--[=[
|
||||
Subscribes to changes in the given atom or molecule. The callback is
|
||||
Subscribes to changes in the given atom or selector. The callback is
|
||||
called with the current state and the previous state immediately after a
|
||||
change occurs.
|
||||
|
||||
@param molecule The atom or molecule to subscribe to.
|
||||
@param callback The function to call when the state changes.
|
||||
@param callback The atom or selector to subscribe to.
|
||||
@param listener The function to call when the state changes.
|
||||
@return A function that unsubscribes the callback.
|
||||
]=]
|
||||
local function subscribe<T>(molecule: Selector<T>, callback: (state: T, prev: T) -> ()): () -> ()
|
||||
local dependencies, state = store.capture(molecule)
|
||||
local function subscribe<T>(callback: Selector<T>, listener: (state: T, prev: T) -> ()): () -> ()
|
||||
local dependencies, state = store.capture(callback)
|
||||
local disconnected = false
|
||||
|
||||
local function listener()
|
||||
local function handler()
|
||||
local prevState = state
|
||||
|
||||
store.disconnect(dependencies, listener)
|
||||
dependencies, state = store.capture(molecule)
|
||||
store.disconnect(dependencies, handler)
|
||||
dependencies, state = store.capture(callback)
|
||||
|
||||
if not disconnected then
|
||||
store.connect(dependencies, listener)
|
||||
store.connect(dependencies, handler)
|
||||
end
|
||||
|
||||
if state ~= prevState then
|
||||
callback(state, prevState)
|
||||
listener(state, prevState)
|
||||
end
|
||||
end
|
||||
|
||||
store.connect(dependencies, listener)
|
||||
store.connect(dependencies, handler)
|
||||
|
||||
return function()
|
||||
if not disconnected then
|
||||
disconnected = true
|
||||
store.disconnect(dependencies, listener)
|
||||
store.disconnect(dependencies, handler)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
10
src/react/src/index.d.ts
vendored
10
src/react/src/index.d.ts
vendored
|
|
@ -1,15 +1,15 @@
|
|||
import { Molecule } from "@rbxts/charm";
|
||||
import { Selector } from "@rbxts/charm";
|
||||
|
||||
/**
|
||||
* A hook that subscribes to changes in the given atom or molecule. The
|
||||
* A hook that subscribes to changes in the given atom or selector. The
|
||||
* component is re-rendered whenever the state changes.
|
||||
*
|
||||
* If the `dependencies` array is provided, the subscription to the atom or
|
||||
* molecule is re-created whenever the dependencies change. Otherwise, the
|
||||
* selector is re-created whenever the dependencies change. Otherwise, the
|
||||
* subscription is created once when the component is mounted.
|
||||
*
|
||||
* @param molecule The atom or molecule to subscribe to.
|
||||
* @param callback The atom or selector to subscribe to.
|
||||
* @param dependencies An array of values that the subscription depends on.
|
||||
* @returns The current state.
|
||||
*/
|
||||
export function useAtom<State>(molecule: Molecule<State>, dependencies?: unknown[]): State;
|
||||
export function useAtom<State>(callback: Selector<State>, dependencies?: unknown[]): State;
|
||||
|
|
|
|||
|
|
@ -4,23 +4,23 @@ local React = if script.Parent:FindFirstChild("react")
|
|||
else require(script.Parent.React)
|
||||
|
||||
--[=[
|
||||
A hook that subscribes to changes in the given atom or molecule. The
|
||||
A hook that subscribes to changes in the given atom or selector. The
|
||||
component is re-rendered whenever the state changes.
|
||||
|
||||
If the `dependencies` array is provided, the subscription to the atom or
|
||||
molecule is re-created whenever the dependencies change. Otherwise, the
|
||||
selector is re-created whenever the dependencies change. Otherwise, the
|
||||
subscription is created once when the component is mounted.
|
||||
|
||||
@param molecule The atom or molecule to subscribe to.
|
||||
@param callback The atom or selector to subscribe to.
|
||||
@param dependencies An array of values that the subscription depends on.
|
||||
@return The current state.
|
||||
]=]
|
||||
local function useAtom<State>(molecule: Charm.Molecule<State>, dependencies: { any }?): State
|
||||
local state, setState = React.useState(molecule)
|
||||
local function useAtom<State>(callback: Charm.Selector<State>, dependencies: { any }?): State
|
||||
local state, setState = React.useState(callback)
|
||||
|
||||
React.useEffect(function()
|
||||
setState(molecule())
|
||||
return Charm.subscribe(molecule, setState)
|
||||
setState(callback())
|
||||
return Charm.subscribe(callback, setState)
|
||||
end, dependencies or {})
|
||||
|
||||
return state
|
||||
|
|
|
|||
6
src/vide/src/index.d.ts
vendored
6
src/vide/src/index.d.ts
vendored
|
|
@ -1,9 +1,9 @@
|
|||
import { Molecule } from "@rbxts/charm";
|
||||
import { Selector } from "@rbxts/charm";
|
||||
|
||||
/**
|
||||
* Subscribes to the state of an atom and returns a Vide source.
|
||||
*
|
||||
* @param molecule The atom or molecule to subscribe to.
|
||||
* @param callback The atom or selector to subscribe to.
|
||||
* @returns The reactive source.
|
||||
*/
|
||||
export function useAtom<T>(atom: Molecule<T>): () => T;
|
||||
export function useAtom<T>(callback: Selector<T>): () => T;
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@ local Vide = if script.Parent:FindFirstChild("vide")
|
|||
--[=[
|
||||
Subscribes to the state of an atom and returns a Vide source.
|
||||
|
||||
@param molecule The atom or molecule to subscribe to.
|
||||
@param callback The atom or selector to subscribe to.
|
||||
@return The reactive source.
|
||||
]=]
|
||||
local function useAtom<State>(molecule: () -> State): State
|
||||
local state = Vide.source(molecule())
|
||||
local unsubscribe = Charm.subscribe(molecule, function(value)
|
||||
local function useAtom<State>(callback: () -> State): State
|
||||
local state = Vide.source(callback())
|
||||
local unsubscribe = Charm.subscribe(callback, function(value)
|
||||
task.spawn(state, value)
|
||||
end)
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ return function()
|
|||
expect(hook.result).to.equal(1)
|
||||
end)
|
||||
|
||||
it("accepts a molecule", function()
|
||||
it("accepts a selector", function()
|
||||
local state = atom(0)
|
||||
local hook = renderHook(function()
|
||||
return useAtom(function()
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ return function()
|
|||
cleanup()
|
||||
end)
|
||||
|
||||
it("accepts a molecule", function()
|
||||
it("accepts a selector", function()
|
||||
local state = atom(0)
|
||||
local source
|
||||
local cleanup = root(function()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue