haori-bootstrap 0.3.1 → 0.4.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/README.ja.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Haori.js Bootstrap は、Haori.js 向けの Bootstrap ベース UI 拡張ライブラリです。
4
4
 
5
- Version: 0.3.1
5
+ Version: 0.4.0
6
6
 
7
7
  ## 概要
8
8
 
@@ -43,7 +43,7 @@ npm install haori-bootstrap
43
43
  />
44
44
  <script src="https://cdn.jsdelivr.net/npm/haori@0.1.5/dist/haori.iife.js"></script>
45
45
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
46
- <script src="https://cdn.jsdelivr.net/npm/haori-bootstrap@0.3.1/dist/haori-bootstrap.iife.js"></script>
46
+ <script src="https://cdn.jsdelivr.net/npm/haori-bootstrap@0.4.0/dist/haori-bootstrap.iife.js"></script>
47
47
  ```
48
48
 
49
49
  IIFE 版は、window.Haori と window.bootstrap が利用可能な場合に自動で有効化されます。
@@ -115,6 +115,24 @@ install({
115
115
  - message 中の `\n` は改行へ正規化され、dialog、confirm、toast で複数行表示されます。
116
116
  - data-click-* の解釈とイベント実行は Haori.js / Procedure 側が担当します。
117
117
 
118
+ ## collapse 開閉状態の永続化
119
+
120
+ Bootstrap collapse 要素に `data-haori-bootstrap-persist="キー名"` を付与すると、開閉状態を sessionStorage に保存し、ページ再訪時に復元します。
121
+
122
+ ```html
123
+ <button data-bs-toggle="collapse" data-bs-target="#sideMenu">メニュー</button>
124
+ <div class="collapse" id="sideMenu" data-haori-bootstrap-persist="side-menu">
125
+ ...
126
+ </div>
127
+ ```
128
+
129
+ - `shown.bs.collapse` / `hidden.bs.collapse` を監視して `shown` / `hidden` を保存します。
130
+ - `install()` 時に既存要素を復元し、`data-import` などで後から挿入されたフラグメントにも `MutationObserver` で復元を適用します。
131
+ - 復元時は紐づくトグル要素(`data-bs-toggle="collapse"` で `data-bs-target` / `href` が当該 collapse を指すもの)の `aria-expanded` と `collapsed` クラスも同期します。トグル同期には collapse 要素の `id` が必要です。
132
+ - 保存キーごとに状態を区別します。同一キーを複数要素に付けると状態を共有します。
133
+ - ストレージが使えない環境(プライベートモード等)では黙って無効化し、例外は送出しません。
134
+ - `uninstall()` で監視を解除します。
135
+
118
136
  ## Build & Publish
119
137
 
120
138
  ローカル確認手順:
@@ -139,12 +157,12 @@ push 後に、そのタグから GitHub Release を published にします。公
139
157
  次回 patch リリースの例:
140
158
 
141
159
  ```bash
142
- # version が 0.3.1 になる
160
+ # version が 0.4.1 になる
143
161
  npm version patch
144
162
  git push origin main --follow-tags
145
163
  ```
146
164
 
147
- その後、push 済みタグの GitHub Release を作成して published にします。例として次回は `0.3.1` タグになります。
165
+ その後、push 済みタグの GitHub Release を作成して published にします。例として次回は `0.4.1` タグになります。
148
166
 
149
167
  自動公開:
150
168
 
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Haori.js Bootstrap is a Bootstrap-based UI extension library for Haori.js.
4
4
 
5
- Version: 0.3.1
5
+ Version: 0.4.0
6
6
 
7
7
  ## Overview
8
8
 
@@ -43,7 +43,7 @@ Load dependencies in this order for browser direct loading:
43
43
  />
44
44
  <script src="https://cdn.jsdelivr.net/npm/haori@0.1.5/dist/haori.iife.js"></script>
45
45
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
46
- <script src="https://cdn.jsdelivr.net/npm/haori-bootstrap@0.3.1/dist/haori-bootstrap.iife.js"></script>
46
+ <script src="https://cdn.jsdelivr.net/npm/haori-bootstrap@0.4.0/dist/haori-bootstrap.iife.js"></script>
47
47
  ```
48
48
 
49
49
  The IIFE build auto-enables when both window.Haori and window.bootstrap are available.
@@ -115,6 +115,24 @@ Existing Procedure flows can keep using data-click-* and data-click-*-message at
115
115
  - Literal `\n` sequences are normalized to line breaks for dialog, confirm, and toast.
116
116
  - Haori.js and Procedure remain responsible for interpreting data-click-* attributes and dispatching static method calls.
117
117
 
118
+ ## Persisting collapse state
119
+
120
+ Add `data-haori-bootstrap-persist="key"` to a Bootstrap collapse element to persist its open/closed state in `sessionStorage` and restore it on the next visit.
121
+
122
+ ```html
123
+ <button data-bs-toggle="collapse" data-bs-target="#sideMenu">Menu</button>
124
+ <div class="collapse" id="sideMenu" data-haori-bootstrap-persist="side-menu">
125
+ ...
126
+ </div>
127
+ ```
128
+
129
+ - Listens to `shown.bs.collapse` / `hidden.bs.collapse` and stores `shown` / `hidden`.
130
+ - `install()` restores existing elements and applies restoration to fragments inserted later (e.g. via `data-import`) through a `MutationObserver`.
131
+ - On restore it also syncs the associated toggles (`data-bs-toggle="collapse"` whose `data-bs-target` / `href` points to the collapse) — their `aria-expanded` and `collapsed` class. Toggle syncing requires the collapse element to have an `id`.
132
+ - State is keyed by the attribute value; reusing a key across elements shares their state.
133
+ - When storage is unavailable (e.g. private mode) the feature silently disables itself and never throws.
134
+ - `uninstall()` removes the listeners and observer.
135
+
118
136
  ## Build & Publish
119
137
 
120
138
  Local verification:
@@ -136,15 +154,15 @@ git push origin main --follow-tags
136
154
 
137
155
  After pushing, publish a GitHub Release from the generated version tag. The release workflow then publishes the package and uploads `dist.zip` automatically.
138
156
 
139
- Example next patch release after `0.3.1`:
157
+ Example next patch release after `0.4.0`:
140
158
 
141
159
  ```bash
142
- # version becomes 0.3.2
160
+ # version becomes 0.4.1
143
161
  npm version patch
144
162
  git push origin main --follow-tags
145
163
  ```
146
164
 
147
- Create and publish the GitHub Release for the pushed tag such as `0.3.2`.
165
+ Create and publish the GitHub Release for the pushed tag such as `0.4.1`.
148
166
 
149
167
  Release automation:
150
168
 
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @fileoverview Bootstrap collapse の開閉状態を sessionStorage へ永続化する。
3
+ *
4
+ * `data-haori-bootstrap-persist="キー名"` を collapse 要素(`.collapse`)に付与すると、
5
+ * `shown.bs.collapse` / `hidden.bs.collapse` を監視して開閉状態を保存し、ページ再訪時や
6
+ * `data-import` で後から挿入されたフラグメントにも保存済みの状態を復元する。
7
+ *
8
+ * Haori 本体の式サンドボックスはストレージ操作を禁止しているため、ストレージを使う
9
+ * 永続化は Bootstrap 連携の責務として本パッケージ側に置く。
10
+ */
11
+ /**
12
+ * collapse 永続化を有効化する。多重呼び出しは無視する。
13
+ *
14
+ * body が未生成の場合は DOMContentLoaded を待ってから初期化する。
15
+ *
16
+ * @param doc 対象 document。既定は現在の document。
17
+ * @return 戻り値はない。
18
+ */
19
+ export declare function setupCollapsePersistence(doc?: Document): void;
20
+ /**
21
+ * collapse 永続化を無効化し、監視を解除する。
22
+ *
23
+ * @param doc 対象 document。既定は setup 時の document。
24
+ * @return 戻り値はない。
25
+ */
26
+ export declare function teardownCollapsePersistence(doc?: Document): void;
@@ -1,3 +1,3 @@
1
- var HaoriBootstrap=(function(p){"use strict";function F(e){return typeof e=="function"}function z(e){return F(e?.Modal)?e?.Modal:void 0}function O(e){return F(e?.Toast)?e?.Toast:void 0}function k(e){return!!z(e)}function ue(e){return!!O(e)}function L(e,o,t){const n=z(t);if(n)return typeof n.getOrCreateInstance=="function"?n.getOrCreateInstance(e,o):new n(e,o)}function de(e,o,t){const n=O(t);if(n)return typeof n.getOrCreateInstance=="function"?n.getOrCreateInstance(e,o):new n(e,o)}const fe="data-haori-bootstrap-dialog",w="data-haori-bootstrap-action",me="data-haori-bootstrap-dialog-title";let be=0;function W(){return{backdrop:"static",keyboard:!1}}function G(e,o){if(o.dialogContainerSelector){const t=e.querySelector(o.dialogContainerSelector);if(t)return t}return e.body}function V(e,o,t,n){const r=e.createElement("div");r.className="modal fade",r.tabIndex=-1,r.setAttribute(fe,"true"),r.setAttribute("aria-hidden","true");const i=e.createElement("div");i.className="modal-dialog modal-dialog-centered";const c=e.createElement("div");if(c.className="modal-content",n){const u=`haori-dialog-title-${++be}`,A=e.createElement("div");A.className="modal-header";const M=e.createElement("h5");M.className="modal-title",M.id=u,M.setAttribute(me,"true"),M.textContent=n,A.appendChild(M),c.appendChild(A),r.setAttribute("aria-labelledby",u)}const a=e.createElement("div");a.className="modal-body";const d=e.createElement("p");d.className="mb-0",d.style.whiteSpace="pre-line",d.textContent=o,a.appendChild(d);const l=e.createElement("div");if(l.className="modal-footer",t){const u=e.createElement("button");u.type="button",u.className="btn btn-secondary",u.setAttribute(w,"cancel"),u.textContent="Cancel",l.appendChild(u)}const b=e.createElement("button");return b.type="button",b.className="btn btn-primary",b.setAttribute(w,"ok"),b.textContent="OK",l.appendChild(b),c.append(a,l),i.appendChild(c),r.appendChild(i),r}function pe(e,o){const t=globalThis.document,n=V(t,e,!1,o.dialogTitle);G(t,o).appendChild(n);const r=L(n,W(),o.bootstrap);return r?new Promise((i,c)=>{const a=()=>{n.removeEventListener("hidden.bs.modal",d),n.remove(),r.dispose?.(),i()},d=()=>{a()};n.querySelector(`[${w}="ok"]`)?.addEventListener("click",()=>{r.hide()},{once:!0}),n.addEventListener("hidden.bs.modal",d,{once:!0});try{r.show()}catch(b){n.removeEventListener("hidden.bs.modal",d),n.remove(),r.dispose?.(),c(b)}}):(n.remove(),Promise.reject(new Error("Bootstrap Modal is unavailable.")))}function he(e,o){const t=globalThis.document,n=V(t,e,!0,o.dialogTitle);G(t,o).appendChild(n);const r=L(n,W(),o.bootstrap);return r?new Promise((i,c)=>{let a=!1;const d=()=>{n.removeEventListener("hidden.bs.modal",l),n.remove(),r.dispose?.(),i(a)},l=()=>{d()},b=n.querySelector(`[${w}="ok"]`),u=n.querySelector(`[${w}="cancel"]`);b?.addEventListener("click",()=>{a=!0,r.hide()},{once:!0}),u?.addEventListener("click",()=>{a=!1,r.hide()},{once:!0}),n.addEventListener("hidden.bs.modal",l,{once:!0});try{r.show()}catch(A){n.removeEventListener("hidden.bs.modal",l),n.remove(),r.dispose?.(),c(A)}}):(n.remove(),Promise.reject(new Error("Bootstrap Modal is unavailable.")))}const h="data-haori-bootstrap-owned",m="data-haori-bootstrap-message-container",C="data-haori-bootstrap-invalid-target",y="data-haori-bootstrap-valid-target";function S(e){return e instanceof HTMLInputElement&&(e.type==="checkbox"||e.type==="radio")}function E(e){return e instanceof HTMLInputElement&&e.type==="radio"}function I(e){return e instanceof HTMLInputElement||e instanceof HTMLSelectElement||e instanceof HTMLTextAreaElement}function B(e){return Array.from(e.children).find(o=>o instanceof HTMLElement&&o.getAttribute(m)==="true")}function j(e,o){const t=e.createElement("div");return t.setAttribute(h,"true"),t.textContent=o,t}function K(e){return B(e)}function N(e){if(e.name){const o=e.form??e.ownerDocument,t=typeof CSS<"u"&&typeof CSS.escape=="function"?CSS.escape(e.name):e.name.replace(/(["\\])/g,"\\$1"),n=Array.from(o.querySelectorAll(`input[type="radio"][name="${t}"]`));if(n.length>0)return n}return[e]}function Ee(e){const[o,...t]=e;if(!o)return;let n=o;for(;n;){if(t.every(r=>n?.contains(r)))return n;n=n.parentElement}}function D(e){const t=N(e).map(n=>n.closest(".form-check")).filter(n=>n instanceof HTMLElement);if(t.length>1){const n=Ee(t);if(n&&!t.includes(n))return n}return H(e)}function H(e){const o=e.closest(".form-check");return o instanceof HTMLElement?o:void 0}function J(e){const o=e.nextElementSibling;if(o instanceof HTMLElement&&o.getAttribute(m)==="true")return o;const t=document.createElement("div");return t.className="invalid-feedback d-block",t.setAttribute(h,"true"),t.setAttribute(m,"true"),e.insertAdjacentElement("afterend",t),t}function ve(e){const o=E(e)?D(e):H(e);if(!o)return J(e);const t=B(o);if(t)return t;const n=document.createElement("div");return n.className="invalid-feedback d-block",n.setAttribute(h,"true"),n.setAttribute(m,"true"),o.appendChild(n),n}function Te(e){const o=K(e);if(o)return o;const t=document.createElement("div");return t.className="alert alert-danger",t.setAttribute("role","alert"),t.setAttribute(h,"true"),t.setAttribute(m,"true"),e.insertAdjacentElement("afterbegin",t),t}function v(e){e.getAttribute(C)==="true"&&(e.classList.remove("is-invalid"),e.removeAttribute(C))}function T(e){e.getAttribute(y)==="true"&&(e.classList.remove("is-valid"),e.removeAttribute(y))}function Q(e){switch(e){case"success":return"alert alert-success";case"warning":return"alert alert-warning";case"info":return"alert alert-info";default:return"alert alert-danger"}}function P(e){return e==="success"?"valid-feedback d-block":"invalid-feedback d-block"}function X(e){(E(e)?N(e):[e]).forEach(t=>{t.classList.add("is-invalid"),t.setAttribute(C,"true")})}function Ae(e){(E(e)?N(e):[e]).forEach(t=>{v(t)})}function Y(e,o){const t=e.nextElementSibling;if(t instanceof HTMLElement&&t.getAttribute(m)==="true")return t.className=P(o),t;const n=document.createElement("div");return n.className=P(o),n.setAttribute(h,"true"),n.setAttribute(m,"true"),e.insertAdjacentElement("afterend",n),n}function Ce(e,o){const t=E(e)?D(e):H(e);if(!t)return Y(e,o);const n=B(t);if(n)return n.className=P(o),n;const r=document.createElement("div");return r.className=P(o),r.setAttribute(h,"true"),r.setAttribute(m,"true"),t.appendChild(r),r}function ge(e,o){const t=K(e);if(t)return t.className=Q(o),t;const n=document.createElement("div");return n.className=Q(o),n.setAttribute("role","alert"),n.setAttribute(h,"true"),n.setAttribute(m,"true"),e.insertAdjacentElement("afterbegin",n),n}function we(e,o){return(S(e)?ve(e):I(e)?J(e):Te(e)).appendChild(j(document,o)),S(e)?X(e):I(e)&&(e.classList.add("is-invalid"),e.setAttribute(C,"true")),Promise.resolve()}function ye(e,o,t){if((S(e)?Ce(e,t):I(e)?Y(e,t):ge(e,t)).appendChild(j(document,o)),S(e)){const r=E(e)?N(e):[e];t==="success"?r.forEach(i=>{v(i),i.classList.add("is-valid"),i.setAttribute(y,"true")}):!t||t==="error"?(r.forEach(i=>T(i)),X(e)):r.forEach(i=>{T(i),v(i)})}else I(e)&&(t==="success"?(v(e),e.classList.add("is-valid"),e.setAttribute(y,"true")):!t||t==="error"?(T(e),e.classList.add("is-invalid"),e.setAttribute(C,"true")):(T(e),v(e)));return Promise.resolve()}function Se(e){if(S(e)){const r=E(e)?D(e):H(e);(r?B(r):void 0)?.remove(),Ae(e),(E(e)?N(e):[e]).forEach(a=>T(a))}else if(I(e)){const r=e.nextElementSibling;r instanceof HTMLElement&&r.getAttribute(m)==="true"&&r.remove(),v(e),T(e)}return e.querySelectorAll(`[${m}="true"]`).forEach(r=>{r.remove()}),e.querySelectorAll(`[${C}="true"]`).forEach(r=>{v(r)}),e.querySelectorAll(`[${y}="true"]`).forEach(r=>{T(r)}),Promise.resolve()}function Z(e){e.classList.contains("modal")||e.classList.add("modal"),e.tabIndex<0&&(e.tabIndex=-1),e.hasAttribute("aria-hidden")||e.setAttribute("aria-hidden","true")}function Ie(e,o){Z(e);const t=L(e,void 0,o.bootstrap);return t?(t.show(),Promise.resolve()):Promise.reject(new Error("Bootstrap Modal is unavailable."))}function Ne(e,o){Z(e);const t=L(e,void 0,o.bootstrap);return t?(t.hide(),Promise.resolve()):Promise.reject(new Error("Bootstrap Modal is unavailable."))}const ee="data-haori-bootstrap-toast-container",Me="data-haori-bootstrap-toast",ke="data-haori-bootstrap-toast-accent",Le="data-haori-bootstrap-toast-dismiss",te={"top-start":"top-0 start-0","top-center":"top-0 start-50 translate-middle-x","top-end":"top-0 end-0","bottom-start":"bottom-0 start-0","bottom-center":"bottom-0 start-50 translate-middle-x","bottom-end":"bottom-0 end-0"};function Be(e){switch(e){case"success":return{accentClassName:"bg-success"};case"warning":return{accentClassName:"bg-warning"};case"error":return{accentClassName:"bg-danger"};default:return{accentClassName:"bg-info"}}}function He(e,o){if(o.toastContainerSelector){const t=e.querySelector(o.toastContainerSelector);if(t)return t}return e.body}function Pe(e,o){const t=He(e,o),n=te[o.toastPosition??"bottom-end"],r=t.querySelector(`[${ee}="true"]`);if(r){const c=Object.values(te).flatMap(a=>a.split(" "));return r.classList.remove(...c),r.classList.add(...n.split(" ")),r}const i=e.createElement("div");return i.className=`toast-container position-fixed ${n} p-3`,i.setAttribute(ee,"true"),t.appendChild(i),i}function Re(e,o,t){const n=globalThis.document,r=Be(o),i=n.createElement("div");i.className="toast border bg-body text-body shadow-sm",i.setAttribute("role","status"),i.setAttribute("aria-live","polite"),i.setAttribute("aria-atomic","true"),i.setAttribute(Me,"true");const c=n.createElement("div");c.className="d-flex align-items-stretch";const a=n.createElement("div");a.className=`flex-shrink-0 rounded-start ${r.accentClassName}`,a.style.width="0.375rem",a.setAttribute(ke,"true");const d=n.createElement("div");d.className="toast-body",d.style.whiteSpace="pre-line",d.textContent=e;const l=n.createElement("button");l.type="button",l.className="btn-close me-2 m-auto flex-shrink-0",l.setAttribute("aria-label","Close"),l.setAttribute(Le,"true"),c.appendChild(a),c.appendChild(d),c.appendChild(l),i.appendChild(c),Pe(n,t).appendChild(i);const b=t.toastDelay!==void 0?{delay:t.toastDelay}:void 0,u=de(i,b,t.bootstrap);if(!u)return i.remove(),Promise.reject(new Error("Bootstrap Toast is unavailable."));l.addEventListener("click",()=>{u.hide?.()}),i.addEventListener("hidden.bs.toast",()=>{i.remove(),u.dispose?.()},{once:!0});try{return u.show(),Promise.resolve()}catch(A){return i.remove(),u.dispose?.(),Promise.reject(A)}}let f={options:{fallbackToNative:!0}};function g(e){return e.replace(/\\n/g,`
2
- `)}function oe(){return globalThis.window}function $(e){return Promise.resolve(e).then(()=>{})}function R(e){const o=f.originalHaori?.[e];return typeof o=="function"?o:void 0}function _(e){console.warn(`[haori-bootstrap] ${e} skipped because Bootstrap support is unavailable.`)}function ne(e){const o=g(e),t=R("dialog");if(t)return $(t(o));const n=oe();return f.options.fallbackToNative&&typeof n?.alert=="function"?(n.alert(o),Promise.resolve()):(_("dialog"),Promise.resolve())}function re(e){const o=g(e),t=R("confirm");if(t)return Promise.resolve(t(o)).then(r=>!!r);const n=oe();return f.options.fallbackToNative&&typeof n?.confirm=="function"?Promise.resolve(n.confirm(o)):(_("confirm"),Promise.resolve(!1))}function ie(e,o){const t=g(e),n=R("toast");return n?$(n(t,o)):(_("toast"),Promise.resolve())}function x(e,o){const t=R(e);return t?$(t(o)):(_(e),Promise.resolve())}function _e(e){f=e}class se{static dialog(o){const t=g(o);return k(f.options.bootstrap)?pe(t,f.options).catch(()=>ne(t)):ne(t)}static confirm(o){const t=g(o);return k(f.options.bootstrap)?he(t,f.options).catch(()=>re(t)):re(t)}static toast(o,t){const n=g(o);return ue(f.options.bootstrap)?Re(n,t,f.options).catch(()=>ie(n,t)):ie(n,t)}static openDialog(o){return k(f.options.bootstrap)?Ie(o,f.options).catch(()=>x("openDialog",o)):x("openDialog",o)}static closeDialog(o){return k(f.options.bootstrap)?Ne(o,f.options).catch(()=>x("closeDialog",o)):x("closeDialog",o)}static addErrorMessage(o,t){return we(o,t)}static addMessage(o,t,n){return ye(o,t,n)}static clearMessages(o){return Se(o)}}const q={fallbackToNative:!0},s={installed:!1,options:q};function U(){return globalThis.window}function xe(e,o){return{bootstrap:e.bootstrap??o?.bootstrap,fallbackToNative:e.fallbackToNative??q.fallbackToNative,runtime:e.runtime??s.options.runtime??o?.Haori?.runtime,toastContainerSelector:e.toastContainerSelector??s.options.toastContainerSelector,dialogContainerSelector:e.dialogContainerSelector??s.options.dialogContainerSelector,dialogTitle:e.dialogTitle??s.options.dialogTitle,toastPosition:e.toastPosition??s.options.toastPosition,toastDelay:e.toastDelay??s.options.toastDelay}}function ae(e=U()){return!!(e?.Haori&&e.bootstrap)}function ce(e={}){const o=U();if(!o?.Haori)throw new Error("window.Haori is required before calling install().");if(s.originalHaori||(s.originalHaori=o.Haori,s.originalRuntime=o.Haori.runtime),s.options=xe(e,o),s.options.runtime){const t=s.originalHaori??o.Haori;typeof t.setRuntime=="function"?t.setRuntime(s.options.runtime):console.warn("[haori-bootstrap] Haori.setRuntime が利用できません。runtime 設定は無視されます。")}_e({originalHaori:s.originalHaori,options:s.options}),o.Haori=se,s.installed=!0}function De(){const e=U();!e||!s.originalHaori||(s.originalHaori.runtime=s.originalRuntime,e.Haori=s.originalHaori,s.installed=!1,s.originalHaori=void 0,s.originalRuntime=void 0,s.options=q)}function $e(){return s.installed}const le="__haoriJsBootstrapAutoEnabled__";function qe(){return globalThis.window}function Ue(e){return!!e[le]}function Fe(e){e[le]=!0}function ze(){const e=qe();if(!(!e||Ue(e))){if(!ae(e)){console.warn("[haori-bootstrap] Auto-enable skipped because window.Haori or window.bootstrap is missing.");return}try{ce({bootstrap:e.bootstrap}),Fe(e)}catch(o){console.warn("[haori-bootstrap] Auto-enable failed.",o)}}}ze();const Oe="0.3.1";return p.BootstrapHaori=se,p.hasAutoEnablePrerequisites=ae,p.install=ce,p.isInstalled=$e,p.uninstall=De,p.version=Oe,Object.defineProperty(p,Symbol.toStringTag,{value:"Module"}),p})({});
1
+ var HaoriBootstrap=(function(p){"use strict";function G(e){return typeof e=="function"}function V(e){return G(e?.Modal)?e?.Modal:void 0}function j(e){return G(e?.Toast)?e?.Toast:void 0}function N(e){return!!V(e)}function Ce(e){return!!j(e)}function k(e,t,o){const n=V(o);if(n)return typeof n.getOrCreateInstance=="function"?n.getOrCreateInstance(e,t):new n(e,t)}function we(e,t,o){const n=j(o);if(n)return typeof n.getOrCreateInstance=="function"?n.getOrCreateInstance(e,t):new n(e,t)}const Se="data-haori-bootstrap-dialog",w="data-haori-bootstrap-action",ye="data-haori-bootstrap-dialog-title";let Me=0;function K(){return{backdrop:"static",keyboard:!1}}function J(e,t){if(t.dialogContainerSelector){const o=e.querySelector(t.dialogContainerSelector);if(o)return o}return e.body}function X(e,t,o,n){const r=e.createElement("div");r.className="modal fade",r.tabIndex=-1,r.setAttribute(Se,"true"),r.setAttribute("aria-hidden","true");const i=e.createElement("div");i.className="modal-dialog modal-dialog-centered";const c=e.createElement("div");if(c.className="modal-content",n){const u=`haori-dialog-title-${++Me}`,g=e.createElement("div");g.className="modal-header";const L=e.createElement("h5");L.className="modal-title",L.id=u,L.setAttribute(ye,"true"),L.textContent=n,g.appendChild(L),c.appendChild(g),r.setAttribute("aria-labelledby",u)}const a=e.createElement("div");a.className="modal-body";const d=e.createElement("p");d.className="mb-0",d.style.whiteSpace="pre-line",d.textContent=t,a.appendChild(d);const l=e.createElement("div");if(l.className="modal-footer",o){const u=e.createElement("button");u.type="button",u.className="btn btn-secondary",u.setAttribute(w,"cancel"),u.textContent="Cancel",l.appendChild(u)}const b=e.createElement("button");return b.type="button",b.className="btn btn-primary",b.setAttribute(w,"ok"),b.textContent="OK",l.appendChild(b),c.append(a,l),i.appendChild(c),r.appendChild(i),r}function Ie(e,t){const o=globalThis.document,n=X(o,e,!1,t.dialogTitle);J(o,t).appendChild(n);const r=k(n,K(),t.bootstrap);return r?new Promise((i,c)=>{const a=()=>{n.removeEventListener("hidden.bs.modal",d),n.remove(),r.dispose?.(),i()},d=()=>{a()};n.querySelector(`[${w}="ok"]`)?.addEventListener("click",()=>{r.hide()},{once:!0}),n.addEventListener("hidden.bs.modal",d,{once:!0});try{r.show()}catch(b){n.removeEventListener("hidden.bs.modal",d),n.remove(),r.dispose?.(),c(b)}}):(n.remove(),Promise.reject(new Error("Bootstrap Modal is unavailable.")))}function Le(e,t){const o=globalThis.document,n=X(o,e,!0,t.dialogTitle);J(o,t).appendChild(n);const r=k(n,K(),t.bootstrap);return r?new Promise((i,c)=>{let a=!1;const d=()=>{n.removeEventListener("hidden.bs.modal",l),n.remove(),r.dispose?.(),i(a)},l=()=>{d()},b=n.querySelector(`[${w}="ok"]`),u=n.querySelector(`[${w}="cancel"]`);b?.addEventListener("click",()=>{a=!0,r.hide()},{once:!0}),u?.addEventListener("click",()=>{a=!1,r.hide()},{once:!0}),n.addEventListener("hidden.bs.modal",l,{once:!0});try{r.show()}catch(g){n.removeEventListener("hidden.bs.modal",l),n.remove(),r.dispose?.(),c(g)}}):(n.remove(),Promise.reject(new Error("Bootstrap Modal is unavailable.")))}const h="data-haori-bootstrap-owned",m="data-haori-bootstrap-message-container",A="data-haori-bootstrap-invalid-target",S="data-haori-bootstrap-valid-target";function y(e){return e instanceof HTMLInputElement&&(e.type==="checkbox"||e.type==="radio")}function E(e){return e instanceof HTMLInputElement&&e.type==="radio"}function M(e){return e instanceof HTMLInputElement||e instanceof HTMLSelectElement||e instanceof HTMLTextAreaElement}function H(e){return Array.from(e.children).find(t=>t instanceof HTMLElement&&t.getAttribute(m)==="true")}function Q(e,t){const o=e.createElement("div");return o.setAttribute(h,"true"),o.textContent=t,o}function Y(e){return H(e)}function I(e){if(e.name){const t=e.form??e.ownerDocument,o=typeof CSS<"u"&&typeof CSS.escape=="function"?CSS.escape(e.name):e.name.replace(/(["\\])/g,"\\$1"),n=Array.from(t.querySelectorAll(`input[type="radio"][name="${o}"]`));if(n.length>0)return n}return[e]}function Ne(e){const[t,...o]=e;if(!t)return;let n=t;for(;n;){if(o.every(r=>n?.contains(r)))return n;n=n.parentElement}}function O(e){const o=I(e).map(n=>n.closest(".form-check")).filter(n=>n instanceof HTMLElement);if(o.length>1){const n=Ne(o);if(n&&!o.includes(n))return n}return B(e)}function B(e){const t=e.closest(".form-check");return t instanceof HTMLElement?t:void 0}function Z(e){const t=e.nextElementSibling;if(t instanceof HTMLElement&&t.getAttribute(m)==="true")return t;const o=document.createElement("div");return o.className="invalid-feedback d-block",o.setAttribute(h,"true"),o.setAttribute(m,"true"),e.insertAdjacentElement("afterend",o),o}function ke(e){const t=E(e)?O(e):B(e);if(!t)return Z(e);const o=H(t);if(o)return o;const n=document.createElement("div");return n.className="invalid-feedback d-block",n.setAttribute(h,"true"),n.setAttribute(m,"true"),t.appendChild(n),n}function He(e){const t=Y(e);if(t)return t;const o=document.createElement("div");return o.className="alert alert-danger",o.setAttribute("role","alert"),o.setAttribute(h,"true"),o.setAttribute(m,"true"),e.insertAdjacentElement("afterbegin",o),o}function v(e){e.getAttribute(A)==="true"&&(e.classList.remove("is-invalid"),e.removeAttribute(A))}function T(e){e.getAttribute(S)==="true"&&(e.classList.remove("is-valid"),e.removeAttribute(S))}function ee(e){switch(e){case"success":return"alert alert-success";case"warning":return"alert alert-warning";case"info":return"alert alert-info";default:return"alert alert-danger"}}function R(e){return e==="success"?"valid-feedback d-block":"invalid-feedback d-block"}function te(e){(E(e)?I(e):[e]).forEach(o=>{o.classList.add("is-invalid"),o.setAttribute(A,"true")})}function Be(e){(E(e)?I(e):[e]).forEach(o=>{v(o)})}function oe(e,t){const o=e.nextElementSibling;if(o instanceof HTMLElement&&o.getAttribute(m)==="true")return o.className=R(t),o;const n=document.createElement("div");return n.className=R(t),n.setAttribute(h,"true"),n.setAttribute(m,"true"),e.insertAdjacentElement("afterend",n),n}function Re(e,t){const o=E(e)?O(e):B(e);if(!o)return oe(e,t);const n=H(o);if(n)return n.className=R(t),n;const r=document.createElement("div");return r.className=R(t),r.setAttribute(h,"true"),r.setAttribute(m,"true"),o.appendChild(r),r}function Pe(e,t){const o=Y(e);if(o)return o.className=ee(t),o;const n=document.createElement("div");return n.className=ee(t),n.setAttribute("role","alert"),n.setAttribute(h,"true"),n.setAttribute(m,"true"),e.insertAdjacentElement("afterbegin",n),n}function De(e,t){return(y(e)?ke(e):M(e)?Z(e):He(e)).appendChild(Q(document,t)),y(e)?te(e):M(e)&&(e.classList.add("is-invalid"),e.setAttribute(A,"true")),Promise.resolve()}function _e(e,t,o){if((y(e)?Re(e,o):M(e)?oe(e,o):Pe(e,o)).appendChild(Q(document,t)),y(e)){const r=E(e)?I(e):[e];o==="success"?r.forEach(i=>{v(i),i.classList.add("is-valid"),i.setAttribute(S,"true")}):!o||o==="error"?(r.forEach(i=>T(i)),te(e)):r.forEach(i=>{T(i),v(i)})}else M(e)&&(o==="success"?(v(e),e.classList.add("is-valid"),e.setAttribute(S,"true")):!o||o==="error"?(T(e),e.classList.add("is-invalid"),e.setAttribute(A,"true")):(T(e),v(e)));return Promise.resolve()}function xe(e){if(y(e)){const r=E(e)?O(e):B(e);(r?H(r):void 0)?.remove(),Be(e),(E(e)?I(e):[e]).forEach(a=>T(a))}else if(M(e)){const r=e.nextElementSibling;r instanceof HTMLElement&&r.getAttribute(m)==="true"&&r.remove(),v(e),T(e)}return e.querySelectorAll(`[${m}="true"]`).forEach(r=>{r.remove()}),e.querySelectorAll(`[${A}="true"]`).forEach(r=>{v(r)}),e.querySelectorAll(`[${S}="true"]`).forEach(r=>{T(r)}),Promise.resolve()}function ne(e){e.classList.contains("modal")||e.classList.add("modal"),e.tabIndex<0&&(e.tabIndex=-1),e.hasAttribute("aria-hidden")||e.setAttribute("aria-hidden","true")}function $e(e,t){ne(e);const o=k(e,void 0,t.bootstrap);return o?(o.show(),Promise.resolve()):Promise.reject(new Error("Bootstrap Modal is unavailable."))}function qe(e,t){ne(e);const o=k(e,void 0,t.bootstrap);return o?(o.hide(),Promise.resolve()):Promise.reject(new Error("Bootstrap Modal is unavailable."))}const re="data-haori-bootstrap-toast-container",Oe="data-haori-bootstrap-toast",Ue="data-haori-bootstrap-toast-accent",Fe="data-haori-bootstrap-toast-dismiss",ie={"top-start":"top-0 start-0","top-center":"top-0 start-50 translate-middle-x","top-end":"top-0 end-0","bottom-start":"bottom-0 start-0","bottom-center":"bottom-0 start-50 translate-middle-x","bottom-end":"bottom-0 end-0"};function ze(e){switch(e){case"success":return{accentClassName:"bg-success"};case"warning":return{accentClassName:"bg-warning"};case"error":return{accentClassName:"bg-danger"};default:return{accentClassName:"bg-info"}}}function We(e,t){if(t.toastContainerSelector){const o=e.querySelector(t.toastContainerSelector);if(o)return o}return e.body}function Ge(e,t){const o=We(e,t),n=ie[t.toastPosition??"bottom-end"],r=o.querySelector(`[${re}="true"]`);if(r){const c=Object.values(ie).flatMap(a=>a.split(" "));return r.classList.remove(...c),r.classList.add(...n.split(" ")),r}const i=e.createElement("div");return i.className=`toast-container position-fixed ${n} p-3`,i.setAttribute(re,"true"),o.appendChild(i),i}function Ve(e,t,o){const n=globalThis.document,r=ze(t),i=n.createElement("div");i.className="toast border bg-body text-body shadow-sm",i.setAttribute("role","status"),i.setAttribute("aria-live","polite"),i.setAttribute("aria-atomic","true"),i.setAttribute(Oe,"true");const c=n.createElement("div");c.className="d-flex align-items-stretch";const a=n.createElement("div");a.className=`flex-shrink-0 rounded-start ${r.accentClassName}`,a.style.width="0.375rem",a.setAttribute(Ue,"true");const d=n.createElement("div");d.className="toast-body",d.style.whiteSpace="pre-line",d.textContent=e;const l=n.createElement("button");l.type="button",l.className="btn-close me-2 m-auto flex-shrink-0",l.setAttribute("aria-label","Close"),l.setAttribute(Fe,"true"),c.appendChild(a),c.appendChild(d),c.appendChild(l),i.appendChild(c),Ge(n,o).appendChild(i);const b=o.toastDelay!==void 0?{delay:o.toastDelay}:void 0,u=we(i,b,o.bootstrap);if(!u)return i.remove(),Promise.reject(new Error("Bootstrap Toast is unavailable."));l.addEventListener("click",()=>{u.hide?.()}),i.addEventListener("hidden.bs.toast",()=>{i.remove(),u.dispose?.()},{once:!0});try{return u.show(),Promise.resolve()}catch(g){return i.remove(),u.dispose?.(),Promise.reject(g)}}let f={options:{fallbackToNative:!0}};function C(e){return e.replace(/\\n/g,`
2
+ `)}function se(){return globalThis.window}function U(e){return Promise.resolve(e).then(()=>{})}function P(e){const t=f.originalHaori?.[e];return typeof t=="function"?t:void 0}function D(e){console.warn(`[haori-bootstrap] ${e} skipped because Bootstrap support is unavailable.`)}function ae(e){const t=C(e),o=P("dialog");if(o)return U(o(t));const n=se();return f.options.fallbackToNative&&typeof n?.alert=="function"?(n.alert(t),Promise.resolve()):(D("dialog"),Promise.resolve())}function ce(e){const t=C(e),o=P("confirm");if(o)return Promise.resolve(o(t)).then(r=>!!r);const n=se();return f.options.fallbackToNative&&typeof n?.confirm=="function"?Promise.resolve(n.confirm(t)):(D("confirm"),Promise.resolve(!1))}function le(e,t){const o=C(e),n=P("toast");return n?U(n(o,t)):(D("toast"),Promise.resolve())}function _(e,t){const o=P(e);return o?U(o(t)):(D(e),Promise.resolve())}function je(e){f=e}class ue{static dialog(t){const o=C(t);return N(f.options.bootstrap)?Ie(o,f.options).catch(()=>ae(o)):ae(o)}static confirm(t){const o=C(t);return N(f.options.bootstrap)?Le(o,f.options).catch(()=>ce(o)):ce(o)}static toast(t,o){const n=C(t);return Ce(f.options.bootstrap)?Ve(n,o,f.options).catch(()=>le(n,o)):le(n,o)}static openDialog(t){return N(f.options.bootstrap)?$e(t,f.options).catch(()=>_("openDialog",t)):_("openDialog",t)}static closeDialog(t){return N(f.options.bootstrap)?qe(t,f.options).catch(()=>_("closeDialog",t)):_("closeDialog",t)}static addErrorMessage(t,o){return De(t,o)}static addMessage(t,o,n){return _e(t,o,n)}static clearMessages(t){return xe(t)}}const Ke="haori-bootstrap:collapse:",x="data-haori-bootstrap-persist";let $=!1,q,F;function de(e){return Ke+e}function Je(e){try{const t=window.sessionStorage.getItem(de(e));return t==="shown"||t==="hidden"?t:void 0}catch{return}}function Xe(e,t){try{window.sessionStorage.setItem(de(e),t)}catch{}}function fe(e,t){const o=e.id,n=[`[data-bs-toggle="collapse"][data-bs-target="#${o}"]`];if(o&&n.push(`[data-bs-toggle="collapse"][href="#${o}"]`),!o)return;e.ownerDocument.querySelectorAll(n.join(",")).forEach(i=>{i.setAttribute("aria-expanded",t?"true":"false"),i.classList.toggle("collapsed",!t)})}function me(e){const t=e.getAttribute(x);if(!t)return;const o=Je(t);if(!o)return;const n=e.classList.contains("show");o==="shown"&&!n?(e.classList.add("show"),fe(e,!0)):o==="hidden"&&n&&(e.classList.remove("show"),fe(e,!1))}function be(e){e instanceof HTMLElement&&e.hasAttribute(x)&&me(e),e.querySelectorAll(`[${x}]`).forEach(me)}function pe(e,t){const o=e.target;if(!(o instanceof HTMLElement))return;const n=o.getAttribute(x);n&&Xe(n,t)}const he=e=>pe(e,"shown"),Ee=e=>pe(e,"hidden");function Qe(e=document){if($)return;$=!0,F=e,e.addEventListener("shown.bs.collapse",he),e.addEventListener("hidden.bs.collapse",Ee);const t=()=>{be(e),q=new MutationObserver(o=>{for(const n of o)n.addedNodes.forEach(r=>{r instanceof HTMLElement&&be(r)})}),e.body&&q.observe(e.body,{childList:!0,subtree:!0})};e.body?t():e.addEventListener("DOMContentLoaded",t,{once:!0})}function Ye(e=F??document){$&&($=!1,e.removeEventListener("shown.bs.collapse",he),e.removeEventListener("hidden.bs.collapse",Ee),q?.disconnect(),q=void 0,F=void 0)}const z={fallbackToNative:!0},ve=new Set(["dialog","confirm","toast","openDialog","closeDialog","addErrorMessage","addMessage","clearMessages"]);function Ze(e){const t=ue;return new Proxy(e,{get(o,n,r){return typeof n=="string"&&ve.has(n)?t[n]:Reflect.get(o,n,r)},has(o,n){return typeof n=="string"&&ve.has(n)?!0:Reflect.has(o,n)}})}const s={installed:!1,options:z};function W(){return globalThis.window}function et(e,t){return{bootstrap:e.bootstrap??t?.bootstrap,fallbackToNative:e.fallbackToNative??z.fallbackToNative,runtime:e.runtime??s.options.runtime??t?.Haori?.runtime,toastContainerSelector:e.toastContainerSelector??s.options.toastContainerSelector,dialogContainerSelector:e.dialogContainerSelector??s.options.dialogContainerSelector,dialogTitle:e.dialogTitle??s.options.dialogTitle,toastPosition:e.toastPosition??s.options.toastPosition,toastDelay:e.toastDelay??s.options.toastDelay}}function Te(e=W()){return!!(e?.Haori&&e.bootstrap)}function ge(e={}){const t=W();if(!t?.Haori)throw new Error("window.Haori is required before calling install().");if(s.originalHaori||(s.originalHaori=t.Haori,s.originalRuntime=t.Haori.runtime),s.options=et(e,t),s.options.runtime){const o=s.originalHaori??t.Haori;typeof o.setRuntime=="function"?o.setRuntime(s.options.runtime):console.warn("[haori-bootstrap] Haori.setRuntime が利用できません。runtime 設定は無視されます。")}je({originalHaori:s.originalHaori,options:s.options}),t.Haori=Ze(s.originalHaori),Qe(),s.installed=!0}function tt(){const e=W();if(!e||!s.originalHaori)return;const t=s.originalHaori;typeof t.setRuntime=="function"?t.setRuntime(s.originalRuntime):t.runtime=s.originalRuntime,e.Haori=s.originalHaori,Ye(),s.installed=!1,s.originalHaori=void 0,s.originalRuntime=void 0,s.options=z}function ot(){return s.installed}const Ae="__haoriJsBootstrapAutoEnabled__";function nt(){return globalThis.window}function rt(e){return!!e[Ae]}function it(e){e[Ae]=!0}function st(){const e=nt();if(!(!e||rt(e))){if(!Te(e)){console.warn("[haori-bootstrap] Auto-enable skipped because window.Haori or window.bootstrap is missing.");return}try{ge({bootstrap:e.bootstrap}),it(e)}catch(t){console.warn("[haori-bootstrap] Auto-enable failed.",t)}}}st();const at="0.4.0";return p.BootstrapHaori=ue,p.hasAutoEnablePrerequisites=Te,p.install=ge,p.isInstalled=ot,p.uninstall=tt,p.version=at,Object.defineProperty(p,Symbol.toStringTag,{value:"Module"}),p})({});
3
3
  //# sourceMappingURL=haori-bootstrap.iife.js.map