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);