haori-bootstrap 0.2.0 → 0.3.1

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.2.0
5
+ Version: 0.3.1
6
6
 
7
7
  ## 概要
8
8
 
@@ -13,7 +13,7 @@ Version: 0.2.0
13
13
  - 対応 Bootstrap バージョン: 5.3.x
14
14
  - 配布形式: ESM と IIFE
15
15
 
16
- npm パッケージ名は `haori-js-bootstrap` から `haori-bootstrap` へ変更しました。既存利用者は新しい package 名へ移行してください。GitHub リポジトリ名は変更していません。
16
+ npm パッケージ名は `haori-js-bootstrap` から `haori-bootstrap` へ変更し、旧 package は deprecated にしました。既存利用者は新しい package 名へ移行してください。GitHub リポジトリ名は変更していません。
17
17
 
18
18
  Haori.js の dialog、confirm、toast、openDialog、closeDialog、addErrorMessage、clearMessages などの UI 系静的メソッドを Bootstrap ベース実装へ差し替えつつ、既存の Procedure 連携を維持します。
19
19
 
@@ -41,9 +41,9 @@ npm install haori-bootstrap
41
41
  rel="stylesheet"
42
42
  href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
43
43
  />
44
- <script src="https://cdn.jsdelivr.net/npm/haori@0.1.2/dist/haori.iife.js"></script>
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.2.0/dist/haori-bootstrap.iife.js"></script>
46
+ <script src="https://cdn.jsdelivr.net/npm/haori-bootstrap@0.3.1/dist/haori-bootstrap.iife.js"></script>
47
47
  ```
48
48
 
49
49
  IIFE 版は、window.Haori と window.bootstrap が利用可能な場合に自動で有効化されます。
@@ -63,6 +63,7 @@ import { install } from 'haori-bootstrap';
63
63
 
64
64
  install({
65
65
  fallbackToNative: true,
66
+ runtime: 'demo',
66
67
  });
67
68
  ```
68
69
 
@@ -76,10 +77,18 @@ install({
76
77
  | openDialog(element) | 任意要素の表示 | Promise<void> |
77
78
  | closeDialog(element) | 任意要素の非表示 | Promise<void> |
78
79
  | addErrorMessage(target, message) | 管理対象エラーメッセージの追加 | Promise<void> |
80
+ | addMessage(target, message, level?) | レベル付き管理対象メッセージを追加(`'error'` \| `'success'` \| `'warning'` \| `'info'`)。再呼び出し時は Bootstrap 検証クラス(`is-invalid` / `is-valid`)も切り替わります。 | Promise<void> |
79
81
  | clearMessages(parentOrTarget) | 管理対象メッセージのみ削除 | Promise<void> |
80
- | install(options) | Bootstrap 対応 Haori を再適用し設定を上書き | void |
82
+ | install(options) | Bootstrap 対応 Haori を再適用し、runtime を含めて設定を上書き | void |
81
83
  | uninstall() | 元の Haori 実装を復元 | void |
82
84
 
85
+ ### install オプション
86
+
87
+ | オプション | 型 | デフォルト | 説明 |
88
+ | ---- | ---- | ---- | ---- |
89
+ | toastPosition | `'top-start' \| 'top-center' \| 'top-end' \| 'bottom-start' \| 'bottom-center' \| 'bottom-end'` | `'bottom-end'` | トーストコンテナの表示位置。変更は次のトースト表示時に反映されます。 |
90
+ | toastDelay | `number` | Bootstrap デフォルト (5000ms) | トースト通知の自動非表示までの時間 (ms)。 |
91
+
83
92
  ## Procedure 連携例
84
93
 
85
94
  既存の Procedure は、data-click-* と data-click-*-message をそのまま利用できます。
@@ -130,16 +139,16 @@ push 後に、そのタグから GitHub Release を published にします。公
130
139
  次回 patch リリースの例:
131
140
 
132
141
  ```bash
133
- # version が 0.2.1 になる
142
+ # version が 0.3.1 になる
134
143
  npm version patch
135
144
  git push origin main --follow-tags
136
145
  ```
137
146
 
138
- その後、push 済みタグの GitHub Release を作成して published にします。例として次回は `0.2.1` タグになります。
147
+ その後、push 済みタグの GitHub Release を作成して published にします。例として次回は `0.3.1` タグになります。
139
148
 
140
149
  自動公開:
141
150
 
142
- - `npm version patch` で、src/index.ts の公開用 `version` 定数も package.json と同期されます。
151
+ - `npm version patch` で、src/index.ts の公開用 `version` 定数、README の例、CDN デモ、Playwright の CDN 確認も package.json と同期されます。
143
152
  - publish-on-release.yml がパッケージを build し、npm publish を実行します。
144
153
  - release-archive.yml が dist/ を build し、dist.zip を同じ GitHub Release へ添付します。
145
154
 
@@ -150,12 +159,12 @@ git push origin main --follow-tags
150
159
  - npm アカウントで 2FA を有効化している場合は、write 操作用の bypass 2FA を有効にした token を使います。
151
160
  - `NPM_TOKEN` の作成に、パッケージの事前公開は不要です。
152
161
 
153
- 名称変更後の初回 `0.2.0` 公開の例:
162
+ 名称変更後の初回 `0.3.1` 公開の例:
154
163
 
155
164
  ```bash
156
165
  git push origin main
157
- git tag 0.2.0
158
- git push origin 0.2.0
166
+ git tag 0.3.1
167
+ git push origin 0.3.1
159
168
  ```
160
169
 
161
170
  初回公開チェックリスト:
@@ -170,6 +179,7 @@ git push origin 0.2.0
170
179
 
171
180
  - English README: [README.md](README.md)
172
181
  - 初期設計書: [doc/Haori.js Bootstrap初期設計書.md](doc/Haori.js Bootstrap初期設計書.md)
182
+ - ブラウザデモ時の Procedure 挙動提案: [doc/ブラウザデモ時Procedure挙動仕様提案.md](doc/%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%83%87%E3%83%A2%E6%99%82Procedure%E6%8C%99%E5%8B%95%E4%BB%95%E6%A7%98%E6%8F%90%E6%A1%88.md)
173
183
  - 変更履歴: [CHANGELOG.md](CHANGELOG.md)
174
184
 
175
185
  ## 補足
@@ -178,3 +188,4 @@ git push origin 0.2.0
178
188
  - Haori.js は前提依存として扱い、本ライブラリへ同梱しません。
179
189
  - CDN でブラウザ直読み込みする場合の配布物は dist/haori-bootstrap.iife.js です。
180
190
  - npm 公開時のエントリは dist/haori-bootstrap.js、型定義は dist/index.d.ts です。
191
+ - ブラウザデモ時の通信正規化は上記の提案書で検討しており、現時点の公開 API には含めていません。
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.2.0
5
+ Version: 0.3.1
6
6
 
7
7
  ## Overview
8
8
 
@@ -13,7 +13,7 @@ Version: 0.2.0
13
13
  - Supported Bootstrap version: 5.3.x
14
14
  - Distributed formats: ESM and IIFE
15
15
 
16
- The npm package has been renamed from `haori-js-bootstrap` to `haori-bootstrap`. Existing installations should migrate to the new package name. The GitHub repository name remains unchanged.
16
+ The npm package has been renamed from `haori-js-bootstrap` to `haori-bootstrap`, and the previous package is now deprecated. Existing installations should migrate to the new package name. The GitHub repository name remains unchanged.
17
17
 
18
18
  The library replaces Haori.js static UI methods such as dialog, confirm, toast, openDialog, closeDialog, addErrorMessage, and clearMessages with Bootstrap-based behavior while keeping existing Procedure integration intact.
19
19
 
@@ -41,9 +41,9 @@ Load dependencies in this order for browser direct loading:
41
41
  rel="stylesheet"
42
42
  href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
43
43
  />
44
- <script src="https://cdn.jsdelivr.net/npm/haori@0.1.2/dist/haori.iife.js"></script>
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.2.0/dist/haori-bootstrap.iife.js"></script>
46
+ <script src="https://cdn.jsdelivr.net/npm/haori-bootstrap@0.3.1/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.
@@ -63,6 +63,7 @@ import { install } from 'haori-bootstrap';
63
63
 
64
64
  install({
65
65
  fallbackToNative: true,
66
+ runtime: 'demo',
66
67
  });
67
68
  ```
68
69
 
@@ -76,10 +77,18 @@ install({
76
77
  | openDialog(element) | Open an arbitrary dialog element | Promise<void> |
77
78
  | closeDialog(element) | Close an arbitrary dialog element | Promise<void> |
78
79
  | addErrorMessage(target, message) | Append managed error messages | Promise<void> |
80
+ | addMessage(target, message, level?) | Append a level-aware managed message (`'error'` \| `'success'` \| `'warning'` \| `'info'`). Switches Bootstrap validation classes (`is-invalid` / `is-valid`) on re-call. | Promise<void> |
79
81
  | clearMessages(parentOrTarget) | Remove only managed messages | Promise<void> |
80
- | install(options) | Re-apply Bootstrap-backed Haori with overridden options | void |
82
+ | install(options) | Re-apply Bootstrap-backed Haori with overridden options, including runtime | void |
81
83
  | uninstall() | Restore the original Haori implementation | void |
82
84
 
85
+ ### install options
86
+
87
+ | Option | Type | Default | Description |
88
+ | ---- | ---- | ---- | ---- |
89
+ | toastPosition | `'top-start' \| 'top-center' \| 'top-end' \| 'bottom-start' \| 'bottom-center' \| 'bottom-end'` | `'bottom-end'` | Toast container position. The new position takes effect the next time a toast is shown. |
90
+ | toastDelay | `number` | Bootstrap default (5000ms) | Auto-hide delay in milliseconds for toast notifications. |
91
+
83
92
  ## Procedure Integration Example
84
93
 
85
94
  Existing Procedure flows can keep using data-click-* and data-click-*-message attributes.
@@ -127,19 +136,19 @@ git push origin main --follow-tags
127
136
 
128
137
  After pushing, publish a GitHub Release from the generated version tag. The release workflow then publishes the package and uploads `dist.zip` automatically.
129
138
 
130
- Example next patch release after `0.2.0`:
139
+ Example next patch release after `0.3.1`:
131
140
 
132
141
  ```bash
133
- # version becomes 0.2.1
142
+ # version becomes 0.3.2
134
143
  npm version patch
135
144
  git push origin main --follow-tags
136
145
  ```
137
146
 
138
- Create and publish the GitHub Release for the pushed tag such as `0.2.1`.
147
+ Create and publish the GitHub Release for the pushed tag such as `0.3.2`.
139
148
 
140
149
  Release automation:
141
150
 
142
- - `npm version patch` also keeps the exported `version` constant in src/index.ts in sync.
151
+ - `npm version patch` also keeps the exported `version` constant, README examples, CDN demo, and Playwright CDN checks in sync.
143
152
  - publish-on-release.yml builds the package and runs npm publish.
144
153
  - release-archive.yml builds dist/ and uploads dist.zip to the same GitHub Release.
145
154
 
@@ -150,12 +159,12 @@ First release only:
150
159
  - If npm account 2FA is enabled, create the token with bypass 2FA for write actions.
151
160
  - The package does not need to be published already to create `NPM_TOKEN`.
152
161
 
153
- Example for the first `0.2.0` release after the package rename:
162
+ Example for the first `0.3.1` release after the package rename:
154
163
 
155
164
  ```bash
156
165
  git push origin main
157
- git tag 0.2.0
158
- git push origin 0.2.0
166
+ git tag 0.3.1
167
+ git push origin 0.3.1
159
168
  ```
160
169
 
161
170
  First release checklist:
@@ -170,6 +179,7 @@ First release checklist:
170
179
 
171
180
  - Japanese README: [README.ja.md](README.ja.md)
172
181
  - Initial design: [doc/Haori.js Bootstrap初期設計書.md](doc/Haori.js Bootstrap初期設計書.md)
182
+ - Browser demo procedure proposal: [doc/ブラウザデモ時Procedure挙動仕様提案.md](doc/%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%83%87%E3%83%A2%E6%99%82Procedure%E6%8C%99%E5%8B%95%E4%BB%95%E6%A7%98%E6%8F%90%E6%A1%88.md)
173
183
  - Changelog: [CHANGELOG.md](CHANGELOG.md)
174
184
 
175
185
  ## Notes
@@ -178,3 +188,4 @@ First release checklist:
178
188
  - Haori.js is treated as a prerequisite and is not bundled into this package.
179
189
  - Browser direct loading for CDN consumers uses dist/haori-bootstrap.iife.js.
180
190
  - The published npm entry is dist/haori-bootstrap.js with types at dist/index.d.ts.
191
+ - Browser demo transport normalization is discussed in the proposal document above and is not part of the current public API.
@@ -63,6 +63,15 @@ export declare class BootstrapHaori {
63
63
  * @return 完了時に解決される Promise。
64
64
  */
65
65
  static addErrorMessage(target: HTMLElement, message: string): Promise<void>;
66
+ /**
67
+ * 管理対象のメッセージをレベル付きで追加する。
68
+ *
69
+ * @param target 追加先の要素。
70
+ * @param message 表示するメッセージ。
71
+ * @param level メッセージレベル (error / success / warning / info)。省略時は error。
72
+ * @return 完了時に解決される Promise。
73
+ */
74
+ static addMessage(target: HTMLElement, message: string, level?: string): Promise<void>;
66
75
  /**
67
76
  * 管理対象のメッセージを削除する。
68
77
  *
@@ -1,4 +1,4 @@
1
- import { BootstrapModalConstructor, BootstrapModalInstance, BootstrapModalOptions, BootstrapNamespace, BootstrapToastConstructor, BootstrapToastInstance } from './types';
1
+ import { BootstrapModalConstructor, BootstrapModalInstance, BootstrapModalOptions, BootstrapNamespace, BootstrapToastConstructor, BootstrapToastInstance, BootstrapToastOptions } from './types';
2
2
  /**
3
3
  * Bootstrap の Modal コンストラクターを返す。
4
4
  *
@@ -39,7 +39,8 @@ export declare function createModalInstance(element: HTMLElement, options?: Boot
39
39
  * Toast インスタンスを取得または生成する。
40
40
  *
41
41
  * @param element 対象要素。
42
+ * @param toastOptions Toast 設定。
42
43
  * @param bootstrap Bootstrap 名前空間。
43
44
  * @return Toast インスタンス。生成できない場合は undefined。
44
45
  */
45
- export declare function createToastInstance(element: HTMLElement, bootstrap?: BootstrapNamespace): BootstrapToastInstance | undefined;
46
+ export declare function createToastInstance(element: HTMLElement, toastOptions?: BootstrapToastOptions, bootstrap?: BootstrapNamespace): BootstrapToastInstance | undefined;
@@ -1,3 +1,3 @@
1
- var HaoriBootstrap=(function(m){"use strict";function P(e){return typeof e=="function"}function _(e){return P(e?.Modal)?e?.Modal:void 0}function x(e){return P(e?.Toast)?e?.Toast:void 0}function E(e){return!!_(e)}function Y(e){return!!x(e)}function C(e,t,o){const n=_(o);if(n)return typeof n.getOrCreateInstance=="function"?n.getOrCreateInstance(e,t):new n(e,t)}function Z(e,t){const o=x(t);if(o)return typeof o.getOrCreateInstance=="function"?o.getOrCreateInstance(e):new o(e)}const ee="data-haori-bootstrap-dialog",v="data-haori-bootstrap-action";function D(){return{backdrop:"static"}}function R(e,t){if(t.dialogContainerSelector){const o=e.querySelector(t.dialogContainerSelector);if(o)return o}return e.body}function q(e,t,o){const n=e.createElement("div");n.className="modal fade",n.tabIndex=-1,n.setAttribute(ee,"true"),n.setAttribute("aria-hidden","true");const r=e.createElement("div");r.className="modal-dialog modal-dialog-centered";const i=e.createElement("div");i.className="modal-content";const u=e.createElement("div");u.className="modal-body";const a=e.createElement("p");a.className="mb-0",a.style.whiteSpace="pre-line",a.textContent=t,u.appendChild(a);const s=e.createElement("div");if(s.className="modal-footer",o){const f=e.createElement("button");f.type="button",f.className="btn btn-secondary",f.setAttribute(v,"cancel"),f.textContent="Cancel",s.appendChild(f)}const c=e.createElement("button");return c.type="button",c.className="btn btn-primary",c.setAttribute(v,"ok"),c.textContent="OK",s.appendChild(c),i.append(u,s),r.appendChild(i),n.appendChild(r),n}function te(e,t){const o=globalThis.document,n=q(o,e,!1);R(o,t).appendChild(n);const r=C(n,D(),t.bootstrap);return r?new Promise((i,u)=>{const a=()=>{n.removeEventListener("hidden.bs.modal",s),n.remove(),r.dispose?.(),i()},s=()=>{a()};n.querySelector(`[${v}="ok"]`)?.addEventListener("click",()=>{r.hide()},{once:!0}),n.addEventListener("hidden.bs.modal",s,{once:!0});try{r.show()}catch(f){n.removeEventListener("hidden.bs.modal",s),n.remove(),r.dispose?.(),u(f)}}):(n.remove(),Promise.reject(new Error("Bootstrap Modal is unavailable.")))}function oe(e,t){const o=globalThis.document,n=q(o,e,!0);R(o,t).appendChild(n);const r=C(n,D(),t.bootstrap);return r?new Promise((i,u)=>{let a=!1;const s=()=>{n.removeEventListener("hidden.bs.modal",c),n.remove(),r.dispose?.(),i(a)},c=()=>{s()},f=n.querySelector(`[${v}="ok"]`),ke=n.querySelector(`[${v}="cancel"]`);f?.addEventListener("click",()=>{a=!0,r.hide()},{once:!0}),ke?.addEventListener("click",()=>{a=!1,r.hide()},{once:!0}),n.addEventListener("hidden.bs.modal",c,{once:!0});try{r.show()}catch(Be){n.removeEventListener("hidden.bs.modal",c),n.remove(),r.dispose?.(),u(Be)}}):(n.remove(),Promise.reject(new Error("Bootstrap Modal is unavailable.")))}const T="data-haori-bootstrap-owned",p="data-haori-bootstrap-message-container",h="data-haori-bootstrap-invalid-target";function M(e){return e instanceof HTMLInputElement&&(e.type==="checkbox"||e.type==="radio")}function g(e){return e instanceof HTMLInputElement&&e.type==="radio"}function I(e){return e instanceof HTMLInputElement||e instanceof HTMLSelectElement||e instanceof HTMLTextAreaElement}function N(e){return Array.from(e.children).find(t=>t instanceof HTMLElement&&t.getAttribute(p)==="true")}function ne(e,t){const o=e.createElement("div");return o.setAttribute(T,"true"),o.textContent=t,o}function re(e){return N(e)}function S(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 ie(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 $(e){const o=S(e).map(n=>n.closest(".form-check")).filter(n=>n instanceof HTMLElement);if(o.length>1){const n=ie(o);if(n&&!o.includes(n))return n}return k(e)}function k(e){const t=e.closest(".form-check");return t instanceof HTMLElement?t:void 0}function U(e){const t=e.nextElementSibling;if(t instanceof HTMLElement&&t.getAttribute(p)==="true")return t;const o=document.createElement("div");return o.className="invalid-feedback d-block",o.setAttribute(T,"true"),o.setAttribute(p,"true"),e.insertAdjacentElement("afterend",o),o}function ae(e){const t=g(e)?$(e):k(e);if(!t)return U(e);const o=N(t);if(o)return o;const n=document.createElement("div");return n.className="invalid-feedback d-block",n.setAttribute(T,"true"),n.setAttribute(p,"true"),t.appendChild(n),n}function se(e){const t=re(e);if(t)return t;const o=document.createElement("div");return o.className="alert alert-danger",o.setAttribute("role","alert"),o.setAttribute(T,"true"),o.setAttribute(p,"true"),e.insertAdjacentElement("afterbegin",o),o}function B(e){e.getAttribute(h)==="true"&&(e.classList.remove("is-invalid"),e.removeAttribute(h))}function ce(e){(g(e)?S(e):[e]).forEach(o=>{o.classList.add("is-invalid"),o.setAttribute(h,"true")})}function le(e){(g(e)?S(e):[e]).forEach(o=>{B(o)})}function ue(e,t){return(M(e)?ae(e):I(e)?U(e):se(e)).appendChild(ne(document,t)),M(e)?ce(e):I(e)&&(e.classList.add("is-invalid"),e.setAttribute(h,"true")),Promise.resolve()}function de(e){if(M(e)){const n=g(e)?$(e):k(e);(n?N(n):void 0)?.remove(),le(e)}else if(I(e)){const n=e.nextElementSibling;n instanceof HTMLElement&&n.getAttribute(p)==="true"&&n.remove(),B(e)}return e.querySelectorAll(`[${p}="true"]`).forEach(n=>{n.remove()}),e.querySelectorAll(`[${h}="true"]`).forEach(n=>{B(n)}),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 fe(e,t){z(e);const o=C(e,void 0,t.bootstrap);return o?(o.show(),Promise.resolve()):Promise.reject(new Error("Bootstrap Modal is unavailable."))}function me(e,t){z(e);const o=C(e,void 0,t.bootstrap);return o?(o.hide(),Promise.resolve()):Promise.reject(new Error("Bootstrap Modal is unavailable."))}const W="data-haori-bootstrap-toast-container",pe="data-haori-bootstrap-toast",be="data-haori-bootstrap-toast-accent";function ve(e){switch(e){case"warning":return{accentClassName:"bg-warning"};case"error":return{accentClassName:"bg-danger"};default:return{accentClassName:"bg-info"}}}function he(e,t){if(t.toastContainerSelector){const o=e.querySelector(t.toastContainerSelector);if(o)return o}return e.body}function Ee(e,t){const o=he(e,t),n=o.querySelector(`[${W}="true"]`);if(n)return n;const r=e.createElement("div");return r.className="toast-container position-fixed bottom-0 end-0 p-3",r.setAttribute(W,"true"),o.appendChild(r),r}function Ce(e,t,o){const n=globalThis.document,r=ve(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(pe,"true");const u=n.createElement("div");u.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(be,"true");const s=n.createElement("div");s.className="toast-body",s.style.whiteSpace="pre-line",s.textContent=e,u.appendChild(a),u.appendChild(s),i.appendChild(u),Ee(n,o).appendChild(i);const c=Z(i,o.bootstrap);if(!c)return i.remove(),Promise.reject(new Error("Bootstrap Toast is unavailable."));i.addEventListener("hidden.bs.toast",()=>{i.remove(),c.dispose?.()},{once:!0});try{return c.show(),Promise.resolve()}catch(f){return i.remove(),c.dispose?.(),Promise.reject(f)}}let l={options:{fallbackToNative:!0}};function b(e){return e.replace(/\\n/g,`
2
- `)}function O(){return globalThis.window}function H(e){return Promise.resolve(e).then(()=>{})}function A(e){const t=l.originalHaori?.[e];return typeof t=="function"?t:void 0}function w(e){console.warn(`[haori-bootstrap] ${e} skipped because Bootstrap support is unavailable.`)}function F(e){const t=b(e),o=A("dialog");if(o)return H(o(t));const n=O();return l.options.fallbackToNative&&typeof n?.alert=="function"?(n.alert(t),Promise.resolve()):(w("dialog"),Promise.resolve())}function G(e){const t=b(e),o=A("confirm");if(o)return Promise.resolve(o(t)).then(r=>!!r);const n=O();return l.options.fallbackToNative&&typeof n?.confirm=="function"?Promise.resolve(n.confirm(t)):(w("confirm"),Promise.resolve(!1))}function j(e,t){const o=b(e),n=A("toast");return n?H(n(o,t)):(w("toast"),Promise.resolve())}function y(e,t){const o=A(e);return o?H(o(t)):(w(e),Promise.resolve())}function Te(e){l=e}class K{static dialog(t){const o=b(t);return E(l.options.bootstrap)?te(o,l.options).catch(()=>F(o)):F(o)}static confirm(t){const o=b(t);return E(l.options.bootstrap)?oe(o,l.options).catch(()=>G(o)):G(o)}static toast(t,o){const n=b(t);return Y(l.options.bootstrap)?Ce(n,o,l.options).catch(()=>j(n,o)):j(n,o)}static openDialog(t){return E(l.options.bootstrap)?fe(t,l.options).catch(()=>y("openDialog",t)):y("openDialog",t)}static closeDialog(t){return E(l.options.bootstrap)?me(t,l.options).catch(()=>y("closeDialog",t)):y("closeDialog",t)}static addErrorMessage(t,o){return ue(t,o)}static clearMessages(t){return de(t)}}const V={fallbackToNative:!0},d={installed:!1,options:V};function L(){return globalThis.window}function ge(e,t){return{bootstrap:e.bootstrap??t?.bootstrap,fallbackToNative:e.fallbackToNative??V.fallbackToNative,toastContainerSelector:e.toastContainerSelector,dialogContainerSelector:e.dialogContainerSelector}}function J(e=L()){return!!(e?.Haori&&e.bootstrap)}function Q(e={}){const t=L();if(!t?.Haori)throw new Error("window.Haori is required before calling install().");d.originalHaori||(d.originalHaori=t.Haori),d.options=ge(e,t),Te({originalHaori:d.originalHaori,options:d.options}),t.Haori=K,d.installed=!0}function Ae(){const e=L();!e||!d.originalHaori||(e.Haori=d.originalHaori,d.installed=!1,d.originalHaori=void 0)}function we(){return d.installed}const X="__haoriJsBootstrapAutoEnabled__";function ye(){return globalThis.window}function Me(e){return!!e[X]}function Ie(e){e[X]=!0}function Ne(){const e=ye();if(!(!e||Me(e))){if(!J(e)){console.warn("[haori-bootstrap] Auto-enable skipped because window.Haori or window.bootstrap is missing.");return}try{Q({bootstrap:e.bootstrap}),Ie(e)}catch(t){console.warn("[haori-bootstrap] Auto-enable failed.",t)}}}Ne();const Se="0.2.0";return m.BootstrapHaori=K,m.hasAutoEnablePrerequisites=J,m.install=Q,m.isInstalled=we,m.uninstall=Ae,m.version=Se,Object.defineProperty(m,Symbol.toStringTag,{value:"Module"}),m})({});
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})({});
3
3
  //# sourceMappingURL=haori-bootstrap.iife.js.map