Using React and XState.
// A vertically sliced "MVC-widget"
// VIEW:
export default function Users() {
export const make = Effect.struct({ | |
ref: SubscriptionRef.make(0), | |
}); | |
export interface Counter extends Effect.Success<typeof make> {} | |
export const Counter = Tag<Counter>(); | |
export const CounterLive = Layer.fromEffect(Counter)(make); | |
export const increment = Effect.serviceWithEffect(Counter, ({ ref }) => | |
ref.update((count) => count + 1) |
// WIP, just finding all the boxes and glue, implementation is woefully incomplete | |
import type { DOMAttributes } from "react"; | |
import { assign, createMachine, interpret } from "@xstate/fsm"; | |
import invariant from "tiny-invariant"; | |
type CustomElement<T> = Partial< | |
T & DOMAttributes<T> & { children: any; class: string } | |
>; |
export class Cache<T extends object, K> { | |
items = new WeakMap<T, K>() | |
get<P extends T>(item: P, cb: (item: P) => K) { | |
if (!this.items.has(item)) { | |
this.items.set(item, cb(item)) | |
} | |
return this.items.get(item)! | |
} |
/* eslint-disable no-param-reassign */ | |
import { | |
getMembers, types | |
} from 'mobx-state-tree' | |
import { | |
createMachine | |
} from 'xstate' | |
import { interpret } from 'xstate/lib/interpreter' | |
// Pieced together from: |
A zone is an isolated portion of an @xstate/test model. A zone defines the events it uses, the event that causes it to be entered and the states within the zone
The zones entryEvent is added as an event handler to the zones parent initial state. If this is a root zone passed to buildTestModel
this is the root state, if it's a sub zone (a state pointing at a zone), that is the initial state of the zone that state is contained in
Each state in a zone must contain a test property that validates that the state has been entered. At least one of the states requires it to be marked as the initial state of the zone with initial: true
An event handler in a zone state can only refer to events defined inside of the zone
type State = string; | |
type Message = string; | |
type StatesList = readonly State[]; | |
type MessagesConfig = Record<State, Record<Message, State>>; | |
type OneOf<S extends StatesList> = S[number]; | |
type Send< | |
SBConfig extends StateBuilderConfig<StatesList, State, State>, |
Thoughts on standardizing REST with machines
import { entity } from 'durable-functions'; | |
import { State, interpret } from 'xstate'; | |
import { getMachine } from './machines'; | |
import { updateEntity, waitForMachineToResolve } from '../Shared/utilities'; | |
export default entity(async (context) => { | |
let machine = getMachine(context); | |
switch (context.df.operationName) { | |
case 'send': |
/** | |
* This is a small library I wrote when I was doing R&D work and needed a way to communicate | |
* between an iFrame on the same domain and its parent tab. The existing browser API kinda sucked | |
* and had a lot of issues, and it wasn't particularly enjoyable to use. So I made this small library to solve that. | |
* | |
* The library allows you to communicate using *channels*, which are just streams of events with a given name. | |
* You can subscribe to events of a particular type. Each event type has its own event queue, and each subscriber | |
* must subscribe to a particular event type. This keeps things simple and fast. | |
* | |
* Events are buffered and sent asychronously. There are two ways to send events: firing and blocking. |