Skip to content

chore: reapply October PRs (#101, #102, #103) onto release-1.22 - #106

Merged
ErickXavier merged 4 commits into
release-1.22from
chore/reapply-october
Oct 15, 2026
Merged

ErickXavier merged 4 commits into
release-1.22from
chore/reapply-october

Conversation

@ErickXavier

@ErickXavier ErickXavier commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

Reapplies the three October PRs that were dropped when main went back to v1.21.1. Each one is a separate commit on top of release-1.22, with dist/ rebuilt. A follow-up commit (a620d2a) closes one gap that #103 opened against v1.21.1.

PR Commit Verdict vs v1.21.1 Notes
#101 dnd host API / server-bound implicit lists 6f8cae5 ✅ no change for legitimate uses Core mode keeps the same mechanics; the drag/drop bodies were moved into backend-agnostic functions. The host backend only activates when NoJS.hostApi >= 1, which core never defines. One observable change, which fixes a bug: the plugin init hook no longer re-binds [drag]/[drop] nodes that the real directive already bound against the live context (details below).
#102 dependabot bumps 7ad69a7 ✅ dev-only Lockfile taken from #102 (npm 10), with the root version kept at 1.22.0. npm ci works. dist/ built with esbuild 0.28.2 is byte-identical.
#103 validate + model with validate-on 75d73db ✅ only changes cases that were broken Fields without model, and the legacy path (no validate-on), keep the v1.21.1 listener order. Only model fields under validate-on change, and in v1.21.1 those discarded every keystroke or choice.
follow-up to #103 a620d2a ✅ closes a gap #103 opened #103 moved the value listener of model select/checkbox/radio fields from input to change, so a script-dispatched input stopped validating them. The listener is back on input in its v1.21.1 position, with no change listener: a real pick validates once and an explicit validate-on means what it did in v1.21.1. Before validating, the field value is written to its model the same way core's model does on change, so the pick is no longer reverted. That write is skipped for an unchecked radio and for an if-gated model.

Evidence

Unit tests (Jest)

  • Branch suite: 544 passed, 5 skipped. It passes against Core release-1.22 (4fcd400) and against Core v1.21.1.
  • The unchanged v1.21.1 suite, run against the final src/: 498/498 pass (5 skipped). This is identical to the v1.21.1 baseline.

E2E (Playwright 1.64, chromium + firefox + webkit)

  • 462/462 pass with Core release-1.22.
  • 462/462 pass with Core v1.21.1.
  • This is the v1.21.1 suite (435) plus the validation-model spec (27).

dnd A/B (#101)

  • Setup: a synthetic-event harness ran the same scenarios with the v1.21.1 Elements build and with this branch, against Core v1.21.1 and Core release-1.22. Each combination ran twice: once with the plugin installed before init, once with it installed after init.
  • Scenarios: drag, drag-type, drag-effect, drag-handle, drag-image (+ offset, none), drag-ghost-class, drag-class, drag-disabled (reactive), drop, drop-accept (list and *), drop-effect, drop-class, drop-reject-class, drop-disabled, drop-max, drop-sort + drop-placeholder + drop-placeholder-class, keyboard Space/Enter/Escape, all nojs:dnd-* events, all implicit variables, drag-list reorder/move, and drag-multiple select + group drag.
  • Result: 492 recorded values per run. Everything is identical except:
    • Children of a [drop] zone are initialised once instead of twice. For example, on:init fires 1× instead of 2× (2× instead of 3× when the plugin is installed late).
    • With Core release-1.22, an each inside a [drop] zone re-renders after a drop. On v1.21.1 the state updated but the list did not.

validate A/B (#103 + follow-up)

  • Setup: real typing, select, checkbox and radio input, plus script-dispatched input/change with validate-on set to input, blur and submit. Each form also holds a plain select as a control. Run against both cores.
  • model without validate-on: identical to v1.21.1.
  • Fields without model under validate-on (on:input/on:focusout reading $form, aria-invalid timing): identical to v1.21.1.
  • model text fields under validate-on: the v1.21.1 build wiped typed text. With this branch the text is kept, and behaviour (including on:input ordering) matches the model-without-validate-on path.
  • model select/checkbox/radio under validate-on: a script-dispatched input validates, as in v1.21.1. The v1.21.1 build then reverted the pick; this branch keeps it. A change-only dispatch does not validate, as in v1.21.1. Dirty/touched/error feedback matches the plain select for every validate-on value.
  • New e2e tests: against the v1.21.1 build the model cases fail (the pick is reverted); against 75d73db (fix(validate): keep model values when fields use validate-on #103 alone) the choice-control cases fail (input does not validate).

NoJS-Server (release-1.22, sibling layout with Core release-1.22 + this branch)

  • tsc --noEmit: clean.
  • npm test: 155 + 1167 + 150 + 34 pass.
  • test:e2e: 11/11 pass.
  • test:parity: 12/12 pass, including dnd-reorder.
  • With the current release-1.22 Elements head, Server's plugin compiler suites fail 5 tests. With this branch they pass 119/119.

npm run version:check: OK 1.22.0.

Reapply #101 (76a3f89) onto release-1.22.

- drag/drop split into backend-agnostic mechanics plus a core backend
  (unchanged semantics) and a host backend used only when
  window.NoJS.hostApi >= 1, which core never defines
- attribute contract for the NoJS-Server compiler (plugin.contract)
- init-hook re-bind skips dnd nodes already bound by the real directive
  against the live context, so an `each` inside a [drop] zone keeps
  re-rendering
- dnd expressions captured at init, as in v1.21.1
Reapply #102 (709b675) onto release-1.22.

- @testing-library/jest-dom 7.0.0 -> 7.0.1
- esbuild 0.28.1 -> 0.28.2
- jest-environment-jsdom 30.4.1 -> 30.5.2
- jest 30.4.2 -> 30.5.2
- babel-jest 30.2.0 -> 30.5.2
- @babel/preset-env 8.0.2 -> 8.0.7
- @playwright/test 1.61.1 -> 1.64.0
- @babel/core 8.0.1 -> 8.0.7

Lockfile from #102 (npm 10) with the root version kept at 1.22.0.
dist/ rebuilt with esbuild 0.28.2 is byte-identical.
Reapply #103 (73fa034) onto release-1.22.

With validate-on, per-field value listeners were bound before the
field's own `model` listener. checkValidity() notified the context
synchronously, so `model` re-rendered its stale value over what the
user typed or picked.

- re-append the value listeners of `model` fields in a microtask, once
  the subtree is processed, so they run after `model`
- `model` select/checkbox/radio sync on "change", so validate listens
  on "change" for those fields
- fields without `model` keep their v1.21.1 listener order
#103 moved the validate-on value listener of select/checkbox/radio
fields with `model` from "input" to "change". A script-dispatched
"input" no longer validated those fields, unlike v1.21.1.

- listen on "input" again, in the v1.21.1 position; no "change"
  listener, so a real pick (input then change) validates once and an
  explicit validate-on keeps its v1.21.1 meaning
- before validating, write the field value to its `model` the way
  core's `model` does on "change", so the validation notify no longer
  re-renders the stale value over the pick
- skip that write for an unchecked radio and for an if-gated `model`
@ErickXavier
ErickXavier merged commit 86d2433 into release-1.22 Oct 15, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant