haori 0.22.2 → 0.23.0

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
@@ -1320,7 +1320,7 @@ const me = class me {
1320
1320
  }
1321
1321
  };
1322
1322
  me.ASYNC_QUEUE = new ge();
1323
- let P = me;
1323
+ let k = me;
1324
1324
  const F = class F {
1325
1325
  /**
1326
1326
  * 集計状態を初期化します。
@@ -1595,7 +1595,7 @@ const X = class X {
1595
1595
  return Promise.resolve();
1596
1596
  if (this.parent) {
1597
1597
  const e = this.parent, t = e.skipMutationNodes;
1598
- return P.enqueue(() => {
1598
+ return k.enqueue(() => {
1599
1599
  e.skipMutationNodes = !0, this.target.parentNode === e.getTarget() && e.getTarget().removeChild(this.target), this.mounted = !1;
1600
1600
  }).finally(() => {
1601
1601
  e.skipMutationNodes = t;
@@ -1603,7 +1603,7 @@ const X = class X {
1603
1603
  } else {
1604
1604
  const e = this.target.parentNode;
1605
1605
  if (e)
1606
- return P.enqueue(() => {
1606
+ return k.enqueue(() => {
1607
1607
  this.target.parentNode === e && e.removeChild(this.target), this.mounted = !1;
1608
1608
  });
1609
1609
  this.mounted = !1;
@@ -1620,7 +1620,7 @@ const X = class X {
1620
1620
  return Promise.resolve();
1621
1621
  if (this.parent) {
1622
1622
  const e = this.parent, t = e.skipMutationNodes;
1623
- return P.enqueue(() => {
1623
+ return k.enqueue(() => {
1624
1624
  e.skipMutationNodes = !0, this.target.parentNode !== e.getTarget() && e.getTarget().appendChild(this.target), this.mounted = !0;
1625
1625
  }).finally(() => {
1626
1626
  e.skipMutationNodes = t;
@@ -2092,14 +2092,25 @@ const K = class K extends T {
2092
2092
  if (r instanceof HTMLInputElement && (r.type === "checkbox" || r.type === "radio")) {
2093
2093
  const i = this.getAttribute("value"), n = r.type === "checkbox" && i === "true";
2094
2094
  let s;
2095
- return n ? s = e === !0 || e === "true" : i === "false" ? s = e === !1 : Array.isArray(e) ? s = e.map(String).includes(String(i)) : s = i === String(e), n ? this.value = s : s ? Array.isArray(e) ? this.value = String(i) : this.value = e : this.value = null, r.checked === s ? Promise.resolve() : (this.skipChangeValue = !0, P.enqueue(() => {
2095
+ return n ? s = e === !0 || e === "true" : i === "false" ? s = e === !1 : Array.isArray(e) ? s = e.map(String).includes(String(i)) : s = i === String(e), n ? this.value = s : s ? Array.isArray(e) ? this.value = String(i) : this.value = e : this.value = null, r.checked === s ? Promise.resolve() : (this.skipChangeValue = !0, k.enqueue(() => {
2096
2096
  r.checked = s, t && r.dispatchEvent(new Event("change", { bubbles: !0 }));
2097
2097
  }).finally(() => {
2098
2098
  this.skipChangeValue = !1;
2099
2099
  }));
2100
+ } else if (r instanceof HTMLSelectElement && r.multiple) {
2101
+ const i = (Array.isArray(e) ? e : e === null ? [] : [e]).map(String);
2102
+ return this.value = i.slice(), this.skipChangeValue = !0, k.enqueue(() => {
2103
+ let n = !1;
2104
+ Array.from(r.options).forEach((s) => {
2105
+ const a = i.includes(s.value);
2106
+ s.selected !== a && (s.selected = a, n = !0);
2107
+ }), n && t && r.dispatchEvent(new Event("change", { bubbles: !0 }));
2108
+ }).finally(() => {
2109
+ this.skipChangeValue = !1;
2110
+ });
2100
2111
  } else if (r instanceof HTMLInputElement || r instanceof HTMLTextAreaElement || r instanceof HTMLSelectElement) {
2101
2112
  const i = Array.isArray(e) ? e.join(",") : e;
2102
- return this.value = this.normalizeValueForElement(r, i), this.skipChangeValue = !0, P.enqueue(() => {
2113
+ return this.value = this.normalizeValueForElement(r, i), this.skipChangeValue = !0, k.enqueue(() => {
2103
2114
  r.value = i === null ? "" : String(i), t && ((r instanceof HTMLInputElement && this.INPUT_EVENT_TYPES.includes(r.type) || r instanceof HTMLTextAreaElement) && r.dispatchEvent(new Event("input", { bubbles: !0 })), r.dispatchEvent(new Event("change", { bubbles: !0 })));
2104
2115
  }).finally(() => {
2105
2116
  this.skipChangeValue = !1;
@@ -2164,7 +2175,9 @@ const K = class K extends T {
2164
2175
  }
2165
2176
  } else
2166
2177
  this.value = this.normalizeValueForElement(e, e.value);
2167
- else e instanceof HTMLTextAreaElement ? this.value = e.value : e instanceof HTMLSelectElement && (this.value = e.value);
2178
+ else e instanceof HTMLTextAreaElement ? this.value = e.value : e instanceof HTMLSelectElement && (e.multiple ? this.value = Array.from(e.selectedOptions).map(
2179
+ (t) => t.value
2180
+ ) : this.value = e.value);
2168
2181
  }
2169
2182
  /**
2170
2183
  * 属性の値を評価して設定します。
@@ -2207,7 +2220,7 @@ const K = class K extends T {
2207
2220
  return Promise.resolve();
2208
2221
  this.attributeMap.delete(e), this.skipMutationAttributes = !0;
2209
2222
  const r = this.getTarget();
2210
- return P.enqueue(() => {
2223
+ return k.enqueue(() => {
2211
2224
  r.removeAttribute(e), t !== e && r.removeAttribute(t);
2212
2225
  }).finally(() => {
2213
2226
  this.skipMutationAttributes = !1;
@@ -2231,7 +2244,7 @@ const K = class K extends T {
2231
2244
  if (n) {
2232
2245
  const ce = this.attributeMap.get(e);
2233
2246
  if (ce && (ce.isEvaluate || ce.isForceEvaluation()) && !s.isEvaluate && !s.isForceEvaluation())
2234
- return this.skipMutationAttributes = !0, P.enqueue(() => {
2247
+ return this.skipMutationAttributes = !0, k.enqueue(() => {
2235
2248
  }).finally(() => {
2236
2249
  this.skipMutationAttributes = !1;
2237
2250
  });
@@ -2242,9 +2255,9 @@ const K = class K extends T {
2242
2255
  element: a,
2243
2256
  rawName: e,
2244
2257
  template: r
2245
- }), l = s.isEvaluate || s.isRawEvaluate, h = e === t && K.BOOLEAN_ATTRIBUTES.has(t.toLowerCase()), u = s.isSingleExpression(), p = G.joinEvaluateResults(o.results), v = o.results.length === 1 ? o.results[0] : p, R = !s.isForceEvaluation() && (t !== e || h || u ? o.hasUnresolvedReference || v === null || v === void 0 || v === !1 : l && p === ""), I = s.isForceEvaluation() ? r : u ? v : p, A = i && s.isEvaluate && t === "value" && (a instanceof HTMLInputElement && this.INPUT_EVENT_TYPES.includes(a.type) || a instanceof HTMLTextAreaElement || a instanceof HTMLSelectElement), y = a.getRootNode(), b = A && a === y.activeElement, S = R || I === null || I === !1 ? null : String(I), k = e !== t && a.getAttribute(e) !== r, C = S === null ? a.hasAttribute(t) : a.getAttribute(t) !== S, O = A && !b && S !== null && a.value !== S, j = t === "checked" && a instanceof HTMLInputElement && (a.type === "checkbox" || a.type === "radio"), $ = t === "selected" && a instanceof HTMLOptionElement, _ = y.activeElement, be = _ !== null && (j && a === _ || $ && a.closest("select") === _), te = S !== null, ve = j && !be && a.checked !== te, ye = $ && !be && a.selected !== te;
2246
- return !k && !C && !O && !ve && !ye ? (A && !b && S !== null && (this.value = this.normalizeValueForElement(a, S)), Promise.resolve()) : (this.skipMutationAttributes = !0, P.enqueue(() => {
2247
- k && a.setAttribute(e, r), S === null ? a.removeAttribute(t) : (C && (a.setAttribute(t, S), t === `${c.prefix}bind` && this.recordSelfWrittenBind(S)), A && !b && (this.value = this.normalizeValueForElement(a, S), O && (a.value = S))), ve && (a.checked = te), ye && (a.selected = te);
2258
+ }), l = s.isEvaluate || s.isRawEvaluate, h = e === t && K.BOOLEAN_ATTRIBUTES.has(t.toLowerCase()), u = s.isSingleExpression(), p = G.joinEvaluateResults(o.results), v = o.results.length === 1 ? o.results[0] : p, R = !s.isForceEvaluation() && (t !== e || h || u ? o.hasUnresolvedReference || v === null || v === void 0 || v === !1 : l && p === ""), I = s.isForceEvaluation() ? r : u ? v : p, A = i && s.isEvaluate && t === "value" && (a instanceof HTMLInputElement && this.INPUT_EVENT_TYPES.includes(a.type) || a instanceof HTMLTextAreaElement || a instanceof HTMLSelectElement), y = a.getRootNode(), b = A && a === y.activeElement, S = R || I === null || I === !1 ? null : String(I), P = e !== t && a.getAttribute(e) !== r, C = S === null ? a.hasAttribute(t) : a.getAttribute(t) !== S, O = A && !b && S !== null && a.value !== S, j = t === "checked" && a instanceof HTMLInputElement && (a.type === "checkbox" || a.type === "radio"), $ = t === "selected" && a instanceof HTMLOptionElement, ee = y.activeElement, be = ee !== null && (j && a === ee || $ && a.closest("select") === ee), te = S !== null, ve = j && !be && a.checked !== te, ye = $ && !be && a.selected !== te;
2259
+ return !P && !C && !O && !ve && !ye ? (A && !b && S !== null && (this.value = this.normalizeValueForElement(a, S)), Promise.resolve()) : (this.skipMutationAttributes = !0, k.enqueue(() => {
2260
+ P && a.setAttribute(e, r), S === null ? a.removeAttribute(t) : (C && (a.setAttribute(t, S), t === `${c.prefix}bind` && this.recordSelfWrittenBind(S)), A && !b && (this.value = this.normalizeValueForElement(a, S), O && (a.value = S))), ve && (a.checked = te), ye && (a.selected = te);
2248
2261
  }).finally(() => {
2249
2262
  this.skipMutationAttributes = !1;
2250
2263
  }));
@@ -2260,7 +2273,7 @@ const K = class K extends T {
2260
2273
  return Promise.resolve();
2261
2274
  this.attributeMap.delete(e), this.skipMutationAttributes = !0;
2262
2275
  const t = this.getTarget();
2263
- return P.enqueue(() => {
2276
+ return k.enqueue(() => {
2264
2277
  t.removeAttribute(e);
2265
2278
  }).finally(() => {
2266
2279
  this.skipMutationAttributes = !1;
@@ -2395,7 +2408,7 @@ const K = class K extends T {
2395
2408
  }
2396
2409
  e.setParent(this), e.setMounted(this.mounted);
2397
2410
  const u = this.skipMutationNodes;
2398
- return this.skipMutationNodes = !0, P.enqueue(() => {
2411
+ return this.skipMutationNodes = !0, k.enqueue(() => {
2399
2412
  this.target.insertBefore(e.getTarget(), h);
2400
2413
  }).finally(() => {
2401
2414
  this.skipMutationNodes = u;
@@ -2582,7 +2595,7 @@ class V extends T {
2582
2595
  evaluate() {
2583
2596
  return this.contents.isRawEvaluate && this.parent === null ? Promise.reject(
2584
2597
  new Error("Parent fragment is required for raw evaluation")
2585
- ) : P.enqueue(() => {
2598
+ ) : k.enqueue(() => {
2586
2599
  this.skipMutation = !0;
2587
2600
  let e = this.text;
2588
2601
  this.contents.isRawEvaluate ? e = this.contents.evaluate(
@@ -2642,7 +2655,7 @@ class pe extends T {
2642
2655
  * @return 更新のPromise
2643
2656
  */
2644
2657
  setContent(e) {
2645
- return this.skipMutation || this.text === e ? Promise.resolve() : (this.text = e, P.enqueue(() => {
2658
+ return this.skipMutation || this.text === e ? Promise.resolve() : (this.text = e, k.enqueue(() => {
2646
2659
  this.skipMutation = !0, this.target.textContent = this.text;
2647
2660
  }).finally(() => {
2648
2661
  this.skipMutation = !1;
@@ -2846,7 +2859,7 @@ le.FORCE_EVALUATION_ATTRIBUTES = [
2846
2859
  "hor-derive"
2847
2860
  ];
2848
2861
  let se = le;
2849
- class ee {
2862
+ class Q {
2850
2863
  /**
2851
2864
  * 実行モードを取得します。
2852
2865
  *
@@ -2876,7 +2889,7 @@ class ee {
2876
2889
  * @return すべてのレンダリングが完了したら解決される Promise
2877
2890
  */
2878
2891
  static waitForRenders() {
2879
- return P.waitForIdle();
2892
+ return k.waitForIdle();
2880
2893
  }
2881
2894
  /**
2882
2895
  * 通知ダイアログを表示します。
@@ -2885,7 +2898,7 @@ class ee {
2885
2898
  * @returns 通知が閉じられると解決されるPromise
2886
2899
  */
2887
2900
  static dialog(e) {
2888
- return P.enqueue(() => {
2901
+ return k.enqueue(() => {
2889
2902
  window.alert(e);
2890
2903
  }, !0);
2891
2904
  }
@@ -2913,7 +2926,7 @@ class ee {
2913
2926
  * @returns ユーザーがOKをクリックした場合はtrue、キャンセルした場合はfalseが解決されるPromise
2914
2927
  */
2915
2928
  static confirm(e) {
2916
- return P.enqueue(() => window.confirm(e), !0);
2929
+ return k.enqueue(() => window.confirm(e), !0);
2917
2930
  }
2918
2931
  /**
2919
2932
  * ダイアログを開きます。
@@ -2921,8 +2934,8 @@ class ee {
2921
2934
  * @param element 開くダイアログのHTML要素
2922
2935
  */
2923
2936
  static openDialog(e) {
2924
- return P.enqueue(() => {
2925
- e instanceof HTMLDialogElement ? e.showModal() : m.error("[Haori]", "Element is not a dialog: ", e);
2937
+ return k.enqueue(() => {
2938
+ e instanceof HTMLDialogElement ? (Q.clearMessagesSync(e), e.showModal()) : m.error("[Haori]", "Element is not a dialog: ", e);
2926
2939
  }, !0);
2927
2940
  }
2928
2941
  /**
@@ -2931,7 +2944,7 @@ class ee {
2931
2944
  * @param element 閉じるダイアログのHTML要素
2932
2945
  */
2933
2946
  static closeDialog(e) {
2934
- return P.enqueue(() => {
2947
+ return k.enqueue(() => {
2935
2948
  e instanceof HTMLDialogElement ? e.close() : m.error("[Haori]", "Element is not a dialog: ", e);
2936
2949
  }, !0);
2937
2950
  }
@@ -2942,7 +2955,7 @@ class ee {
2942
2955
  * @param message エラーメッセージ
2943
2956
  */
2944
2957
  static addErrorMessage(e, t) {
2945
- return ee.addMessage(e, t, "error");
2958
+ return Q.addMessage(e, t, "error");
2946
2959
  }
2947
2960
  /**
2948
2961
  * メッセージをレベル付きで追加します。
@@ -2952,7 +2965,7 @@ class ee {
2952
2965
  * @param level メッセージのレベル(省略可能)
2953
2966
  */
2954
2967
  static addMessage(e, t, r) {
2955
- return P.enqueue(() => {
2968
+ return k.enqueue(() => {
2956
2969
  const i = e instanceof HTMLFormElement ? e : e.parentElement ?? e;
2957
2970
  i.setAttribute("data-message", t), r !== void 0 ? i.setAttribute("data-message-level", r) : i.removeAttribute("data-message-level");
2958
2971
  }, !0);
@@ -2963,12 +2976,23 @@ class ee {
2963
2976
  * @param parent メッセージをクリアする親要素
2964
2977
  */
2965
2978
  static clearMessages(e) {
2966
- return P.enqueue(() => {
2967
- e.removeAttribute("data-message"), e.removeAttribute("data-message-level"), e.querySelectorAll("[data-message]").forEach((t) => {
2968
- t.removeAttribute("data-message"), t.removeAttribute("data-message-level");
2969
- });
2979
+ return k.enqueue(() => {
2980
+ Q.clearMessagesSync(e);
2970
2981
  }, !0);
2971
2982
  }
2983
+ /**
2984
+ * 対象のエレメントおよびその子要素のメッセージ属性を同期的に除去します。
2985
+ *
2986
+ * Queue を介さないため、別の enqueue ブロック内から実行順を保ったまま
2987
+ * 呼び出せます。{@link clearMessages} および {@link openDialog} の共通処理です。
2988
+ *
2989
+ * @param parent メッセージをクリアする親要素
2990
+ */
2991
+ static clearMessagesSync(e) {
2992
+ e.removeAttribute("data-message"), e.removeAttribute("data-message-level"), e.querySelectorAll("[data-message]").forEach((t) => {
2993
+ t.removeAttribute("data-message"), t.removeAttribute("data-message-level");
2994
+ });
2995
+ }
2972
2996
  /**
2973
2997
  * 日時を指定フォーマットの文字列へ整形します。
2974
2998
  *
@@ -3115,7 +3139,7 @@ function Ae() {
3115
3139
  const e = globalThis.window?.Haori;
3116
3140
  return Ke.every(
3117
3141
  (r) => typeof e?.[r] == "function"
3118
- ) ? e : ee;
3142
+ ) ? e : Q;
3119
3143
  }
3120
3144
  class E {
3121
3145
  /**
@@ -3209,6 +3233,16 @@ class E {
3209
3233
  const t = e.getTarget();
3210
3234
  return t instanceof HTMLInputElement ? t.type === "radio" ? !0 : t.type !== "checkbox" ? !1 : t.value !== "true" && t.value !== "false" : !1;
3211
3235
  }
3236
+ /**
3237
+ * 複数選択の select 要素かどうかを判定します。
3238
+ *
3239
+ * @param fragment 対象フラグメント
3240
+ * @returns `<select multiple>` の場合 true
3241
+ */
3242
+ static isMultipleSelect(e) {
3243
+ const t = e.getTarget();
3244
+ return t instanceof HTMLSelectElement && t.multiple;
3245
+ }
3212
3246
  /**
3213
3247
  * 単一フラグメントへ値を設定します。
3214
3248
  *
@@ -3236,7 +3270,7 @@ class E {
3236
3270
  const u = t[String(a)];
3237
3271
  l && Array.isArray(u) && r !== null ? s.push(
3238
3272
  E.applyFragmentValue(e, u[r] ?? null, n)
3239
- ) : typeof u > "u" || (Array.isArray(u) && E.isGroupedCheckable(e) || typeof u == "string" || typeof u == "number" || typeof u == "boolean" || u === null ? s.push(
3273
+ ) : typeof u > "u" || (Array.isArray(u) && E.isGroupedCheckable(e) || Array.isArray(u) && E.isMultipleSelect(e) || typeof u == "string" || typeof u == "number" || typeof u == "boolean" || u === null ? s.push(
3240
3274
  E.applyFragmentValue(
3241
3275
  e,
3242
3276
  u,
@@ -3295,7 +3329,7 @@ class E {
3295
3329
  E.clearValues(e), await Promise.all([
3296
3330
  E.clearMessages(e),
3297
3331
  E.clearEachClones(e)
3298
- ]), await P.enqueue(() => {
3332
+ ]), await k.enqueue(() => {
3299
3333
  const r = e.getTarget();
3300
3334
  if (r instanceof HTMLFormElement)
3301
3335
  r.reset();
@@ -3530,14 +3564,6 @@ class N {
3530
3564
  static ready(e) {
3531
3565
  N.dispatch(document, "ready", { version: e });
3532
3566
  }
3533
- /**
3534
- * renderイベントを発火します。
3535
- *
3536
- * @param target 評価対象要素
3537
- */
3538
- static render(e) {
3539
- N.dispatch(e, "render", { target: e });
3540
- }
3541
3567
  /**
3542
3568
  * importstartイベントを発火します。
3543
3569
  *
@@ -3833,7 +3859,7 @@ function ie() {
3833
3859
  const e = globalThis.window?.Haori;
3834
3860
  return Xe.every(
3835
3861
  (r) => typeof e?.[r] == "function"
3836
- ) ? e : ee;
3862
+ ) ? e : Q;
3837
3863
  }
3838
3864
  const Ze = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS"]);
3839
3865
  function _e(f) {
@@ -4270,8 +4296,8 @@ ${y}
4270
4296
  );
4271
4297
  if (b) {
4272
4298
  const S = document.body.querySelectorAll(b);
4273
- S.length > 0 ? (r.adjustFragments = [], S.forEach((k) => {
4274
- const C = T.get(k);
4299
+ S.length > 0 ? (r.adjustFragments = [], S.forEach((P) => {
4300
+ const C = T.get(P);
4275
4301
  C && r.adjustFragments.push(C);
4276
4302
  })) : m.error(
4277
4303
  "Haori",
@@ -4281,8 +4307,8 @@ ${y}
4281
4307
  if (e.hasAttribute(g.attrName(t, "adjust-value"))) {
4282
4308
  const S = e.getRawAttribute(
4283
4309
  g.attrName(t, "adjust-value")
4284
- ), k = Number(S);
4285
- isNaN(k) || (r.adjustValue = k);
4310
+ ), P = Number(S);
4311
+ isNaN(P) || (r.adjustValue = P);
4286
4312
  }
4287
4313
  }
4288
4314
  if (e.hasAttribute(g.attrName(t, "row-add")) && (r.rowAdd = !0), e.hasAttribute(g.attrName(t, "row-remove")) && (r.rowRemove = !0), e.hasAttribute(g.attrName(t, "row-prev")) && (r.rowMovePrev = !0), e.hasAttribute(g.attrName(t, "row-next")) && (r.rowMoveNext = !0), e.hasAttribute(`${c.prefix}${t}-after-run`)) {
@@ -4308,8 +4334,8 @@ ${b}
4308
4334
  );
4309
4335
  const b = e.getRawAttribute(
4310
4336
  g.attrName(t, "toast-level")
4311
- ), k = ["info", "warning", "error", "success"].includes(b);
4312
- r.toastLevel = k ? b : null;
4337
+ ), P = ["info", "warning", "error", "success"].includes(b);
4338
+ r.toastLevel = P ? b : null;
4313
4339
  }
4314
4340
  if (e.hasAttribute(g.attrName(t, "redirect"))) {
4315
4341
  r.redirectUrl = e.getAttribute(
@@ -4354,12 +4380,12 @@ ${b}
4354
4380
  const S = g.attrName(t, b);
4355
4381
  if (!e.hasAttribute(S))
4356
4382
  return;
4357
- const k = e.getRawAttribute(S), C = [];
4358
- if (k)
4359
- document.body.querySelectorAll(k).forEach((j) => {
4383
+ const P = e.getRawAttribute(S), C = [];
4384
+ if (P)
4385
+ document.body.querySelectorAll(P).forEach((j) => {
4360
4386
  const $ = T.get(j);
4361
4387
  $ && C.push($);
4362
- }), C.length === 0 && m.error("Haori", `Element not found: ${k} (${S})`);
4388
+ }), C.length === 0 && m.error("Haori", `Element not found: ${P} (${S})`);
4363
4389
  else if (b === "open" || b === "close") {
4364
4390
  const O = e.getTarget().closest("dialog");
4365
4391
  O ? C.push(T.get(O)) : m.error("Haori", `Ancestor <dialog> not found (${S})`);
@@ -4398,8 +4424,8 @@ ${b}
4398
4424
  if (b) {
4399
4425
  const S = document.body.querySelector(b);
4400
4426
  if (S !== null) {
4401
- const k = T.get(S);
4402
- k ? r.copySourceFragment = k : m.error(
4427
+ const P = T.get(S);
4428
+ P ? r.copySourceFragment = P : m.error(
4403
4429
  "Haori",
4404
4430
  `Element is not managed by Haori: ${b} (${y})`
4405
4431
  );
@@ -5396,7 +5422,7 @@ const d = class d {
5396
5422
  const s = performance.now();
5397
5423
  return t.setAttribute(`${c.prefix}importing`, ""), N.importStart(t, n), nt.load(n).then((a) => {
5398
5424
  const o = new TextEncoder().encode(a).length;
5399
- return P.enqueue(() => {
5425
+ return k.enqueue(() => {
5400
5426
  t.innerHTML = a;
5401
5427
  }).then(() => {
5402
5428
  if (t.removeAttribute(`${c.prefix}importing`), N.importEnd(t, n, o, s), !document.body.hasAttribute("data-haori-ready")) {
@@ -6035,13 +6061,52 @@ const d = class d {
6035
6061
  do
6036
6062
  t.rerunRequested = !1, await d.performEachUpdate(e);
6037
6063
  while (t.rerunRequested);
6038
- e.getTarget().setAttribute(`${c.prefix}each-done`, "");
6064
+ const i = e.getTarget();
6065
+ i.setAttribute(`${c.prefix}each-done`, ""), d.runEachRenderedScript(i);
6039
6066
  } finally {
6040
6067
  t.running = !1, t.settled = null;
6041
6068
  }
6042
6069
  })();
6043
6070
  return t.settled = r, r;
6044
6071
  }
6072
+ /**
6073
+ * data-each-rendered-run 属性に指定された JS を、描画確定後に一度実行します。
6074
+ *
6075
+ * data-each の再描画が安定し `data-each-done` が付与されるたびに呼び出され、
6076
+ * 再 fetch・再バインドのたびに確実な再同期契機を提供します。本体内の `this`
6077
+ * は対象コンテナ要素に束縛され、外部の select 拡張ライブラリ(Choices.js 等)
6078
+ * の再同期フック(例: `window.__choicesRefresh(this)`)として利用できます。
6079
+ *
6080
+ * @param target data-each コンテナ要素
6081
+ */
6082
+ static runEachRenderedScript(e) {
6083
+ const t = `${c.prefix}each-rendered-run`;
6084
+ if (!e.hasAttribute(t))
6085
+ return;
6086
+ const r = String(e.getAttribute(t) ?? "");
6087
+ let i = null;
6088
+ try {
6089
+ i = new Function(
6090
+ `"use strict"; return (
6091
+ ${r}
6092
+ );`
6093
+ );
6094
+ } catch {
6095
+ try {
6096
+ i = new Function(`"use strict";
6097
+ ${r}
6098
+ `);
6099
+ } catch (n) {
6100
+ m.error("Haori", `Invalid each-rendered-run script: ${n}`);
6101
+ }
6102
+ }
6103
+ if (i)
6104
+ try {
6105
+ i.call(e);
6106
+ } catch (n) {
6107
+ m.error("Haori", `each-rendered-run execution error: ${n}`);
6108
+ }
6109
+ }
6045
6110
  /**
6046
6111
  * data-each の差分更新本体を実行します(再入制御は呼び出し側で行います)。
6047
6112
  *
@@ -6326,12 +6391,12 @@ const d = class d {
6326
6391
  i && (i = String(i));
6327
6392
  const n = e.getAttribute(`${c.prefix}each-key`), s = e.getAttribute(`${c.prefix}each-arg`), a = /* @__PURE__ */ new Map(), o = [];
6328
6393
  t.forEach((b, S) => {
6329
- const k = d.createListKey(
6394
+ const P = d.createListKey(
6330
6395
  b,
6331
6396
  n ? String(n) : null,
6332
6397
  S
6333
6398
  );
6334
- o.push(k), a.set(k, { item: b, itemIndex: S });
6399
+ o.push(P), a.set(P, { item: b, itemIndex: S });
6335
6400
  });
6336
6401
  const l = new Set(o), h = [];
6337
6402
  let u = e.getChildren().filter((b) => b instanceof M).filter(
@@ -6349,14 +6414,14 @@ const d = class d {
6349
6414
  ).length;
6350
6415
  let y = Promise.resolve();
6351
6416
  return o.forEach((b, S) => {
6352
- const { item: k, itemIndex: C } = a.get(b);
6417
+ const { item: P, itemIndex: C } = a.get(b);
6353
6418
  let O;
6354
6419
  const j = R.get(b);
6355
6420
  if (j)
6356
6421
  O = j, y = y.then(
6357
6422
  () => d.updateRowFragment(
6358
6423
  O,
6359
- k,
6424
+ P,
6360
6425
  i,
6361
6426
  C,
6362
6427
  s ? String(s) : null,
@@ -6372,14 +6437,14 @@ const d = class d {
6372
6437
  y = y.then(
6373
6438
  () => d.updateRowFragment(
6374
6439
  O,
6375
- k,
6440
+ P,
6376
6441
  i,
6377
6442
  C,
6378
6443
  s ? String(s) : null,
6379
6444
  b
6380
6445
  ).then(() => {
6381
- const _ = I[$] ?? null;
6382
- return e.insertBefore(O, _).then(() => {
6446
+ const ee = I[$] ?? null;
6447
+ return e.insertBefore(O, ee).then(() => {
6383
6448
  I.splice($, 0, O);
6384
6449
  }).then(() => d.initializeFreshEachRow(O));
6385
6450
  })
@@ -6390,7 +6455,7 @@ const d = class d {
6390
6455
  ($) => $ !== null
6391
6456
  ), S = v.filter(
6392
6457
  ($) => $ !== null
6393
- ), k = new Set(S), C = b.filter(($) => !k.has($)), j = p.filter(
6458
+ ), P = new Set(S), C = b.filter(($) => !P.has($)), j = p.filter(
6394
6459
  ($) => $ !== null
6395
6460
  ).filter(
6396
6461
  ($) => !l.has($)
@@ -6557,7 +6622,7 @@ d.ATTRIBUTE_ALIAS_SUFFIX = "attr-", d.PRIORITY_ATTRIBUTE_SUFFIXES = [
6557
6622
  "url-param"
6558
6623
  ], d.ATTRIBUTE_PLACEHOLDER_REGEX = /\{\{\{[\s\S]+?\}\}\}|\{\{[\s\S]+?\}\}/, d.REACTIVE_FETCH_STATES = /* @__PURE__ */ new WeakMap(), d.REACTIVE_IMPORT_STATES = /* @__PURE__ */ new WeakMap(), d.DERIVE_SUBTREE_PROFILES = /* @__PURE__ */ new WeakMap(), d.EACH_UPDATE_STATES = /* @__PURE__ */ new WeakMap();
6559
6624
  let x = d;
6560
- const Z = class Z {
6625
+ const _ = class _ {
6561
6626
  /**
6562
6627
  * コンストラクタ。
6563
6628
  *
@@ -6569,7 +6634,7 @@ const Z = class Z {
6569
6634
  r && new q(r, "load").run();
6570
6635
  }, this.onPopstate = (t) => {
6571
6636
  const r = t.state;
6572
- !r || r[Z.HISTORY_STATE_KEY] !== !0 || location.reload();
6637
+ !r || r[_.HISTORY_STATE_KEY] !== !0 || location.reload();
6573
6638
  }, this.root = e;
6574
6639
  }
6575
6640
  /**
@@ -6621,7 +6686,7 @@ const Z = class Z {
6621
6686
  subscribeCustomEvent(e) {
6622
6687
  if (e === null || e === "")
6623
6688
  return;
6624
- if (Z.BUILTIN_EVENT_NAMES.has(e)) {
6689
+ if (_.BUILTIN_EVENT_NAMES.has(e)) {
6625
6690
  m.warn(
6626
6691
  "[Haori]",
6627
6692
  `data-on="${e}" は組み込みイベントです。data-${e}-* を使用してください(data-on はカスタムイベント専用)。`
@@ -6748,13 +6813,13 @@ const Z = class Z {
6748
6813
  return null;
6749
6814
  }
6750
6815
  };
6751
- Z.HISTORY_STATE_KEY = "__haoriHistoryState__", Z.BUILTIN_EVENT_NAMES = /* @__PURE__ */ new Set([
6816
+ _.HISTORY_STATE_KEY = "__haoriHistoryState__", _.BUILTIN_EVENT_NAMES = /* @__PURE__ */ new Set([
6752
6817
  "click",
6753
6818
  "change",
6754
6819
  "input",
6755
6820
  "load"
6756
6821
  ]);
6757
- let fe = Z;
6822
+ let fe = _;
6758
6823
  const D = class D {
6759
6824
  /**
6760
6825
  * ノードが現在の Window に属する HTMLElement かどうかを判定します。
@@ -6882,7 +6947,7 @@ D.CONFIG_KEYS = /* @__PURE__ */ new Set([
6882
6947
  "disabled",
6883
6948
  "once"
6884
6949
  ]), D.registrations = /* @__PURE__ */ new Map();
6885
- let Q = D;
6950
+ let Z = D;
6886
6951
  function st(f) {
6887
6952
  typeof requestAnimationFrame == "function" ? requestAnimationFrame(() => f()) : Promise.resolve().then(f);
6888
6953
  }
@@ -7183,7 +7248,23 @@ const H = class H {
7183
7248
  x.scan(document.head),
7184
7249
  x.scan(document.body)
7185
7250
  ]), [t, r] = e;
7186
- t.status !== "fulfilled" && m.error("[Haori]", "Failed to build head fragment:", t.reason), r.status !== "fulfilled" && m.error("[Haori]", "Failed to build body fragment:", r.reason), await P.wait(), document.body.setAttribute("data-haori-ready", ""), H.observe(document.head), H.observe(document.body), new fe().start(), Q.syncTree(document.body), Y.syncTree(document.body);
7251
+ t.status !== "fulfilled" && m.error("[Haori]", "Failed to build head fragment:", t.reason), r.status !== "fulfilled" && m.error("[Haori]", "Failed to build body fragment:", r.reason), await k.wait(), document.body.setAttribute("data-haori-ready", ""), H.observe(document.head), H.observe(document.body), new fe().start(), Z.syncTree(document.body), Y.syncTree(document.body);
7252
+ }
7253
+ /**
7254
+ * 指定ノードが「外部管理」サブツリーに属するかどうかを判定します。
7255
+ *
7256
+ * `data-external` 属性を持つ要素とその子孫で発生した DOM 変更は、外部の
7257
+ * select 拡張ライブラリ(Choices.js など)が生成・更新する DOM とみなし、
7258
+ * Haori の監視・自動更新の対象から除外します。これにより、外部生成 DOM が
7259
+ * Haori に破壊・干渉されることを防ぎます。`data-each` による `<option>` の
7260
+ * 配列バインドは Haori のバインド評価パイプラインが駆動するため、監視除外
7261
+ * 下でも維持されます。
7262
+ *
7263
+ * @param node 判定対象のノード(要素・テキスト・コメントいずれも可)
7264
+ * @returns 外部管理サブツリーに属する場合 true
7265
+ */
7266
+ static isExternallyManaged(e) {
7267
+ return (e instanceof Element ? e : e?.parentElement ?? null)?.closest(`[${c.prefix}external]`) != null;
7187
7268
  }
7188
7269
  /**
7189
7270
  * 指定された要素を監視します。
@@ -7194,6 +7275,8 @@ const H = class H {
7194
7275
  const t = new MutationObserver(async (r) => {
7195
7276
  for (const i of r)
7196
7277
  try {
7278
+ if (H.isExternallyManaged(i.target))
7279
+ continue;
7197
7280
  switch (i.type) {
7198
7281
  case "attributes": {
7199
7282
  const n = i.target;
@@ -7207,14 +7290,14 @@ const H = class H {
7207
7290
  i.attributeName,
7208
7291
  n.getAttribute(i.attributeName),
7209
7292
  !0
7210
- ), Q.syncElement(n), Y.syncElement(n);
7293
+ ), Z.syncElement(n), Y.syncElement(n);
7211
7294
  break;
7212
7295
  }
7213
7296
  case "childList": {
7214
7297
  Array.from(i.removedNodes).forEach((n) => {
7215
- Q.cleanupTree(n), Y.cleanupTree(n), x.removeNode(n);
7298
+ Z.cleanupTree(n), Y.cleanupTree(n), x.removeNode(n);
7216
7299
  }), Array.from(i.addedNodes).forEach((n) => {
7217
- n.parentElement instanceof Element && (x.addNode(n.parentElement, n), Q.syncTree(n), Y.syncTree(n));
7300
+ n.parentElement instanceof Element && (x.addNode(n.parentElement, n), Z.syncTree(n), Y.syncTree(n));
7218
7301
  }), i.target instanceof Element && Y.syncElement(
7219
7302
  i.target
7220
7303
  );
@@ -7247,16 +7330,16 @@ const H = class H {
7247
7330
  H._initialized = !1, H._mutationObservers = [];
7248
7331
  let ae = H;
7249
7332
  document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", ae.init) : ae.init();
7250
- const at = () => ee.waitForRenders(), ot = "0.20.0";
7333
+ const at = () => Q.waitForRenders(), ot = "0.20.0";
7251
7334
  export {
7252
7335
  x as Core,
7253
7336
  c as Env,
7254
7337
  E as Form,
7255
7338
  T as Fragment,
7256
- ee as Haori,
7339
+ Q as Haori,
7257
7340
  m as Log,
7258
- P as Queue,
7259
- ee as default,
7341
+ k as Queue,
7342
+ Q as default,
7260
7343
  ot as version,
7261
7344
  at as waitForRenders
7262
7345
  };