-
-
Save foxdonut/56eb81e9a1e155c652fe0be287d44fd6 to your computer and use it in GitHub Desktop.
Meiosis setup with React and Mergerino TS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import ReactDOM from "react-dom"; | |
import flyd from "flyd"; | |
import merge from "mergerino"; | |
import meiosis, { | |
Local, | |
MergerinoPatch, | |
MergerinoApp, | |
LocalPatch, | |
ActionConstructor | |
} from "../../source/dist"; | |
type Patch = MergerinoPatch<State>; | |
type TemperaturePatch = MergerinoPatch<Temperature>; | |
type TemperatureLocal = Local<State, Patch, Temperature, TemperaturePatch>; | |
type TemperatureUnits = "C" | "F"; | |
interface Temperature { | |
label: string; | |
value: number; | |
units: TemperatureUnits; | |
} | |
interface TemperatureActions<P1, P2> { | |
increment: (local: LocalPatch<P1, P2>, amount: number) => void; | |
changeUnits: (local: LocalPatch<P1, P2>) => void; | |
} | |
interface TemperatureComponent<P1, P2> { | |
Initial: (label: string) => Temperature; | |
Actions: ActionConstructor<Temperature, P1, TemperatureActions<P1, P2>>; | |
} | |
interface State { | |
temperature: { | |
air: Temperature; | |
water: Temperature; | |
}; | |
} | |
interface Attrs { | |
state: State; | |
actions: Actions; | |
} | |
const nest = meiosis.mergerino.nest; | |
const convert = (value: number, to: TemperatureUnits): number => { | |
return Math.round(to === "C" ? ((value - 32) / 9) * 5 : (value * 9) / 5 + 32); | |
}; | |
const InitialTemperature = (label: string): Temperature => ({ | |
label, | |
value: 22, | |
units: "C" | |
}); | |
interface Actions { | |
temperature: TemperatureActions<Patch, TemperaturePatch>; | |
} | |
interface TemperatureAttrs extends Attrs { | |
local: TemperatureLocal; | |
} | |
const temperature: TemperatureComponent<Patch, TemperaturePatch> = { | |
Initial: InitialTemperature, | |
Actions: update => ({ | |
increment: (local, amount) => { | |
update(local.patch({ value: x => x + amount })); | |
}, | |
changeUnits: local => { | |
update( | |
local.patch(state => { | |
const value = state.value; | |
const newUnits = state.units === "C" ? "F" : "C"; | |
const newValue = convert(value, newUnits); | |
return { ...state, value: newValue, units: newUnits }; | |
}) | |
); | |
} | |
}) | |
}; | |
const TemperatureElement: (attrs: TemperatureAttrs) => JSX.Element = ({ | |
state, | |
local, | |
actions | |
}) => ( | |
<div> | |
{local.get(state).label} Temperature: | |
{local.get(state).value}°{local.get(state).units} | |
<div> | |
<button onClick={() => actions.temperature.increment(local, 1)}>Increment</button> | |
<button onClick={() => actions.temperature.increment(local, -1)}>Decrement</button> | |
</div> | |
<div> | |
<button onClick={() => actions.temperature.changeUnits(local)}>Change Units</button> | |
</div> | |
</div> | |
); | |
const app: MergerinoApp<State, Actions> = { | |
initial: { | |
temperature: { | |
air: temperature.Initial("Air"), | |
water: temperature.Initial("Water") | |
} | |
}, | |
Actions: update => ({ | |
temperature: temperature.Actions(update) | |
}) | |
}; | |
const Root: (attrs: Attrs) => JSX.Element = ({ state, actions }) => ( | |
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr" }}> | |
<div> | |
<TemperatureElement | |
state={state} | |
local={nest(["temperature", "air"]) as TemperatureLocal} | |
actions={actions} | |
/> | |
<TemperatureElement | |
state={state} | |
local={nest(["temperature", "water"]) as TemperatureLocal} | |
actions={actions} | |
/> | |
</div> | |
<pre style={{ margin: "0" }}>{JSON.stringify(state, null, 4)}</pre> | |
</div> | |
); | |
const stream = { | |
stream: (value?: any) => flyd.stream(value), | |
scan: (acc: any, init: any, stream: any) => flyd.scan(acc, init, stream) | |
}; | |
const { states, update, actions } = meiosis.mergerino.setup<State, Actions>({ | |
stream, | |
merge, | |
app | |
}); | |
const App = meiosis.react.setup<State, MergerinoPatch<State>, Actions>({ React, Root }); | |
export const reactMergerino = (): void => { | |
const element = document.getElementById("reactMergerino"); | |
ReactDOM.render(React.createElement(App, { states, update, actions }), element); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment