Text.js
The complete source of src/Text.js, exactly as it ships, in reading order. Every line is present; the file is split at its own section banners.
Text.js - the Text type (a native string) and its functions
// ============================================================================
// Text.js - the Text type (a native string) and its functions
// ============================================================================
//
// Text is a native string TYPE (Reactive.Type + Reactive.Native), and the type name
// doubles as its namespace: functions like Text.Equal hang directly off it (a type
// acting as a pseudo-module). This file adds the type-specific EQUALITY test the
// editor needs; the rest of the Text surface (Text.Select, ...) is framework.
//
// Why type-specific equality
// ---------------------------------------------------------------------------
// There is deliberately NO generic `equal(a, b)` that works over any type. The
// framework is not in a position to carry one yet (an any-type reactive compare
// needs a settled notion of equality per type), so equality is spelled out PER
// TYPE, at the type it belongs to:
//
// Text.Equal(a, b) two text values -> reactive boolean
// Maths.Integer.Equal(a, b) two integers (Maths.js) -> reactive boolean
// ... one per comparable type, added when first needed
//
// Each returns a reactive boolean that stays true exactly while its two operands are
// equal - the input to a selection highlight, a conditional, etc. This replaces the
// generic Logic.Equal the editor used to lean on.
//
// STUB: the reactive comparison is a framework derivation (a boolean node tracking
// its operands); the body is not written here. The consumer (Button.Select.Option)
// is authored against this surface now.
// ----------------------------------------------------------------------------
Reactive.Type("Text", () => {
// This is a native type.
Reactive.Native( (text) => {
// Check that the text is a string
if( typeof text !== "string" ) throw new Error("Text must be a String");
return text;
})
// Equal - a reactive boolean that is true while text `a` equals text `b`. Both may
// be reactive nodes; the result re-derives when either changes, and inherits their
// locks/errors (via Reactive.Value inside the Calculate). The result is a native
// boolean node, which is what Reactive.If coerces and what an attribute value renders;
// it is NOT a reified Boolean field type (booleans as DATA are the Logic.Maybe union).
Reactive.Function("Equal", () => {
const a = Reactive.Argument(Text);
const b = Reactive.Argument(Text);
return Reactive.Calculate(() => {
return Reactive.Value(a) === Reactive.Value(b);
});
});
});
// Text operations as an OVERRIDABLE INTERFACE (same pattern as Maths arithmetic, doc 14 sec 8):
// Text.Concat dispatches to the bound implementation; the host default concatenates via
// Reactive.Calculate, and a Mode can bind a codegen implementation that emits instead.
Reactive.Interface("Text", () => {
Reactive.Function("Concat", () => {
Reactive.Argument(Text);
Reactive.Argument(Text);
Reactive.Returns(Text);
});
});
Reactive.Module("Text", () => {
Reactive.Module("Host", () => {
Reactive.Function("Concat", () => {
const a = Reactive.Argument(Text);
const b = Reactive.Argument(Text);
return Reactive.Calculate(() => Reactive.Value(a) + Reactive.Value(b));
});
});
});
Reactive.With(Text, Text.Host);