@askrjs/askr 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.3 — 2026-10-02
4
+
5
+ ### Breaking changes
6
+
7
+ - None.
8
+
9
+ ### Deprecations
10
+
11
+ - None.
12
+
13
+ ### Additions
14
+
15
+ - None.
16
+
17
+ ### Fixes
18
+
19
+ - Retain each queued input or textarea edit and checkbox/radio change during
20
+ hydration, so replayed handlers and a following submit observe the captured
21
+ values even when hydration writes the initial control state. File input
22
+ values remain untouched.
23
+ - Preserve native printable typing, Backspace, and Delete in editable text
24
+ controls before hydration. Enter, modified shortcuts, and activation retain
25
+ their existing cancellation; immediately activated deferred key handlers
26
+ can still cancel the native edit.
27
+ - Discard events whose target is replaced during deferred activation and
28
+ release root capture listeners when the final deferred boundary completes.
29
+
3
30
  ## 0.4.2 — 2026-10-01
4
31
 
5
32
  - fix(foundations): honor previously cancelled click and keyboard events in
package/dist/benchmark.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { y as flushSync } from "./instance-DL-YKrj6.js";
2
2
  import { a as state, i as selector } from "./state-i9D4EtY6.js";
3
3
  import { i as jsxs, n as jsx } from "./jsx-runtime-C4idqHY0.js";
4
- import { r as createIsland } from "./boot-DUJkrqGs.js";
4
+ import { r as createIsland } from "./boot-DpsfNWHm.js";
5
5
  import { n as For } from "./control-hr3B0QaD.js";
6
6
  //#region src/bench/components/benchmark-row.tsx
7
7
  function BenchmarkRow({ item, isSelected, onSelect, onRemove }) {
@@ -58,8 +58,8 @@ function BenchmarkTable({ rows, isSelected, onSelect, onRemove }) {
58
58
  }
59
59
  const benchmarkMetadata = {
60
60
  packageName: "@askrjs/askr",
61
- packageVersion: "0.4.2",
62
- buildLabel: "0.4.2-local"
61
+ packageVersion: "0.4.3",
62
+ buildLabel: "0.4.3-local"
63
63
  };
64
64
  function getBenchmarkMetadata() {
65
65
  return { ...benchmarkMetadata };
@@ -1,2 +1,2 @@
1
- import { a as cleanupApp, i as createIslands, n as createSPA, o as hasApp, r as createIsland, t as hydrateSPA } from "../boot-DUJkrqGs.js";
1
+ import { a as cleanupApp, i as createIslands, n as createSPA, o as hasApp, r as createIsland, t as hydrateSPA } from "../boot-DpsfNWHm.js";
2
2
  export { cleanupApp, createIsland, createIslands, createSPA, hasApp, hydrateSPA };
@@ -3773,6 +3773,33 @@ function cloneInteractionEvent(event) {
3773
3773
  });
3774
3774
  }
3775
3775
  }
3776
+ function captureControlState(event, target) {
3777
+ if (event.type !== "input" && event.type !== "change") return void 0;
3778
+ if (target instanceof HTMLInputElement) {
3779
+ if (target.type === "checkbox" || target.type === "radio") return { checked: target.checked };
3780
+ if (target.type !== "file") return { value: target.value };
3781
+ }
3782
+ if (target instanceof HTMLTextAreaElement) return { value: target.value };
3783
+ }
3784
+ function restoreControlState(interaction) {
3785
+ const { target, controlState } = interaction;
3786
+ if (!controlState) return;
3787
+ if ("checked" in controlState) {
3788
+ if (target instanceof HTMLInputElement && (target.type === "checkbox" || target.type === "radio")) target.checked = controlState.checked;
3789
+ } else if (target instanceof HTMLTextAreaElement || target instanceof HTMLInputElement && target.type !== "file") target.value = controlState.value;
3790
+ }
3791
+ function allowsNativeTextInput(event, target) {
3792
+ if (!(event instanceof KeyboardEvent) || event.type !== "keydown" || event.key.length !== 1 && event.key !== "Backspace" && event.key !== "Delete" || event.ctrlKey || event.metaKey || event.altKey) return false;
3793
+ return (target instanceof HTMLTextAreaElement || target instanceof HTMLInputElement && [
3794
+ "text",
3795
+ "search",
3796
+ "email",
3797
+ "url",
3798
+ "tel",
3799
+ "password",
3800
+ "number"
3801
+ ].includes(target.type)) && !target.readOnly && !target.disabled;
3802
+ }
3776
3803
  /**
3777
3804
  * Capture discrete interactions before hydrated handlers exist, then replay
3778
3805
  * them after the listener transaction commits. Deferred boundaries remain
@@ -3825,8 +3852,13 @@ function beginHydrationInteractionReplay(root, activateBoundary, permanentSkipSe
3825
3852
  deferredBoundaries.delete(boundary);
3826
3853
  notifyIfDeferredBoundariesDrained();
3827
3854
  }
3855
+ if (!root.contains(interaction.target)) {
3856
+ releaseIfFinished();
3857
+ return;
3858
+ }
3828
3859
  replaying = true;
3829
3860
  try {
3861
+ restoreControlState(interaction);
3830
3862
  interaction.target.dispatchEvent(interaction.event);
3831
3863
  } finally {
3832
3864
  replaying = false;
@@ -3839,17 +3871,19 @@ function beginHydrationInteractionReplay(root, activateBoundary, permanentSkipSe
3839
3871
  if (!target || isPermanentlySkipped(target)) return;
3840
3872
  const boundary = findDeferredBoundary(target);
3841
3873
  if (!hydratingRoot && !boundary) return;
3842
- event.preventDefault();
3874
+ if (!allowsNativeTextInput(event, target)) event.preventDefault();
3843
3875
  event.stopImmediatePropagation();
3844
3876
  const interaction = {
3845
3877
  target,
3846
- event: cloneInteractionEvent(event)
3878
+ event: cloneInteractionEvent(event),
3879
+ controlState: captureControlState(event, target)
3847
3880
  };
3848
3881
  if (hydratingRoot) {
3849
3882
  queued.push(interaction);
3850
3883
  return;
3851
3884
  }
3852
3885
  replayInteraction(interaction);
3886
+ if (interaction.event.defaultPrevented) event.preventDefault();
3853
3887
  }
3854
3888
  const installedTypes = [];
3855
3889
  try {
@@ -1,7 +1,7 @@
1
1
  import { y as flushSync } from "../instance-DL-YKrj6.js";
2
2
  import { n as createSource, s as notify, u as readSource } from "../hooks-kjLigwDJ.js";
3
3
  import { v as matchRoute } from "../resolution-CF1BqHLm.js";
4
- import { a as cleanupApp, n as createSPA, r as createIsland } from "../boot-DUJkrqGs.js";
4
+ import { a as cleanupApp, n as createSPA, r as createIsland } from "../boot-DpsfNWHm.js";
5
5
  import { h as addInvalidationListener, t as createDataRuntime, u as resolveDataRuntimeState } from "../data-runtime-i-RD0Ffm.js";
6
6
  import { a as loadingQueryState, i as freshQueryState, o as refreshingQueryState, r as errorQueryState, s as staleQueryState } from "../data-BsnOUpQ6.js";
7
7
  import { i as normalizeAsyncDataError } from "../shared-O2ZnmYAf.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askrjs/askr",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "A TypeScript UI runtime with getter-based state, fine-grained bindings, transactional commits with rollback, and one route graph for SPA, SSR, and SSG.",
5
5
  "keywords": [
6
6
  "askr",