Sprites.Reactive

The reactive core. Values hold state, calculations read and derive, and the structure grows and shrinks with the data. Context injects a value for a subtree, read by any descendant.

Async work lives in drivers, outside the synchronous core. A value can be pending, with no value yet; reading a pending value under a Sprites.Ui.Loading shows a spinner. Sprites.Animate holds the time based drivers.

Sprites.Reactive

Sprites.Reactive.Context

Sprites.Reactive.Assert Void

Sprites.Reactive.Assert(condition)

A failsafe inside a lens. Compose the condition from ordinary operations, the same as any value, and pass it. If it reads false, the whole transaction throws and rolls back silently, changing nothing the forward direction sees, like an assertion. A condition that is not available yet, still pending on async work, is skipped rather than failed, so an assert never trips on a value on its way. Allowed only in the reverse direction, inside a lens or a handler. Because a settle is one atomic transaction, a failed assert leaves no half written state: every value it would have set stays as it was.

InputTypeDescription
conditionBoolean or Sprites.Reactive.ValueThe condition to hold. A reactive boolean, usually built with Logic and Maths. Read false, it fails the transaction; pending, it is skipped.

Returns nothing.

const items = Sprites.Reactive.Value([]);
const add = Sprites.Reactive.Reverse(() => {
  const count = Sprites.Array.Length(items);
  // stop at three: a fourth add fails the check, so the whole settle rolls back.
  const under = Sprites.Logic.Less(count, 3);
  Sprites.Reactive.Assert(under);
  const position = Sprites.Maths.Add(count, 1);
  const label = Sprites.Text.Concat('Item ', position);
  const grown = Sprites.Array.Append(items, label);
  Sprites.Reactive.Set(items, grown);
});
Sprites.Ui.Button.Act(add, 'Add (max 3)');
Sprites.Reactive.Each(items, (item) => {
  Sprites.Ui.Dom.Tag('p', item);
});
Add up to three; the fourth press fails the check and silently rolls back, so nothing changes.

Sprites.Reactive.Calculate Sprites.Reactive.Value

Sprites.Reactive.Calculate(fn)

Read values and return a value. Going forward the result is a read-only reactive value, recomputed when a value it read changes. Inside a lens it builds the same live value, which a Set commits when it is ready, or when it lands if an async part is still on the way, so a calculation function reads the same in both directions.

InputTypeDescription
fnFunctionReads values with Calculate.Get and plain work, returning the computed result.

Returns a read-only Sprites.Reactive.Value holding the result, recomputed when a value it read changes.

const w = Sprites.Reactive.Value(4);
const h = Sprites.Reactive.Value(3);
const area = Sprites.Reactive.Calculate(() => {
  const width = Sprites.Reactive.Calculate.Get(w);
  const height = Sprites.Reactive.Calculate.Get(h);
  return width * height;
});
Sprites.Ui.Input.Number(w);
Sprites.Ui.Input.Number(h);
Sprites.Ui.Dom.Text('Area: ', area);
Change either number and the area recomputes.

Sprites.Reactive.Calculate.Get Any

Sprites.Reactive.Calculate.Get(value)

Read a value inside a Calculate callback. A constant is returned as is; a reactive value gives its current value and subscribes, so the calculation recomputes when it changes. The reader is installed only while the callback runs and lifts after, so it reads only there. To read outside a Calculate, wrap the read in one, or reach for a library function that derives the value for you.

InputTypeDescription
valueAny or Sprites.Reactive.ValueA constant, returned as is, or a reactive value to read and follow.

Returns the current value.

const price = Sprites.Reactive.Value(5);
const label = Sprites.Reactive.Calculate(() => {
  const now = Sprites.Reactive.Calculate.Get(price);
  return 'Price: ' + now;
});
Sprites.Ui.Input.Number(price);
Sprites.Ui.Dom.Text(label);
Calculate.Get reads the price inside a calculation, so the label follows it.

Sprites.Reactive.Binding Sprites.Reactive.Value

Sprites.Reactive.Binding(source, reverse)

A two-way view composed from a get side and a set side: it takes reading and tracking from the first value and writing from the second. Binding(source) tracks the source going forward, so it follows every change, and a set to it holds until the source changes again. Binding(source, reverse) adds the set side: a set to the binding writes the reverse, whose own onChange runs. The reverse is a Reverse; a plain callback is shorthand for an anonymous one, the way an inline arrow is an anonymous function. The get side never constrains whether the binding is writable; the locks flow through the set side, so a read-only source paired with a writable reverse still writes. This is the controlled-input and derived-field shape. To make fresh state that does not track, use Value.

InputTypeDescription
sourceSprites.Reactive.ValueThe forward value to track. The binding follows it going forward.
reverseSprites.Reactive.Reverse or FunctionOptional. The reverse half, run on set to write other values. A callback is shorthand for a Reverse.

Returns a reactive Sprites.Reactive.Value that tracks the source and, with a reverse, writes back on set.

const size = Sprites.Reactive.Value(16);
const input = Sprites.Reactive.Binding(size, (v) => {
  const held = Sprites.Maths.Clamp(v, 1, 256);
  Sprites.Reactive.Set(size, held);
});
Sprites.Ui.Input.Number(input);
Sprites.Ui.Dom.Text(' size = ', size);
The input tracks size and clamps on the way back: type 999 and it settles at 256.

Sprites.Reactive.Driver Object

Sprites.Reactive.Driver(name, resultBinding, request, make)

Ask a driver for async work. The driver runs the work and writes the result value, which opens the next update. The first request for a name builds the driver with make; the request lives until its scope ends. Drivers keep the core synchronous, so no calculation or handler waits.

The request may be a reactive value, so the driver follows it: when the request changes the driver reruns with the new value, cancelling any stale work, and writes the same result value. A read whose query is a reactive object stays live this way, with no rebuild. A plain request dispatches once.

A request emitted inside a handler freezes the values that handler read until the driver reports, and marks the result pending. A control that writes a frozen value disables on its own, and a control that reads a pending value shows a spinner under a Loading, so the interface locks the right parts while the work runs.

InputTypeDescription
nameStringThe driver's name. The same name ties every call to one driver.
resultBindingSprites.Reactive.ValueThe value the driver writes as the work runs and completes.
requestAny or Sprites.Reactive.ValueThis request's parameters. A reactive value reruns the driver whenever it changes.
makeFunctionBuilds the driver the first time the name is seen, returning onRequestAdd and onDriverDestroy.

Returns the request control, with update and destroy.

const status = Sprites.Reactive.Pending('');
const go = Sprites.Reactive.Value(false);
const delay = () => {
  return {
    onRequestAdd: (binding, params) => {
      const id = setTimeout(() => {
        Sprites.Reactive.batch(() => {
          Sprites.Reactive.Set(binding, params.text);
        });
      }, params.ms);
      return { onRequestDestroy: () => { clearTimeout(id); } };
    },
  };
};
Sprites.Ui.Button.SetValue(go, true, 'Start');
Sprites.Ui.Loading(() => {
  Sprites.Ui.Dom.Text(' status = ', status);
});
Sprites.Reactive.If(go, () => {
  Sprites.Reactive.Driver('demo.delay', status, { text: 'ready', ms: 1500 }, delay);
});
Press Start; the driver writes the value after a delay, and the spinner clears.

Sprites.Reactive.Each Void

Sprites.Reactive.Each(list, build)

Repeat the content for each element of a list.

InputTypeDescription
listArray or Sprites.Reactive.ValueThe list to walk. A reactive list rebuilds as it changes, and each item is a two-way field.
buildFunctionCalled as build(item, index) to build the content for each element.

Returns nothing.

const items = Sprites.Reactive.Value(['Red', 'Green']);
Sprites.Ui.Button.Push(items, 'Blue', 'Add colour');
Sprites.Reactive.Each(items, (item) => {
  Sprites.Ui.Dom.Tag('p', item);
});
Add a colour and a new paragraph appears.

Sprites.Reactive.Field Sprites.Reactive.Value

Sprites.Reactive.Field(source, key)

A two way lens into one field of a container value: read, it is source[key]; set, it writes the container back with that field replaced and Sets source, so the write cascades up the container's own lens chain to any depth. It composes only reactive primitives, so it lives in the core with them; Sprites.Object.Field is the object namespace's entry to it, and Each and Repeat hand each row one so an edit writes back to the list.

InputTypeDescription
sourceSprites.Reactive.ValueA reactive value holding the container, an array or an object.
keyNumber or StringThe index or property name of the field to view.

Returns a two way value of that field.

const point = Sprites.Reactive.Value({ x: 3, y: 4 });
const x = Sprites.Reactive.Field(point, 'x');
const y = Sprites.Reactive.Field(point, 'y');
Sprites.Ui.Layout.Row(() => {
  Sprites.Ui.Input.Number(x, 0, 99);
  Sprites.Ui.Input.Number(y, 0, 99);
});
Sprites.Ui.Dom.Text('point = ', x, ', ', y);
Each input is a field of the one point; editing either writes back through the field.

Sprites.Reactive.Emit Void

Sprites.Reactive.Emit(name, value)

Emit one value to the nearest sink of that name, opened by Sprites.Reactive.Gather. Call it anywhere inside the build, on its own or within an If, Each or Repeat, and the value joins the gathered list in tree order. For the common unnamed case use Sprites.Array.Emit.

InputTypeDescription
nameStringThe name of the enclosing Gather to emit into.
valueAny or Sprites.Reactive.ValueThe value to add. A pending value pends the whole list.

Returns nothing.

const on = Sprites.Reactive.Value(true);
const items = Sprites.Reactive.Gather('demo', () => {
  Sprites.Reactive.Emit('demo', 'always');
  Sprites.Reactive.If(on, () => {
    Sprites.Reactive.Emit('demo', 'sometimes');
  });
});
Sprites.Ui.Input.Checkbox(on);
const joined = Sprites.Text.Join(items, ', ');
Sprites.Ui.Dom.Text(' items = ', joined);
Uncheck the box and the conditional emission leaves the list.

Sprites.Reactive.Gather Sprites.Reactive.Value

Sprites.Reactive.Gather(name, build)

Open a named sink, run build, and collect what it emits into one reactive list, in tree order. It is the dual of Context.Set: a value set high is read deep; a value emitted deep is read high. Any reactive logic may emit, with an If or an Each among it, and it works the same in a lens. It runs the DOM too, where each element gathers its children. For the common unnamed case use Sprites.Array.Gather.

InputTypeDescription
nameStringThe sink's name, so several independent gathers may run at once. Emit targets the nearest of that name.
buildFunctionBuilds the emissions with Sprites.Reactive.Emit.

Returns a read-only Sprites.Reactive.Value holding the gathered list.

const items = Sprites.Reactive.Gather('demo', () => {
  Sprites.Reactive.Emit('demo', 'one');
  Sprites.Reactive.Emit('demo', 'two');
});
const joined = Sprites.Text.Join(items, ', ');
Sprites.Ui.Dom.Text(joined);
Two emitted values become a gathered list.

Sprites.Reactive.If Void

Sprites.Reactive.If(cond, build)

Show the content while a value is true.

InputTypeDescription
condBoolean or Sprites.Reactive.ValueThe condition. A reactive condition shows and hides the content as it changes.
buildFunctionBuilds the content shown while the condition is true.

Returns nothing.

const open = Sprites.Reactive.Value(true);
Sprites.Ui.Input.Checkbox(open);
Sprites.Reactive.If(open, () => {
  Sprites.Ui.Dom.Tag('p', 'Now you see me');
});
Uncheck the box to hide the paragraph.

Sprites.Reactive.Else Void

Sprites.Reactive.Else(cond, build)

The mirror of If: show the content while a value is false, so a part shown only while something is absent needs no separate negation.

InputTypeDescription
condBoolean or Sprites.Reactive.ValueThe condition. The content shows while it is false.
buildFunctionBuilds the content shown while the condition is false.

Returns nothing.

const full = Sprites.Reactive.Value(false);
Sprites.Ui.Input.Checkbox(full);
Sprites.Reactive.Else(full, () => {
  Sprites.Ui.Dom.Tag('p', 'There is still room.');
});
Check the box and the message hides.

Sprites.Reactive.Map Sprites.Reactive.Value

Sprites.Reactive.Map(list, build)

Map a reactive list through a reactive build, one element at a time, and collect the built values into one reactive list. It is a Gather whose body is an Each that emits: build takes a reactive value viewing the element, and its index, and returns a reactive value; the collector reads every built value into one list. The result follows the list, growing and shrinking with it, and each built value follows its inputs.

InputTypeDescription
listArray or Sprites.Reactive.ValueThe list to map. A reactive list rebuilds as it changes, and each element is a two-way field.
buildFunctionCalled as build(item, index), returning a reactive value for each element.

Returns a read-only Sprites.Reactive.Value holding the list of built values, following the source list.

const nums = Sprites.Reactive.Value([1, 2, 3]);
const doubled = Sprites.Reactive.Map(nums, (n) => {
  return Sprites.Maths.Multiply(n, 2);
});
Sprites.Ui.Button.Push(nums, 4, 'Add 4');
const joined = Sprites.Text.Join(doubled, ', ');
Sprites.Ui.Dom.Text('doubled = ', joined);
Each number is doubled; add one and the mapped list grows with it.

Sprites.Reactive.Pending Sprites.Reactive.Value

Sprites.Reactive.Pending(initial)

A value that is loading. It holds a realistic stand-in of the right shape, an empty array, a blank string, zero or false, so a reader can use it while it waits. It is pending, so reading it under a Sprites.Ui.Loading shows the spinner and a calculation over it stays pending too. The first Set gives it the real value and clears the flag. It stays writable, so a driver may fill it.

InputTypeDescription
initialAnyThe stand-in value of the right shape, used while the value loads.

Returns a pending Sprites.Reactive.Value, unreadable until set.

const result = Sprites.Reactive.Pending('');
const started = Sprites.Reactive.Value(false);
Sprites.Ui.Button.SetValue(started, true, 'Load');
Sprites.Ui.Loading(() => {
  Sprites.Ui.Dom.Text(' result = ', result);
});
Sprites.Reactive.If(started, () => {
  Sprites.Animate.SetAfter(result, 'done', 1500);
});
The value shows a spinner until SetAfter fills it.

Sprites.Reactive.Readable Sprites.Reactive.Value

Sprites.Reactive.Readable(value)

Readability as a reactive value: true while the value holds a real value, false while it is still pending on async work. It reads the pending flag as data, not as a read that waits, so it never turns pending itself or raises a loading veil, yet it subscribes to the value, so it recomputes when the pending flag flips. A constant is always readable. Compose it with Logic to show a part only once its values have arrived, without the read itself waiting on them.

InputTypeDescription
valueAny or Sprites.Reactive.ValueThe value to watch. Its pending flag drives the result; a constant reads always readable.

Returns a read-only Sprites.Reactive.Value holding true while the value is readable, false while pending.

const result = Sprites.Reactive.Pending('');
const started = Sprites.Reactive.Value(false);
const ready = Sprites.Reactive.Readable(result);
Sprites.Ui.Button.SetValue(started, true, 'Load');
Sprites.Ui.Dom.Text(' ready = ', ready);
Sprites.Reactive.If(started, () => {
  Sprites.Animate.SetAfter(result, 'done', 1500);
});
ready reads false while the value loads, then true once SetAfter fills it, without waiting itself.

Sprites.Reactive.Repeat Void

Sprites.Reactive.Repeat(count, build)

Repeat the content count times, calling build with each index. count may be a constant or a reactive value, so the run grows and shrinks as it changes.

InputTypeDescription
countNumber or Sprites.Reactive.ValueHow many times to repeat. A reactive count grows and shrinks the run.
buildFunctionCalled as build(index) for each repetition.

Returns nothing.

const count = Sprites.Reactive.Value(3);
Sprites.Ui.Input.Number(count, 0, 6);
Sprites.Reactive.Repeat(count, (i) => {
  Sprites.Ui.Dom.Tag('button', 'Item ' + (i + 1));
});
Change the count and the run of buttons follows.

Sprites.Reactive.Set Any

Sprites.Reactive.Set(value, next)

Write a value, in an event handler or a lens. A lens set runs its onChange. Takes a reactive value or a constant, never a function; it throws on a function. Give it a live value, such as a calculation, and it commits when that value is ready, or when it lands if an async part is still on the way.

A set does not change the value on the spot. The whole reverse settle is one transaction: every set buffers into a working store, and the store commits all at once when the settle finishes, so the final state and every value in between change together, or none change. While the settle waits on async work, every value it will write is locked and holds its old value. If a lens fails part way, the whole transaction rolls back and nothing lands. See Reverse.

InputTypeDescription
valueSprites.Reactive.ValueThe value to write. Allowed only in a handler or a lens.
nextAny or Sprites.Reactive.ValueThe new value: a reactive value or a constant, never a function.

Returns the value written.

const n = Sprites.Reactive.Value(0);
Sprites.Ui.Button.Increment(n, 'Add one');
Sprites.Ui.Dom.Text('n = ', n);
Each click sets n to one more than before.

Sprites.Reactive.Reverse Sprites.Reactive.Value

Sprites.Reactive.Reverse(onChange)

A write-only value: it can be set but not read. Reverse makes a reverse lens with no forward value of its own, for an action a set triggers, or as the reverse half of a Binding. Setting it runs onChange, which composes the new value from the current values and Sets it on. Reading it throws, since it holds no forward value; combine it with a forward value through Binding when a view must read as well as write. A button command is the everyday form: the click pokes it, and its onChange writes.

InputTypeDescription
onChangeFunctionRun on set. It composes the new values and Sets them on; it never reads or branches.

Returns a write-only Sprites.Reactive.Value: settable, not readable.

const total = Sprites.Reactive.Value(0);
const step = Sprites.Reactive.Value(5);
const add = Sprites.Reactive.Reverse(() => {
  const next = Sprites.Maths.Add(total, step);
  Sprites.Reactive.Set(total, next);
});
Sprites.Ui.Button.Act(add, 'Add step');
Sprites.Ui.Dom.Text(' total = ', total);
The command has no value of its own; the click runs its reverse, which adds the step to the total.

Sprites.Reactive.Value Sprites.Reactive.Value

Sprites.Reactive.Value(source)

New state, seeded once from the current value of what you pass. A constant makes state holding that constant. A reactive source is captured: the new value takes the source's value now and detaches, so a later change to the source does not reach it, and writing the new value does not touch the source. This is the modal-edit draft, seeded as an editor opens. If the source is pending, the copy carries the pending and takes its value once, when it resolves. Value never tracks and never writes back. To follow a source live, use Binding; to read a value in a calculation, use Calculate.Get.

InputTypeDescription
sourceAny or Sprites.Reactive.ValueA constant to hold as state, or a reactive value to capture its current value from.

Returns a new writable Sprites.Reactive.Value, independent of any source.

const count = Sprites.Reactive.Value(2);
Sprites.Ui.Input.Number(count);
Sprites.Ui.Dom.Text('Count: ', count);
The text follows the value as you change it.

Sprites.Reactive.Writable Sprites.Reactive.Value

Sprites.Reactive.Writable(value)

Writability as a reactive value: true while the value can be written now, false while a process holds it locked or it is read-only. It follows the locks, so a control bound to it enables and disables on its own. It is the reactive form of the private writable check, for composing a control's disabled state with Logic instead of a raw function.

InputTypeDescription
valueSprites.Reactive.ValueThe value to watch. Its writability drives the result.

Returns a read-only Sprites.Reactive.Value holding true while the value can be written, false while it is locked or read-only.

const name = Sprites.Reactive.Value('Ada');
const shout = Sprites.Reactive.Calculate(() => {
  const text = Sprites.Reactive.Calculate.Get(name);
  return text.toUpperCase();
});
Sprites.Ui.Input.Text(name);
const nameWritable = Sprites.Reactive.Writable(name);
Sprites.Ui.Dom.Text(' name writable = ', nameWritable);
Sprites.Ui.Dom.Tag('br');
const shoutWritable = Sprites.Reactive.Writable(shout);
Sprites.Ui.Dom.Text(' shout writable = ', shoutWritable);
The plain value is writable; the read-only calculation is not.

Sprites.Reactive.Object Sprites.Reactive.Value

Sprites.Reactive.Object(mixed)

Build a two-way reactive object from a plain object literal at any depth, the one way to construct a reactive object. Each field is a constant or a reactive value, or itself an object or array holding reactive values; the whole reads as one plain object, rebuilt when any reactive part changes, so a free mix of separate values, nested to any depth, reads as one. A field with no reactive value in it is a constant, kept whole by reference. Each leaf reads through Calculate.Get, so the assembled value is a plain snapshot and the live values stay outside it, as its sources.

It is two way: set the whole object and each reactive field is written back from the matching field of the new object, fanning the write out to any depth. The set is strict, so it can only ever move the reactive parts: a set that changes a constant field, that adds or drops a field, or whose value is not a plain object, throws, and the whole transaction rolls back. It needs a plain object; a primitive or an array throws. Use Array for an array, Constant for a fixed leaf, and ReadOnly when the fields are only read.

InputTypeDescription
mixedObjectA plain object literal whose fields, at any depth, are a free mix of constants and reactive values.

Returns a two-way Sprites.Reactive.Value over the assembled nested object.

const left = Sprites.Reactive.Value(12);
const width = Sprites.Reactive.Value(240);
const coords = Sprites.Reactive.Object({ left: left, top: 320, size: { width: width, height: 320 } });
Sprites.Ui.Input.Number(left, 0, 999);
Sprites.Ui.Input.Number(width, 0, 999);
const size = Sprites.Object.Field(coords, 'size');
const nestedWidth = Sprites.Object.Field(size, 'width');
const nestedLeft = Sprites.Object.Field(coords, 'left');
Sprites.Ui.Dom.Text(' left = ', nestedLeft, ', nested width = ', nestedWidth);
Edit either leaf; the assembled nested object follows, read here back through its fields at each level.

Sprites.Reactive.Array Sprites.Reactive.Value

Sprites.Reactive.Array(mixed)

Build a two-way reactive array from a plain array literal at any depth, the array sibling of Object. Each element is descended the same way, a reactive value tracked and written back, a nested object or array rebuilt two-way, anything else a constant kept whole. The whole reads as one plain array, rebuilt when any reactive part changes.

It is two way: set the whole array and each reactive element is written back at its index, while a constant element must arrive unchanged and the length may not change; a set that breaks either rule throws and rolls back. It needs an array; anything else throws. Use Object for an object.

InputTypeDescription
mixedArrayA plain array whose elements, at any depth, are a free mix of constants and reactive values.

Returns a two-way Sprites.Reactive.Value over the assembled array.

const a = Sprites.Reactive.Value(1);
const b = Sprites.Reactive.Value(2);
const row = Sprites.Reactive.Array([a, 50, b]);
Sprites.Ui.Input.Number(a, 0, 99);
Sprites.Ui.Input.Number(b, 0, 99);
const first = Sprites.Object.Field(row, 0);
const last = Sprites.Object.Field(row, 2);
Sprites.Ui.Dom.Text(' row = ', first, ', 50, ', last);
Edit either reactive element; the assembled array follows, its constant middle held at 50.

Sprites.Reactive.ReadOnly Sprites.Reactive.Value

Sprites.Reactive.ReadOnly(mixed)

A read-only view of any value or literal, the read-only twin of Object. A single reactive value reads as a read-only tracking view of it. A mixed object or array literal reads as one read-only object that reads every field through Calculate.Get at any depth, so it tracks its sources, reads as one plain object, nests no live value, but writes to none.

A primitive, or a container with no reactive value in it, is a Constant; an already read-only value is returned as is. It is the light read-only combiner, one Calculate with no write-back machinery, so unlike Object it may be built inside a lens or a handler. Reach for Object when the value must write its fields back, and ReadOnly when they are only read. It never throws on its input.

InputTypeDescription
mixedAnyAny value or literal: a reactive value, an object or array literal mixing constants and reactive values at any depth, or a plain primitive.

Returns a read-only Sprites.Reactive.Value tracking its sources.

const a = Sprites.Reactive.Value(3);
const view = Sprites.Reactive.ReadOnly({ a: a, b: 2 });
Sprites.Ui.Input.Number(a, 0, 99);
const fa = Sprites.Object.Field(view, 'a');
Sprites.Ui.Dom.Text(' view.a = ', fa, ', view.b = 2');
A reactive value and a constant read as one plain object that tracks its source.

Sprites.Reactive.Constant Sprites.Reactive.Value

Sprites.Reactive.Constant(thing)

A read-only value holding a fixed thing. It reads as that thing, and locks like any value, but can never be written: a Set of it throws, and Writable over it, or over a lens that sets it, stays false. Object and Array wrap every constant field in it, so each part of a built value is a reactive value and the write-back path stays uniform: a writable leaf takes the new value, a constant one only confirms it is unchanged.

InputTypeDescription
thingAnyThe fixed value to hold. Read back as is; never written.

Returns a read-only Sprites.Reactive.Value over the fixed thing.

const label = Sprites.Reactive.Constant('read only');
const canWrite = Sprites.Reactive.Writable(label);
Sprites.Ui.Dom.Text(' label = ', label, ', writable = ', canWrite);
The constant reads back as its thing and reports as never writable.

Sprites.Reactive.Context.Get Any

Sprites.Reactive.Context.Get(name, def)

Read the nearest value in scope for a name, or a default when no Set is in scope.

InputTypeDescription
nameStringThe context name to read.
defAnyOptional value returned when the name is not in scope.

Returns the nearest value in scope for the name, or the default.

const theme = Sprites.Reactive.Value('dark');
Sprites.Reactive.Context.Set('theme', theme, () => {
  const t = Sprites.Reactive.Context.Get('theme', 'light');
  Sprites.Ui.Input.Text(t);
  Sprites.Ui.Dom.Text('theme = ', t);
});
Read the nearest value in scope, or a default.

Sprites.Reactive.Context.Set Any

Sprites.Reactive.Context.Set(name, value, build)

Inject a named value for the subtree that build creates, then restore. A nearer Set shadows a wider one of the same name.

InputTypeDescription
nameStringThe context name.
valueAnyThe value to inject for the subtree.
buildFunctionBuilds the subtree that can read the value.

Returns the result of build.

const theme = Sprites.Reactive.Value('dark');
Sprites.Reactive.Context.Set('theme', theme, () => {
  const t = Sprites.Reactive.Context.Get('theme');
  Sprites.Ui.Input.Text(t);
  Sprites.Ui.Dom.Text('theme = ', t);
});
Inject a value for the subtree; a descendant reads and edits it.