haori 0.41.0 → 0.41.2

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/dist/haori.es.js CHANGED
@@ -662,7 +662,7 @@ const vt = Object.freeze({
662
662
  distinct: lt,
663
663
  groupBy: ut
664
664
  });
665
- class Le {
665
+ class Be {
666
666
  constructor() {
667
667
  this.MAX_BUDGET = 8, this.queue = [], this.processing = !1;
668
668
  }
@@ -752,7 +752,7 @@ class Le {
752
752
  async waitForIdle(e = 1e3) {
753
753
  let t = 0, r = 0;
754
754
  for (; t < 2 && r < e; )
755
- this.processing || this.queue.length > 0 ? (await this.wait(), t = 0) : t += 1, await Le.nextTick(), r += 1;
755
+ this.processing || this.queue.length > 0 ? (await this.wait(), t = 0) : t += 1, await Be.nextTick(), r += 1;
756
756
  }
757
757
  /**
758
758
  * 次のフレーム(または 1 マクロタスク)まで待機します。
@@ -792,7 +792,7 @@ const He = class He {
792
792
  return this.ASYNC_QUEUE.waitForIdle(e);
793
793
  }
794
794
  };
795
- He.ASYNC_QUEUE = new Le();
795
+ He.ASYNC_QUEUE = new Be();
796
796
  let W = He;
797
797
  const C = class C {
798
798
  /**
@@ -3349,8 +3349,10 @@ const M = class M extends N {
3349
3349
  /**
3350
3350
  * この入力欄がユーザーに編集されたことを記録します。
3351
3351
  *
3352
- * `change` / `input` の委譲で内部値を DOM から同期した直後に呼び出します。
3353
- * プログラムからの値反映(バインド由来の書き戻しなど)では呼び出しません。
3352
+ * DOM で `change` / `input` が発火した時点(内部値を DOM から同期した直後)に
3353
+ * 呼び出します。イベントを伴って値を反映した場合(`Form.setValues()` など)も、
3354
+ * その発火を通じて呼ばれます。イベントを伴わない反映(`syncBindingValue()` や
3355
+ * `Core.setBindingData()` 由来の書き戻し)では呼び出しません。
3354
3356
  *
3355
3357
  * @returns 発番した編集の通番
3356
3358
  */
@@ -3715,14 +3717,14 @@ const M = class M extends N {
3715
3717
  r,
3716
3718
  l
3717
3719
  );
3718
- const D = o.isForceEvaluation() ? r : y ? S : A, B = i && o.isEvaluate && t === "value" && M.isValuePropertyTarget(l), E = l.getRootNode(), v = B && (l === E.activeElement || this.hasPendingUserEdit()), R = P || D === null || D === !1 ? null : String(D), k = e !== t && l.getAttribute(e) !== r, x = R === null ? l.hasAttribute(t) : l.getAttribute(t) !== R, V = R === null ? "" : R, G = B && !v && l.value !== V, _ = t === "checked" && l instanceof HTMLInputElement && (l.type === "checkbox" || l.type === "radio"), Z = t === "selected" && l instanceof HTMLOptionElement, Ne = E.activeElement, Fe = Ne !== null && (_ && l === Ne || Z && l.closest("select") === Ne) || (_ || Z) && this.hasPendingCheckableUserEdit(Z), be = R !== null, xe = _ && !Fe && l.checked !== be, ye = Z && !Fe && l.selected !== be;
3720
+ const D = o.isForceEvaluation() ? r : y ? S : A, L = i && o.isEvaluate && t === "value" && M.isValuePropertyTarget(l), E = l.getRootNode(), v = L && (l === E.activeElement || this.hasPendingUserEdit()), R = P || D === null || D === !1 ? null : String(D), k = e !== t && l.getAttribute(e) !== r, x = R === null ? l.hasAttribute(t) : l.getAttribute(t) !== R, V = R === null ? "" : R, G = L && !v && l.value !== V, _ = t === "checked" && l instanceof HTMLInputElement && (l.type === "checkbox" || l.type === "radio"), Z = t === "selected" && l instanceof HTMLOptionElement, Ne = E.activeElement, Fe = Ne !== null && (_ && l === Ne || Z && l.closest("select") === Ne) || (_ || Z) && this.hasPendingCheckableUserEdit(Z), be = R !== null, xe = _ && !Fe && l.checked !== be, ye = Z && !Fe && l.selected !== be;
3719
3721
  if (!k && !x && !G && !xe && !ye)
3720
- return B && !v && (this.value = this.normalizeValueForElement(
3722
+ return L && !v && (this.value = this.normalizeValueForElement(
3721
3723
  l,
3722
3724
  V
3723
3725
  ), this.clearUnappliedValueWrite()), (_ || Z) && !Fe && this.syncCheckableValueFromDom(Z), Promise.resolve();
3724
3726
  const Ue = W.enqueue(() => {
3725
- k && l.setAttribute(e, r), R === null ? l.removeAttribute(t) : x && (l.setAttribute(t, R), t === `${u.prefix}bind` && this.recordSelfWrittenBind(R)), B && !v && (this.value = this.normalizeValueForElement(
3727
+ k && l.setAttribute(e, r), R === null ? l.removeAttribute(t) : x && (l.setAttribute(t, R), t === `${u.prefix}bind` && this.recordSelfWrittenBind(R)), L && !v && (this.value = this.normalizeValueForElement(
3726
3728
  l,
3727
3729
  V
3728
3730
  ), G && (l.value = V), this.recordValueWriteResult(l.value === V)), xe && (l.checked = be), ye && (l.selected = be), (xe || ye) && this.syncCheckableValueFromDom(ye);
@@ -5995,8 +5997,8 @@ const p = class p {
5995
5997
  // 解釈する(後続の分岐)。位置で配ると選択状態を決められないため、
5996
5998
  // `data-form-list` を併記していても従来どおりそちらへ渡す。
5997
5999
  !p.isGroupedCheckable(e) && !p.isMultipleSelect(e)) {
5998
- const B = String(l), E = s.get(B) ?? 0;
5999
- s.set(B, E + 1), o.push(
6000
+ const L = String(l), E = s.get(L) ?? 0;
6001
+ s.set(L, E + 1), o.push(
6000
6002
  p.applyFragmentValue(
6001
6003
  e,
6002
6004
  D[E] ?? null,
@@ -6045,8 +6047,8 @@ const p = class p {
6045
6047
  A,
6046
6048
  P == null ? null : String(P)
6047
6049
  ) : null;
6048
- for (let B = 0; B < S.length; B++) {
6049
- const E = S[B], v = D ? D[B] : A.length > B ? A[B] : null;
6050
+ for (let L = 0; L < S.length; L++) {
6051
+ const E = S[L], v = D ? D[L] : A.length > L ? A[L] : null;
6050
6052
  o.push(
6051
6053
  // 行ごとに values が切り替わるので出現位置も行単位で数える。
6052
6054
  p.setPartValues(
@@ -7338,7 +7340,7 @@ function me(g) {
7338
7340
  me
7339
7341
  ) : !1;
7340
7342
  }
7341
- function Bt(g) {
7343
+ function Lt(g) {
7342
7344
  return Object.values(g).some((e) => e instanceof Blob ? !1 : Array.isArray(e) ? e.some(
7343
7345
  (t) => !(t instanceof Blob) && me(t)
7344
7346
  ) : me(e));
@@ -7370,7 +7372,7 @@ function $e(g) {
7370
7372
  t[r] = e(i);
7371
7373
  return F.carryCollectedRowIdentity(g, t), t;
7372
7374
  }
7373
- function Lt(g, e) {
7375
+ function Bt(g, e) {
7374
7376
  const t = new Headers(
7375
7377
  e.headers || void 0
7376
7378
  ), r = Array.from(t.entries()).sort(
@@ -7988,22 +7990,22 @@ ${R}
7988
7990
  `Element not found: ${E} (${D})`
7989
7991
  )) : v.push(e), v.length > 0 && (r.fetchStateFragments = v);
7990
7992
  }
7991
- const B = t ? b.attrName(t, "store-clear") : b.attrName(null, "store-clear", !0);
7992
- if (e.hasAttribute(B)) {
7993
- const E = e.getRawAttribute(B), v = E === null ? "" : E.trim();
7993
+ const L = t ? b.attrName(t, "store-clear") : b.attrName(null, "store-clear", !0);
7994
+ if (e.hasAttribute(L)) {
7995
+ const E = e.getRawAttribute(L), v = E === null ? "" : E.trim();
7994
7996
  if (v === "")
7995
7997
  m.error(
7996
7998
  "Haori",
7997
- `ストレージキーが指定されていません (${B})`
7999
+ `ストレージキーが指定されていません (${L})`
7998
8000
  );
7999
8001
  else {
8000
8002
  r.storeClearKey = v;
8001
8003
  const R = e.getRawAttribute(
8002
- `${B}-type`
8004
+ `${L}-type`
8003
8005
  ), k = R === null ? "session" : R.trim();
8004
8006
  k === "local" || k === "session" ? r.storeClearKind = k : (m.warn(
8005
8007
  "Haori",
8006
- `${B}-type は session または local を指定してください(session として扱います): ${k}`
8008
+ `${L}-type は session または local を指定してください(session として扱います): ${k}`
8007
8009
  ), r.storeClearKind = "session");
8008
8010
  }
8009
8011
  }
@@ -8149,11 +8151,11 @@ ${R}
8149
8151
  s
8150
8152
  );
8151
8153
  n = S.url;
8152
- const P = { ...S.options }, D = S.normalized ? S.requestedMethod : r.requestedMethod, B = S.effectiveMethod, E = r.transportMode === "query-get" || S.normalized, v = S.queryString ?? r.queryString;
8154
+ const P = { ...S.options }, D = S.normalized ? S.requestedMethod : r.requestedMethod, L = S.effectiveMethod, E = r.transportMode === "query-get" || S.normalized, v = S.queryString ?? r.queryString;
8153
8155
  if (E && m.info("Haori demo fetch normalization", {
8154
8156
  runtime: u.runtime,
8155
8157
  requestedMethod: D,
8156
- effectiveMethod: B,
8158
+ effectiveMethod: L,
8157
8159
  transportMode: "query-get",
8158
8160
  url: n,
8159
8161
  payload: l ? i : void 0,
@@ -8162,7 +8164,7 @@ ${R}
8162
8164
  const R = performance.now(), k = {
8163
8165
  runtime: u.runtime,
8164
8166
  requestedMethod: D,
8165
- effectiveMethod: B,
8167
+ effectiveMethod: L,
8166
8168
  transportMode: E ? "query-get" : "http",
8167
8169
  ...E ? { queryString: v } : {}
8168
8170
  };
@@ -8194,17 +8196,17 @@ ${R}
8194
8196
  const h = this.options.formFragment, y = h.getTarget(), A = /* @__PURE__ */ new Set();
8195
8197
  e && e.appliedDisabledAttribute && this.options.targetFragment && A.add(this.options.targetFragment);
8196
8198
  const S = h.getRawBindingData(), P = $e(i), D = h.getAttribute(`${u.prefix}form-arg`);
8197
- let B;
8199
+ let L;
8198
8200
  if (D) {
8199
- B = { ...S ?? {} };
8201
+ L = { ...S ?? {} };
8200
8202
  const E = String(D), v = F.resolveAncestorArgOwner(h, E);
8201
- B[E] = F.mergeCollectedValues(
8202
- (v ? v.value : B[E]) ?? null,
8203
+ L[E] = F.mergeCollectedValues(
8204
+ (v ? v.value : L[E]) ?? null,
8203
8205
  P
8204
8206
  );
8205
8207
  } else
8206
- B = F.mergeCollectedValues(S, P);
8207
- await O.setBindingData(y, B, {
8208
+ L = F.mergeCollectedValues(S, P);
8209
+ await O.setBindingData(y, L, {
8208
8210
  skipFragments: A,
8209
8211
  kind: "nonSupply",
8210
8212
  sequence: this.operationSequence,
@@ -8492,7 +8494,74 @@ ${R}
8492
8494
  ), !0;
8493
8495
  F.applyCustomValidity(e);
8494
8496
  const t = this.findFirstInvalid(e);
8495
- return t === null ? !0 : (t.reportValidity(), t.focus(), this.options.scrollOnError && t.scrollIntoView({ behavior: "smooth", block: "nearest" }), !1);
8497
+ if (t === null)
8498
+ return !0;
8499
+ const r = t;
8500
+ return b.isRectFullyVisible(t.getBoundingClientRect()) ? (r.reportValidity(), t.focus(), this.options.scrollOnError && t.scrollIntoView({ behavior: "smooth", block: "nearest" }), !1) : (t.focus({ preventScroll: !0 }), t.scrollIntoView({ behavior: "smooth", block: "nearest" }), b.reportValidityAfterScroll(r), !1);
8501
+ }
8502
+ /**
8503
+ * スクロールが止まってから、対象の入力要素の検証 UI(バブル)を表示します。
8504
+ *
8505
+ * `requestAnimationFrame` ごとに対象要素の位置を測り、位置が変わらないフレームが
8506
+ * 続き、かつ画面内に入ったら表示します。スムーズスクロールの所要時間はブラウザに
8507
+ * よって変わるため、上限(`VALIDATION_SCROLL_TIMEOUT_MS`)を過ぎたら静止を待たずに
8508
+ * 表示します。待機中に別の検証が始まった場合と、対象が DOM から外れた場合は
8509
+ * 表示しません。
8510
+ *
8511
+ * @param target 検証エラーの入力要素
8512
+ */
8513
+ static reportValidityAfterScroll(e) {
8514
+ const t = ++b.validationReportGeneration, r = performance.now();
8515
+ let i = null, n = 0;
8516
+ const s = () => {
8517
+ if (t !== b.validationReportGeneration || !e.isConnected)
8518
+ return;
8519
+ const a = e.getBoundingClientRect(), o = `${Math.round(a.top)}:${Math.round(a.left)}`;
8520
+ if (n = o === i ? n + 1 : 0, i = o, n >= b.VALIDATION_SCROLL_STABLE_FRAMES && b.isRectPartlyVisible(a) || performance.now() - r >= b.VALIDATION_SCROLL_TIMEOUT_MS) {
8521
+ e.reportValidity();
8522
+ return;
8523
+ }
8524
+ requestAnimationFrame(s);
8525
+ };
8526
+ requestAnimationFrame(s);
8527
+ }
8528
+ /**
8529
+ * ビューポートの大きさを返します。
8530
+ *
8531
+ * @returns ビューポートの幅と高さ
8532
+ */
8533
+ static getViewportSize() {
8534
+ return {
8535
+ width: window.innerWidth || document.documentElement.clientWidth,
8536
+ height: window.innerHeight || document.documentElement.clientHeight
8537
+ };
8538
+ }
8539
+ /**
8540
+ * 矩形がビューポートに収まっているかを判定します。
8541
+ *
8542
+ * 検証 UI を今すぐ出してよいかの判定に使います。一部でも外に出ていれば、
8543
+ * `reportValidity()` がバブルを見せるためにスクロールする余地が残っているため、
8544
+ * 「収まっている」とは扱いません。
8545
+ *
8546
+ * @param rect 判定する矩形
8547
+ * @returns 全体が画面内にあれば true
8548
+ */
8549
+ static isRectFullyVisible(e) {
8550
+ const { width: t, height: r } = b.getViewportSize();
8551
+ return e.top >= 0 && e.left >= 0 && e.bottom <= r && e.right <= t;
8552
+ }
8553
+ /**
8554
+ * 矩形がビューポートと重なっているかを判定します。
8555
+ *
8556
+ * スクロールの静止判定に使います。位置が変わらないだけでは、スクロールが始まる
8557
+ * 前の 1 フレームを「静止」と誤認するため、画面内に入ったことも条件にします。
8558
+ *
8559
+ * @param rect 判定する矩形
8560
+ * @returns 一部でも画面内にあれば true
8561
+ */
8562
+ static isRectPartlyVisible(e) {
8563
+ const { width: t, height: r } = b.getViewportSize();
8564
+ return e.top < r && e.bottom > 0 && e.left < t && e.right > 0;
8496
8565
  }
8497
8566
  /**
8498
8567
  * `data-{event}-if` の実行条件を評価します。
@@ -8992,7 +9061,7 @@ ${R}
8992
9061
  ), a = (n.method || "GET").toUpperCase(), o = u.runtime === "demo" && !Pe(a), l = o ? "GET" : a;
8993
9062
  if (n.method = l, Object.keys(t).length > 0 && me(t)) {
8994
9063
  const d = s.get("Content-Type") || "";
8995
- l !== "GET" && l !== "HEAD" && l !== "OPTIONS" && /multipart\/form-data/i.test(d) ? Bt(t) && m.warn(
9064
+ l !== "GET" && l !== "HEAD" && l !== "OPTIONS" && /multipart\/form-data/i.test(d) ? Lt(t) && m.warn(
8996
9065
  "Haori",
8997
9066
  `A File value nested under ${u.prefix}form-object / ${u.prefix}form-list cannot be sent. Place file inputs at the top level of the collected form values.`
8998
9067
  ) : m.warn(
@@ -9032,7 +9101,7 @@ ${R}
9032
9101
  effectiveMethod: l,
9033
9102
  queryString: c,
9034
9103
  transportMode: o ? "query-get" : "http",
9035
- signature: Lt(i, n)
9104
+ signature: Bt(i, n)
9036
9105
  };
9037
9106
  }
9038
9107
  /**
@@ -9543,7 +9612,7 @@ ${R}
9543
9612
  );
9544
9613
  }
9545
9614
  };
9546
- b.DATA_PLACEHOLDER_REGEX = /\{\{\{([\s\S]+?)\}\}\}|\{\{([\s\S]+?)\}\}/g, b.SINGLE_PLACEHOLDER_REGEX = /^(\{\{\{[\s\S]+?\}\}\}|\{\{[\s\S]+?\}\})$/, b.RUNNING_CLICK_TARGETS = /* @__PURE__ */ new WeakSet();
9615
+ b.DATA_PLACEHOLDER_REGEX = /\{\{\{([\s\S]+?)\}\}\}|\{\{([\s\S]+?)\}\}/g, b.SINGLE_PLACEHOLDER_REGEX = /^(\{\{\{[\s\S]+?\}\}\}|\{\{[\s\S]+?\}\})$/, b.RUNNING_CLICK_TARGETS = /* @__PURE__ */ new WeakSet(), b.validationReportGeneration = 0, b.VALIDATION_SCROLL_TIMEOUT_MS = 1e3, b.VALIDATION_SCROLL_STABLE_FRAMES = 2;
9547
9616
  let ee = b;
9548
9617
  class Ot {
9549
9618
  /**
@@ -10101,10 +10170,10 @@ const f = class f {
10101
10170
  return e.tagName === "FORM" && (D = D.then(() => {
10102
10171
  if (i.wasResetAfter(h))
10103
10172
  return;
10104
- const B = i.getRawBindingData() ?? A;
10173
+ const L = i.getRawBindingData() ?? A;
10105
10174
  return F.syncValues(
10106
10175
  i,
10107
- F.resolveSyncValues(i, B),
10176
+ F.resolveSyncValues(i, L),
10108
10177
  !1,
10109
10178
  c
10110
10179
  );
@@ -10116,8 +10185,8 @@ const f = class f {
10116
10185
  () => f.reevaluateReactiveSpecialAttributes(i, n)
10117
10186
  ), D.then(
10118
10187
  () => i.markBindingWorkEnd(),
10119
- (B) => {
10120
- throw i.markBindingWorkEnd(), B;
10188
+ (L) => {
10189
+ throw i.markBindingWorkEnd(), L;
10121
10190
  }
10122
10191
  );
10123
10192
  };
@@ -11336,7 +11405,7 @@ ${r}
11336
11405
  const P = e.getChildElementFragments().filter((E) => !y.has(E)), D = P.filter(
11337
11406
  (E) => E.hasAttribute(`${u.prefix}each-before`)
11338
11407
  ).length;
11339
- let B = Promise.resolve();
11408
+ let L = Promise.resolve();
11340
11409
  return a.forEach((E, v) => {
11341
11410
  const R = t[v], k = v;
11342
11411
  let x;
@@ -11344,7 +11413,7 @@ ${r}
11344
11413
  if (V) {
11345
11414
  x = V;
11346
11415
  const G = D + v;
11347
- B = B.then(
11416
+ L = L.then(
11348
11417
  () => f.updateRowFragment(
11349
11418
  x,
11350
11419
  R,
@@ -11379,7 +11448,7 @@ ${r}
11379
11448
  } else {
11380
11449
  x = r.clone();
11381
11450
  const G = D + v;
11382
- B = B.then(
11451
+ L = L.then(
11383
11452
  () => f.updateRowFragment(
11384
11453
  x,
11385
11454
  R,
@@ -11397,7 +11466,7 @@ ${r}
11397
11466
  })
11398
11467
  );
11399
11468
  }
11400
- }), Promise.all(c).then(() => B).then(() => {
11469
+ }), Promise.all(c).then(() => L).then(() => {
11401
11470
  const E = a.filter(
11402
11471
  (G) => G !== null
11403
11472
  ), v = A.filter(
@@ -11856,8 +11925,10 @@ const fe = class fe {
11856
11925
  if (r) {
11857
11926
  if (t === "input") {
11858
11927
  const i = `${u.prefix}input-`;
11859
- if (!r.getAttributeNames().some((s) => s.startsWith(i)))
11928
+ if (!r.getAttributeNames().some((s) => s.startsWith(i))) {
11929
+ this.recordUserEdit(r);
11860
11930
  return;
11931
+ }
11861
11932
  }
11862
11933
  if (r.hasAttribute(`${u.prefix}${t}-prevent`) && e.preventDefault(), this.deferred) {
11863
11934
  this.deferredProcedures.push(() => {
@@ -11880,15 +11951,7 @@ const fe = class fe {
11880
11951
  const i = N.get(e);
11881
11952
  if (!i)
11882
11953
  return;
11883
- if ((t === "change" || t === "input") && i instanceof T && (i.syncValue(), i.markUserEdit(), e instanceof HTMLInputElement && e.type === "radio" && e.name)) {
11884
- const s = document.getElementsByName(e.name);
11885
- for (const a of Array.from(s)) {
11886
- if (a === e || !(a instanceof HTMLInputElement) || a.type !== "radio" || a.form !== e.form)
11887
- continue;
11888
- const o = N.get(a);
11889
- o instanceof T && (o.syncValue(), o.markUserEdit());
11890
- }
11891
- }
11954
+ (t === "change" || t === "input") && this.syncUserEdit(e);
11892
11955
  const n = () => {
11893
11956
  new ee(i, t, r).run().catch((s) => {
11894
11957
  m.error("[Haori]", "Procedure execution error:", s);
@@ -11900,6 +11963,49 @@ const fe = class fe {
11900
11963
  }
11901
11964
  n();
11902
11965
  }
11966
+ /**
11967
+ * 手続きを起動しない `input` について、ユーザー編集だけを記録します。
11968
+ *
11969
+ * `data-input-*` を宣言していない入力欄でも、打鍵は編集として記録しなければ
11970
+ * なりません(記録しないと、反映待ちの書き込みが打鍵の後に着弾して打った文字を
11971
+ * 消します)。初期化中は手続きと同じく保留し、フラグメントが確定した後に記録
11972
+ * します。
11973
+ *
11974
+ * 対象は値を持つ入力要素だけです。`contenteditable` など値収集の対象でない要素で
11975
+ * `input` が発火しても、記録すべき編集はありません。
11976
+ *
11977
+ * @param element 編集された要素
11978
+ * @returns 戻り値はない。
11979
+ */
11980
+ recordUserEdit(e) {
11981
+ if (!(!(e instanceof HTMLInputElement) && !(e instanceof HTMLSelectElement) && !(e instanceof HTMLTextAreaElement))) {
11982
+ if (this.deferred) {
11983
+ this.deferredProcedures.push(() => {
11984
+ e.isConnected && this.syncUserEdit(e);
11985
+ });
11986
+ return;
11987
+ }
11988
+ this.syncUserEdit(e);
11989
+ }
11990
+ }
11991
+ /**
11992
+ * `change` / `input` の対象要素について、内部値の同期とユーザー編集の記録を行います。
11993
+ *
11994
+ * @param element 編集された要素
11995
+ * @returns 戻り値はない。
11996
+ */
11997
+ syncUserEdit(e) {
11998
+ const t = N.get(e);
11999
+ if (t instanceof T && (t.syncValue(), t.markUserEdit(), e instanceof HTMLInputElement && e.type === "radio" && e.name)) {
12000
+ const r = document.getElementsByName(e.name);
12001
+ for (const i of Array.from(r)) {
12002
+ if (i === e || !(i instanceof HTMLInputElement) || i.type !== "radio" || i.form !== e.form)
12003
+ continue;
12004
+ const n = N.get(i);
12005
+ n instanceof T && (n.syncValue(), n.markUserEdit());
12006
+ }
12007
+ }
12008
+ }
11903
12009
  /**
11904
12010
  * イベントのターゲットから HTMLElement を取得します。
11905
12011
  *
@@ -11949,7 +12055,7 @@ fe.HISTORY_STATE_KEY = "__haoriHistoryState__", fe.BUILTIN_EVENT_NAMES = /* @__P
11949
12055
  "input",
11950
12056
  "load"
11951
12057
  ]);
11952
- let Be = fe;
12058
+ let Le = fe;
11953
12059
  const U = class U {
11954
12060
  /**
11955
12061
  * ノードが現在の Window に属する HTMLElement かどうかを判定します。
@@ -12622,11 +12728,11 @@ w.CONFIG_KEYS = /* @__PURE__ */ new Set([
12622
12728
  "state"
12623
12729
  ]), w.DEFAULT_INTERVAL_MS = 5e3, w.MIN_INTERVAL_MS = 100, w.registrations = /* @__PURE__ */ new Map(), w.visibilityListener = null;
12624
12730
  let ce = w;
12625
- const Ht = "0.41.0";
12731
+ const Ht = "0.41.2";
12626
12732
  function Ut(g) {
12627
12733
  typeof requestAnimationFrame == "function" ? requestAnimationFrame(() => g()) : Promise.resolve().then(g);
12628
12734
  }
12629
- const L = class L {
12735
+ const B = class B {
12630
12736
  /**
12631
12737
  * ノードが現在の Window に属する HTMLElement かどうかを判定します。
12632
12738
  *
@@ -12645,8 +12751,8 @@ const L = class L {
12645
12751
  * @param root 走査の起点ノード
12646
12752
  */
12647
12753
  static syncTree(e) {
12648
- (e instanceof Element || e instanceof DocumentFragment) && (L.isHtmlElement(e) && L.syncElement(e), e.querySelectorAll("*").forEach((t) => {
12649
- L.syncElement(t);
12754
+ (e instanceof Element || e instanceof DocumentFragment) && (B.isHtmlElement(e) && B.syncElement(e), e.querySelectorAll("*").forEach((t) => {
12755
+ B.syncElement(t);
12650
12756
  }));
12651
12757
  }
12652
12758
  /**
@@ -12656,42 +12762,42 @@ const L = class L {
12656
12762
  * @param element 対象要素
12657
12763
  */
12658
12764
  static syncElement(e) {
12659
- const t = L.registrations.get(e), r = N.get(e);
12660
- if (!(r instanceof T) || !L.shouldObserve(r)) {
12661
- t && (t.observer.disconnect(), L.registrations.delete(e));
12765
+ const t = B.registrations.get(e), r = N.get(e);
12766
+ if (!(r instanceof T) || !B.shouldObserve(r)) {
12767
+ t && (t.observer.disconnect(), B.registrations.delete(e));
12662
12768
  return;
12663
12769
  }
12664
12770
  if (typeof IntersectionObserver > "u")
12665
12771
  return;
12666
- const i = L.resolveVarName(r);
12772
+ const i = B.resolveVarName(r);
12667
12773
  if (i === "") {
12668
- t && (t.observer.disconnect(), L.registrations.delete(e)), m.warn(
12774
+ t && (t.observer.disconnect(), B.registrations.delete(e)), m.warn(
12669
12775
  "[Haori]",
12670
12776
  'data-each-visible requires a variable name (e.g. data-each-visible="visibleRange").'
12671
12777
  );
12672
12778
  return;
12673
12779
  }
12674
- const n = L.resolveRoot(r), s = L.resolveRootMargin(r);
12780
+ const n = B.resolveRoot(r), s = B.resolveRootMargin(r);
12675
12781
  if (t && t.observer.root === n && t.observer.rootMargin === s && t.varName === i) {
12676
- t.fragment = r, L.refreshRows(t);
12782
+ t.fragment = r, B.refreshRows(t);
12677
12783
  return;
12678
12784
  }
12679
- t && (t.observer.disconnect(), L.registrations.delete(e));
12785
+ t && (t.observer.disconnect(), B.registrations.delete(e));
12680
12786
  const a = new IntersectionObserver(
12681
12787
  (l) => {
12682
- const c = L.registrations.get(e);
12788
+ const c = B.registrations.get(e);
12683
12789
  if (!c)
12684
12790
  return;
12685
12791
  let d = !1;
12686
12792
  l.forEach((h) => {
12687
12793
  const y = h.target;
12688
12794
  c.observedRows.has(y) && (h.isIntersecting ? c.visibleRows.has(y) || (c.visibleRows.add(y), d = !0) : c.visibleRows.delete(y) && (d = !0));
12689
- }), d && L.scheduleCompute(c);
12795
+ }), d && B.scheduleCompute(c);
12690
12796
  },
12691
12797
  {
12692
12798
  root: n,
12693
12799
  rootMargin: s,
12694
- threshold: L.THRESHOLD
12800
+ threshold: B.THRESHOLD
12695
12801
  }
12696
12802
  ), o = {
12697
12803
  fragment: r,
@@ -12704,7 +12810,7 @@ const L = class L {
12704
12810
  scheduled: !1,
12705
12811
  lastSnapshot: null
12706
12812
  };
12707
- L.registrations.set(e, o), L.refreshRows(o);
12813
+ B.registrations.set(e, o), B.refreshRows(o);
12708
12814
  }
12709
12815
  /**
12710
12816
  * 指定ノード配下の監視登録を解放します。
@@ -12712,22 +12818,22 @@ const L = class L {
12712
12818
  * @param root 走査の起点ノード
12713
12819
  */
12714
12820
  static cleanupTree(e) {
12715
- if (L.isHtmlElement(e)) {
12716
- const t = L.registrations.get(e);
12717
- t && (t.observer.disconnect(), L.registrations.delete(e));
12821
+ if (B.isHtmlElement(e)) {
12822
+ const t = B.registrations.get(e);
12823
+ t && (t.observer.disconnect(), B.registrations.delete(e));
12718
12824
  }
12719
12825
  (e instanceof Element || e instanceof DocumentFragment) && e.querySelectorAll("*").forEach((t) => {
12720
- const r = L.registrations.get(t);
12721
- r && (r.observer.disconnect(), L.registrations.delete(t));
12826
+ const r = B.registrations.get(t);
12827
+ r && (r.observer.disconnect(), B.registrations.delete(t));
12722
12828
  });
12723
12829
  }
12724
12830
  /**
12725
12831
  * すべての監視登録を解放します。
12726
12832
  */
12727
12833
  static disconnectAll() {
12728
- L.registrations.forEach((e) => {
12834
+ B.registrations.forEach((e) => {
12729
12835
  e.observer.disconnect();
12730
- }), L.registrations.clear();
12836
+ }), B.registrations.clear();
12731
12837
  }
12732
12838
  /**
12733
12839
  * 監視対象(`data-each` かつ `data-each-visible`)かどうかを判定します。
@@ -12762,7 +12868,7 @@ const L = class L {
12762
12868
  if (typeof r != "string" || r.trim() === "")
12763
12869
  return null;
12764
12870
  const i = z.query(r, t, document);
12765
- return L.isHtmlElement(i) ? i : (m.error("[Haori]", `Visible range root element not found: ${r}`), null);
12871
+ return B.isHtmlElement(i) ? i : (m.error("[Haori]", `Visible range root element not found: ${r}`), null);
12766
12872
  }
12767
12873
  /**
12768
12874
  * rootMargin を解決します。
@@ -12772,7 +12878,7 @@ const L = class L {
12772
12878
  */
12773
12879
  static resolveRootMargin(e) {
12774
12880
  const t = `${u.prefix}each-visible-margin`, r = e.getAttribute(t);
12775
- return r === null || r === !1 || r === "" ? L.DEFAULT_ROOT_MARGIN : String(r);
12881
+ return r === null || r === !1 || r === "" ? B.DEFAULT_ROOT_MARGIN : String(r);
12776
12882
  }
12777
12883
  /**
12778
12884
  * コンテナ直下の実際の行要素(`each-before`/`each-after` を除く)を描画順で返します。
@@ -12792,12 +12898,12 @@ const L = class L {
12792
12898
  * @param registration 対象の登録
12793
12899
  */
12794
12900
  static refreshRows(e) {
12795
- const t = L.realRowElements(e.fragment), r = new Set(t);
12901
+ const t = B.realRowElements(e.fragment), r = new Set(t);
12796
12902
  for (const i of [...e.observedRows])
12797
12903
  r.has(i) || (e.observer.unobserve(i), e.observedRows.delete(i), e.visibleRows.delete(i));
12798
12904
  for (const i of t)
12799
12905
  e.observedRows.has(i) || (e.observer.observe(i), e.observedRows.add(i));
12800
- L.scheduleCompute(e);
12906
+ B.scheduleCompute(e);
12801
12907
  }
12802
12908
  /**
12803
12909
  * 次フレームでの集計・公開を予約します(多発する交差イベントを 1 回にまとめる)。
@@ -12808,7 +12914,7 @@ const L = class L {
12808
12914
  e.scheduled || (e.scheduled = !0, Ut(() => {
12809
12915
  e.scheduled = !1;
12810
12916
  const t = e.fragment.getTarget();
12811
- L.registrations.get(t) === e && L.computeAndPublish(e);
12917
+ B.registrations.get(t) === e && B.computeAndPublish(e);
12812
12918
  }));
12813
12919
  }
12814
12920
  /**
@@ -12817,7 +12923,7 @@ const L = class L {
12817
12923
  * @param registration 対象の登録
12818
12924
  */
12819
12925
  static computeAndPublish(e) {
12820
- const t = L.realRowElements(e.fragment), r = /* @__PURE__ */ new Map();
12926
+ const t = B.realRowElements(e.fragment), r = /* @__PURE__ */ new Map();
12821
12927
  t.forEach((a, o) => r.set(a, o));
12822
12928
  const i = [];
12823
12929
  for (const a of e.visibleRows) {
@@ -12850,7 +12956,7 @@ const L = class L {
12850
12956
  };
12851
12957
  }
12852
12958
  const s = JSON.stringify(n);
12853
- s !== e.lastSnapshot && (e.lastSnapshot = s, L.publish(e, n));
12959
+ s !== e.lastSnapshot && (e.lastSnapshot = s, B.publish(e, n));
12854
12960
  }
12855
12961
  /**
12856
12962
  * 可視範囲スナップショットを最近接の上位 `data-bind` スコープへ公開します。
@@ -12859,7 +12965,7 @@ const L = class L {
12859
12965
  * @param snapshot 公開するスナップショット
12860
12966
  */
12861
12967
  static publish(e, t) {
12862
- const r = L.resolveBindOwner(e.fragment);
12968
+ const r = B.resolveBindOwner(e.fragment);
12863
12969
  if (!r) {
12864
12970
  m.warn(
12865
12971
  "[Haori]",
@@ -12901,8 +13007,8 @@ const L = class L {
12901
13007
  return e.hasAttribute(t) ? e : null;
12902
13008
  }
12903
13009
  };
12904
- L.THRESHOLD = 0, L.DEFAULT_ROOT_MARGIN = "0px", L.registrations = /* @__PURE__ */ new Map();
12905
- let se = L;
13010
+ B.THRESHOLD = 0, B.DEFAULT_ROOT_MARGIN = "0px", B.registrations = /* @__PURE__ */ new Map();
13011
+ let se = B;
12906
13012
  const K = class K {
12907
13013
  /**
12908
13014
  * 既存の MutationObserver をすべて停止します。
@@ -12922,7 +13028,7 @@ const K = class K {
12922
13028
  K._initialized = !0, K.disconnectMutationObservers(), T.setPendingMutationFlusher(() => {
12923
13029
  K.flushPendingMutations();
12924
13030
  });
12925
- const e = new Be();
13031
+ const e = new Le();
12926
13032
  K._dispatcher = e, e.startDeferred();
12927
13033
  try {
12928
13034
  const t = await Promise.allSettled([