Skip to content

Tags: tonioloewald/tosijs

Tags

v1.7.9

Toggle v1.7.9's commit message
v1.7.9: take() works in list templates — descriptor is data, memo is …

…per-row

The take descriptor moves out of bindTake's closure onto the binding entry
(DataBinding.take): the closure froze the template's ^. paths forever (the
transform ran on xin['^.…'] = undefined instead of the row's value) and
shared ONE lastInputs memo across every cloned row, so the first row's
update suppressed its siblings' (one row transformed-wrong, the next never
updated). Now row instantiation rewrites take.paths exactly like the entry's
own path — both dispatchers (touchElement, updateRelativeBindings) route
through a shared applyDataBinding in metadata.ts — and the memo rides the
per-element (per-row-cloned) take object itself (no extra WeakMap;
cloneWithBindings already deep-clones entries). Also fixes one descriptor
reused across two elements starving the second.

Regression suite: src/take-list-binding.test.ts (relative-path rows, sibling
independence, late-added rows, descriptor reuse, absolute paths in rows).

Gate: 673/673, tsc clean, lint clean, build 0, Playwright 4/4.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EVU6HWRPnVwqc5XgTSnSv

v1.7.8

Toggle v1.7.8's commit message
v1.7.8: detached part with no replacement returns the cached node ins…

…tead of throwing (tosijs#21)

Root cause of #21 ("this.value stale after interaction on FF/WebKit"): 1.7.7's
parts self-healing re-validated cached parts with isConnected and re-resolved
stale ones — but when a part had been REMOVED with no replacement (segmented's
optional `custom` input: a structural rebuild does options.textContent = '' and
only conditionally re-appends it), re-resolution found nothing and THREW where
1.7.5 leniently returned the detached node. The throw fired inside change
handlers that destructure this.parts unconditionally, killing the handler before
it committed this.value — stale value, correct DOM. The suspected computed-getter
change was exonerated (scalar values never touch it); bisect pinned component.ts.

Fix: when re-resolution fails but a previously-resolved node exists, return it
(1.7.5 leniency); self-healing still wins when a replacement exists; the throw is
reserved for refs that never resolved. Verified against tosijs-ui's real
tosi-segmented Playwright lane: Firefox 2/2-failing -> green, WebKit 4/4,
Chromium green; tosijs-ui tree restored untouched.

New coverage this class of bug was missing:
- unit tests: detach-then-access, and the full click -> change -> value-commit
  round-trip (reproduces in happy-dom — the bug was deterministic, not truly
  browser-specific)
- tests/value-commit.pw.ts: the same round-trip in a real browser per engine

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EVU6HWRPnVwqc5XgTSnSv

v1.7.7

Toggle v1.7.7's commit message
v1.7.7: parts resolves your OWN part via pre-hydration ownership capt…

…ure (supersedes broken 1.7.6, tosijs#20)

parts.foo resolves through a single _partsCache that is SEEDED at hydration with
this component's own [part] elements — captured from the content tree BEFORE it is
inserted and before any nested sub-component hydrates or slots. At that moment the
tree is exactly what the component built, so every [part] is unambiguously its own,
regardless of nesting depth, <tosi-slot> projection, or whether a sub-component is
light- or shadow-DOM. Misses fall back to querySelector (lazily-built parts, static
cloned content, css-selector refs) and are cached back into the same map. Reads
re-validate isConnected, so a part a render() replaced re-resolves (self-heals),
and a missing part is never cached, so a later access resolves once present.

This is ownership, not structure — it defeats the case that broke every structural
attempt: an own part placed inside a light-DOM slotting sub-component (captured
before it's slotted). 1.7.6's custom-element-boundary attempt broke parts for any
component laying parts out inside a sub-component (e.g. tosi-tabs); 1.7.6 is
deprecated on npm.

Also deprecates data-ref (a React-era "refs" fossil): still resolves but warns
once, removed from the docs, slated for removal in 1.8.0 — use part="…".

All other 1.7.6 content retained (computed-property fix, #19, Tosi* blueprint
types, docs). Nine new regression tests in component.test.ts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EVU6HWRPnVwqc5XgTSnSv

v1.7.6

Toggle v1.7.6's commit message
v1.7.6: parts scoping + computed-property crash + XinProps type fixes…

…; blueprint Tosi* types; docs overhaul

Fixes:
- Light-DOM `this.parts.foo` no longer reaches into nested components — part
  resolution stops at nested custom-element boundaries (shadow DOM was already
  scoped). Fixes the wrong-part grab when a component contains another instance
  (tosijs#20, filed from tosijs-ui's self-hosting doc demo).
- Registering an object with a getter no longer throws "assign to readonly
  property" — the set-trap unwrap loop only rewrites writable data properties and
  never invokes getters during registration; computed properties are legal state.
- xinValue/xinPath restored to XinProps (parity with BoxedScalarAPI) — fixes the
  silent typecheck-only break for object/array proxies (tosijs#19).

Added:
- TosiBlueprint/TosiFactory/TosiPackagedComponent/TosiComponentSpec canonical
  type names; Xin* kept as @deprecated aliases (type-only, no runtime change).

Changed:
- Accessor docs lead with .value/.tosi.value; tosiPath()/tosiValue() as the
  programmatic alternative.
- (dev) editableSources:true; build host bumped to tosijs-ui 1.7.2.

Docs: README overhaul (ecosystem table, sharpened case, xin-proxy purge), new
tosijs-history page, new Angular page + expanded React page, Building-Apps
boxed-proxy gotcha.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EVU6HWRPnVwqc5XgTSnSv

v1.7.5

Toggle v1.7.5's commit message
v1.7.5: on<Event> collision warning suggests handle<Event> vs add<Eve…

…nt>Listener by intent

The member-collision warning (and the Component docs) previously offered only
handle<Event> as the rename. It now distinguishes the two real intents:
- handle<Event> for a handler function the component invokes (handleClick)
- add<Event>Listener for a method that registers listeners for a synthetic
  event the component dispatches (addClickListener)

Warning text + docs only; no behavior change. Test asserts both conventions
appear in the warning.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EVU6HWRPnVwqc5XgTSnSv

v1.7.4

Toggle v1.7.4's commit message
v1.7.4: faster dispatch via getElementsByClassName; rename -xin-data …

…-> -tosi-data; export the marker constants

Dispatch enumeration (the global "any state changed" observer, the
MutationObserver re-discovery, and the list-binding relative refresh) now uses
getElementsByClassName — which gathers from the browser's class-name bucket
index — instead of querySelectorAll's whole-tree walk. Measured 1.6-2.6x faster
in Blink on the global scan, gap widening with DOM size. Result set identical;
still snapshotted to a static array so toDOM mutations mid-dispatch can't perturb
a live collection.

Renamed the data-binding marker class -xin-data -> -tosi-data (the last xin-era
name in the runtime DOM), and — the point of this addition — EXPORTED BOUND_CLASS
and BOUND_SELECTOR from the package root. They were internal, so anyone
referencing the marker had to hardcode the literal; that hardcoding is the only
reason the rename is breaking. Integrations import the constant now and follow
future renames automatically. The marker stays a class (not a data-attribute)
because getElementsByClassName is class-only and that's the fast path; it can't
be a WeakMap because dispatch enumerates by path.

Potentially breaking (unlikely): anyone selecting .-xin-data (undocumented
internal) uses .-tosi-data or, better, BOUND_CLASS now.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EVU6HWRPnVwqc5XgTSnSv

v1.7.3

Toggle v1.7.3's commit message
v1.7.3: retire the -xin-event marker class from on()

on() no longer stamps a `-xin-event` class onto elements. Event delegation used
that class to climb the ancestor chain via closest(); it now walks the ancestor
chain (across open-shadow boundaries) consulting the elementToHandlers WeakMap
directly, which is already the authoritative record of which elements have
handlers. Behavior is identical — including delegation across open shadow roots
— but on()-bound elements are no longer mutated: nothing lands in className, and
clones carry no stray marker (so they're skipped naturally, not via a defensive
class check).

The -xin-data marker on data-bound elements is retained: a MutationObserver
re-discovers those via querySelectorAll, which a WeakMap can't provide. That
asymmetry is why events need no class and data bindings do.

Potentially breaking (unlikely): anyone styling/selecting `.-xin-event` (an
undocumented internal) loses it — surfaced in the changelog.

New regression test: on() does not mutate className, delegation still resolves.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EVU6HWRPnVwqc5XgTSnSv

v1.7.2

Toggle v1.7.2's commit message
v1.7.2: fix custom-property line-height losing its px suffix (1.7.0 r…

…egression)

`_lineHeight: 25` emitted `--line-height: 25` instead of `--line-height: 25px`.
1.7.0's `_opacity: 0.5px` fix started stripping the `_` before the unitless-list
test, and `line-height` was in that list, so custom-property line-heights matched
and lost their px. Subtle and lethal — the vars system uses lineHeight as a
length in calc(), so downstream computed sizes silently broke.

line-height is now dual-mode: real declaration keeps the unitless multiplier
(lineHeight: 1.5 -> 1.5); custom property takes px (_lineHeight: 25 -> 25px);
opt out with a string (_lineHeight: '1.5'). The always-unitless set (opacity,
z-index, font-weight, ...) still suppresses px for both real and custom props,
so the 1.7.0 _opacity fix is preserved.

Fail-first regression test in css.test.ts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EVU6HWRPnVwqc5XgTSnSv

v1.7.1

Toggle v1.7.1's commit message
v1.7.1: ship CHANGELOG.md + llms.txt to npm; internal cleanup

Packaging fix (the headline): CHANGELOG.md and llms.txt were built and
committed but omitted from the `files` allowlist, so they never reached
npm installers. Both now publish.

No API or behavior changes. Internal cleanup:
- guard composedPath() behind event.composed in on()'s origin resolution
- remove dead DATEISH constant from dom.ts
- extract shared __tjs bootstrap into configure-tjs.ts (debug/safe)
- extract duplicated blueprint-batch loader into settleBlueprints()
- correct a list-binding.ts comment (SVG/MathML namespaced, not table mode)

Docs: Building-Apps "boxed proxies are minted fresh per access" gotcha;
date-family control round-trip test coverage in dom.test.ts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014EVU6HWRPnVwqc5XgTSnSv

v1.7.0

Toggle v1.7.0's commit message
v1.7.0: the correctness release

Consolidates 1.7.0-beta.1 + beta.2 into the stable 1.7.0. Outcome of the
2026-07-17 whole-codebase review (~45 verified defects, all passing the
prior happy-path suite) plus the medium-backlog triage and the dynamic-
theming docs. No API removed/renamed; the behavior changes (shadow-DOM
on() via composedPath, segment-exact path matching, typed getValue,
Component change bubbling, reactive class replace, deepClone
Date/Map/Set) are documented in CHANGELOG + Migration.md.

Ships a first CI (unit + multi-engine Playwright doc-test lane), pre-
release-reviewed (GO), built against tosijs-ui 1.7.0-rc.1 (tsc failure
now fatal) and tjs-lang 0.10.1. Suite 646 green; browser lane green on
Chromium + Firefox.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>