Skip to main content

max / makenotwork

1.4 KB · 38 lines History Blame Raw
1 // Button loading-state helpers ported from mnw.js:343,407. The delegated HTMX
2 // loading listeners (beforeRequest/afterRequest/etc.) live in htmx-glue (Phase-1
3 // cutover); these two are the reusable pieces feature code calls directly.
4
5 /**
6 * Resolve the button that should reflect loading state for an interaction.
7 * Preference: the element itself if it's a `<button>`, else the submit/primary
8 * button in the closest form. Ported from mnw.js:343.
9 */
10 export function resolveHtmxLoadingButton(elt: Element | null | undefined): HTMLButtonElement | null {
11 if (elt && elt.tagName === 'BUTTON') return elt as HTMLButtonElement;
12 const form = elt?.closest?.('form');
13 return form ? form.querySelector<HTMLButtonElement>('button[type="submit"], .primary') : null;
14 }
15
16 /**
17 * Wrap an async operation with button loading state for plain `fetch()` flows
18 * (non-HTMX), restoring text + enabled state on completion regardless of
19 * outcome. Ported from mnw.js:407.
20 */
21 export function withLoadingState<T>(
22 btn: HTMLButtonElement | null,
23 loadingText: string,
24 fn: () => Promise<T> | T,
25 ): Promise<T> {
26 if (!btn) return Promise.resolve().then(fn);
27 const origText = btn.textContent;
28 const origDisabled = btn.disabled;
29 btn.textContent = loadingText;
30 btn.disabled = true;
31 return Promise.resolve()
32 .then(fn)
33 .finally(() => {
34 btn.textContent = origText;
35 btn.disabled = origDisabled;
36 });
37 }
38