La entrada eidos se parte igual que la de soma: `activeEidosDir(dir)` devuelve la AFIRMACION (prop -> ancestro) y publica en el MISMO DirectionContext — un chart eidos-only dentro de un subarbol soma afirmado (o al reves) resuelve el mismo hecho. La cola matematica va a `resolveEidosDir(dir, eidos.prefs)`, con la vista de prefs cacheada por instancia (WeakMap): construirla dentro de una funcion pura llamada por $derived era una alocacion por pasada. createChartRtl consume las dos mitades por su lado: `attr` estampa la afirmacion cruda (ausente hereda del <html> proyectado), `current`/`anchor` resuelven la cola. Corpus: - direction-contract.md §2 pasa del campo obligatorio de 4.1 al mecanismo del morfo (declaracion -> tipo condicional -> estampado; secundarios del mismo morfo; el censo como guard), §7 documenta el contexto compartido y la tabla de entradas partidas, y el checklist §8.3 pide morfo + cable. - docs/decisions.md registra la ratificacion D1-D4 del 2026-08-05 con las cuatro decisiones y su porque. - CONTINUE-direction-runtime.md §11 cierra el handoff: tabla de fases con commits, verificacion final medida, la cola pospuesta por D4 y las trampas nuevas (pathspec SIEMPRE en rama compartida; el detector de huerfanos y la ruta del import; la vista en $derived). check 77 = linea base · morfo+direction suites 131/131 · docs:check 0/566. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>alpha-0.1-dir-prefs
parent
fc84305c22
commit
8d1909b166
@ -1,35 +1,56 @@
|
||||
import { readableActive, type Active } from '$libs/reactive';
|
||||
import { createActiveUixPrefsView } from '$active-uix/prefs';
|
||||
import { DirectionContext } from '$soma/direction';
|
||||
import type { ActivePrefs } from '$prefs';
|
||||
import type { Direction } from '$soma/types';
|
||||
|
||||
/**
|
||||
* The direction chain's eidos entry point — the same two links `activeDir` runs
|
||||
* The direction chain's eidos entry point — the same links `activeDir` runs
|
||||
* for soma, handed the service an eidos-only component actually holds.
|
||||
*
|
||||
* Most of the catalogue resolves direction in a soma provider, so
|
||||
* `activeDir(getter, soma)` covers it. A few components are eidos-only: they
|
||||
* have no provider, no morfo and no `Soma`, only an `ActiveEidos`. Before this
|
||||
* existed the chain was simply not runnable there, and the workaround was to
|
||||
* read the resolved direction off the element — which the contract forbids,
|
||||
* because the DOM `dir` is a projection of the preference, never a source.
|
||||
* `activeDir(getter)` covers it. A few components are eidos-only: they have no
|
||||
* provider, no morfo and no `Soma`, only an `ActiveEidos`. Before this existed
|
||||
* the chain was simply not runnable there, and the workaround was to read the
|
||||
* resolved direction off the element — which the contract forbids, because the
|
||||
* DOM `dir` is a projection of the assertion, never a source.
|
||||
*
|
||||
* `ActiveEidos.prefs` is an `ActivePrefs` (the raw arts service), which has no
|
||||
* `getDir()`; that method lives on the soma-facing view. Adapting the one to
|
||||
* the other is the whole of the difference between the two entry points.
|
||||
*
|
||||
* Returns `Direction | undefined` for the same reason `activeDir` does:
|
||||
* `undefined` means NOBODY asserted a direction, which is not `'ltr'`. The
|
||||
* consumer defaults it once for its own maths and stamps the RAW value, so the
|
||||
* attribute stays absent when nothing was asserted.
|
||||
* Returns the ASSERTION (`prop → ancestor via DirectionContext`) and publishes
|
||||
* it, exactly like `activeDir` — the context is soma's, shared on purpose, so
|
||||
* an eidos-only chart inside an asserted soma subtree (or the reverse)
|
||||
* resolves the same fact. `undefined` means NOBODY asserted, which is not
|
||||
* `'ltr'`: the consumer stamps the RAW value (absent inherits from the
|
||||
* projected page) and resolves its maths through {@link resolveEidosDir}.
|
||||
*
|
||||
* Contract: `docs/canon/direction-contract.md` §1.
|
||||
* Contract: `docs/canon/direction-contract.md` §1 and §7.
|
||||
*/
|
||||
export function activeEidosDir(dir: () => Direction | undefined): Active<Direction | undefined> {
|
||||
const inherited = DirectionContext.getOr(undefined);
|
||||
const asserted = readableActive(() => dir() ?? inherited?.current);
|
||||
DirectionContext.set(asserted);
|
||||
return asserted;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maths tail for eidos-only components: `assertion → prefs → 'ltr'`.
|
||||
* `ActiveEidos.prefs` is an `ActivePrefs` (the raw arts service), which has no
|
||||
* `getDir()` — that method lives on the soma-facing view; adapting the one to
|
||||
* the other is the whole of the difference from soma's `resolveDir`.
|
||||
*/
|
||||
export function activeEidosDir(
|
||||
dir: () => Direction | undefined,
|
||||
const PREFS_VIEWS = new WeakMap<ActivePrefs, ReturnType<typeof createActiveUixPrefsView>>();
|
||||
|
||||
export function resolveEidosDir(
|
||||
dir: Active<Direction | undefined>,
|
||||
prefs: ActivePrefs | undefined
|
||||
): Active<Direction | undefined> {
|
||||
// Built once, not per read: the view allocates closures over the slot.
|
||||
const view = prefs ? createActiveUixPrefsView(prefs) : undefined;
|
||||
return readableActive(() => dir() ?? view?.getDir());
|
||||
): Direction {
|
||||
if (dir.current !== undefined) return dir.current;
|
||||
if (!prefs) return 'ltr';
|
||||
// The view allocates closures over the slot — cached per prefs instance so
|
||||
// a maths tail read inside a $derived does not rebuild it every pass.
|
||||
let view = PREFS_VIEWS.get(prefs);
|
||||
if (!view) {
|
||||
view = createActiveUixPrefsView(prefs);
|
||||
PREFS_VIEWS.set(prefs, view);
|
||||
}
|
||||
return view.getDir() ?? 'ltr';
|
||||
}
|
||||
|
||||
Loading…
Reference in new issue