@inertiaui/modal-react 2.1.0 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1841 +1,1617 @@
1
- import React, { createContext, useContext, useRef, useEffect, useReducer, useState, createElement, useMemo, forwardRef, useImperativeHandle, useCallback } from "react";
2
- import { jsxs, Fragment, jsx } from "react/jsx-runtime";
3
- import Axios from "axios";
4
- import { generateId as generateId$1, sameUrlPath, kebabCase, except, animate, createFocusTrap, onEscapeKey, cancelAnimations, lockScroll, markAriaHidden, isStandardDomEvent, rejectNullValues, only } from "@inertiaui/vanilla";
5
- import * as vanilla from "@inertiaui/vanilla";
6
- import { usePage, router, progress } from "@inertiajs/react";
1
+ import * as dialogUtils from "@inertiaui/vanilla";
2
+ import { animate, cancelAnimations, createFocusTrap, except, generateId, isStandardDomEvent, kebabCase, lockScroll, markAriaHidden, onEscapeKey, only, rejectNullValues, sameUrlPath } from "@inertiaui/vanilla";
3
+ import React, { createContext, createElement, forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useMemo, useReducer, useRef, useState } from "react";
7
4
  import { mergeDataIntoQueryString } from "@inertiajs/core";
5
+ import { progress, router, usePage } from "@inertiajs/react";
6
+ import Axios from "axios";
7
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { createPortal } from "react-dom";
9
- const defaultConfig = {
10
- type: "modal",
11
- navigate: false,
12
- useNativeDialog: true,
13
- appElement: "#app",
14
- modal: {
15
- closeButton: true,
16
- closeExplicitly: false,
17
- closeOnClickOutside: true,
18
- maxWidth: "2xl",
19
- paddingClasses: "p-4 sm:p-6",
20
- panelClasses: "bg-white rounded",
21
- position: "center"
22
- },
23
- slideover: {
24
- closeButton: true,
25
- closeExplicitly: false,
26
- closeOnClickOutside: true,
27
- maxWidth: "md",
28
- paddingClasses: "p-4 sm:p-6",
29
- panelClasses: "bg-white min-h-screen",
30
- position: "right"
31
- }
9
+ //#region src/config.ts
10
+ var defaultConfig = {
11
+ type: "modal",
12
+ navigate: false,
13
+ useNativeDialog: true,
14
+ appElement: "#app",
15
+ modal: {
16
+ closeButton: true,
17
+ closeExplicitly: false,
18
+ closeOnClickOutside: true,
19
+ maxWidth: "2xl",
20
+ paddingClasses: "p-4 sm:p-6",
21
+ panelClasses: "bg-white rounded",
22
+ position: "center"
23
+ },
24
+ slideover: {
25
+ closeButton: true,
26
+ closeExplicitly: false,
27
+ closeOnClickOutside: true,
28
+ maxWidth: "md",
29
+ paddingClasses: "p-4 sm:p-6",
30
+ panelClasses: "bg-white min-h-screen",
31
+ position: "right"
32
+ }
32
33
  };
33
- class Config {
34
- constructor() {
35
- this.config = {};
36
- this.reset();
37
- }
38
- reset() {
39
- this.config = JSON.parse(JSON.stringify(defaultConfig));
40
- }
41
- put(key, value) {
42
- if (typeof key === "object") {
43
- this.config = {
44
- type: key.type ?? defaultConfig.type,
45
- navigate: key.navigate ?? defaultConfig.navigate,
46
- useNativeDialog: key.useNativeDialog ?? defaultConfig.useNativeDialog,
47
- appElement: key.appElement !== void 0 ? key.appElement : defaultConfig.appElement,
48
- modal: { ...defaultConfig.modal, ...key.modal ?? {} },
49
- slideover: { ...defaultConfig.slideover, ...key.slideover ?? {} }
50
- };
51
- return;
52
- }
53
- const keys = key.split(".");
54
- let current = this.config;
55
- for (let i = 0; i < keys.length - 1; i++) {
56
- current = current[keys[i]] = current[keys[i]] || {};
57
- }
58
- current[keys[keys.length - 1]] = value;
59
- }
60
- get(key) {
61
- if (typeof key === "undefined") {
62
- return this.config;
63
- }
64
- const keys = key.split(".");
65
- let current = this.config;
66
- for (const k of keys) {
67
- if (current === null || current === void 0 || typeof current !== "object") {
68
- return null;
69
- }
70
- current = current[k];
71
- }
72
- return current === void 0 ? null : current;
73
- }
74
- }
75
- const configInstance = new Config();
76
- const resetConfig = () => configInstance.reset();
77
- const putConfig = (key, value) => configInstance.put(key, value);
78
- const getConfig = (key) => configInstance.get(key);
79
- const getConfigByType = (isSlideover, key) => configInstance.get(isSlideover ? `slideover.${key}` : `modal.${key}`);
80
- function generateId(prefix = "inertiaui_") {
81
- return generateId$1(prefix);
34
+ var Config = class {
35
+ constructor() {
36
+ this.config = {};
37
+ this.reset();
38
+ }
39
+ reset() {
40
+ this.config = JSON.parse(JSON.stringify(defaultConfig));
41
+ }
42
+ put(key, value) {
43
+ if (typeof key === "object") {
44
+ this.config = {
45
+ type: key.type ?? defaultConfig.type,
46
+ navigate: key.navigate ?? defaultConfig.navigate,
47
+ useNativeDialog: key.useNativeDialog ?? defaultConfig.useNativeDialog,
48
+ appElement: key.appElement !== void 0 ? key.appElement : defaultConfig.appElement,
49
+ modal: {
50
+ ...defaultConfig.modal,
51
+ ...key.modal
52
+ },
53
+ slideover: {
54
+ ...defaultConfig.slideover,
55
+ ...key.slideover
56
+ }
57
+ };
58
+ return;
59
+ }
60
+ const keys = key.split(".");
61
+ let current = this.config;
62
+ for (let i = 0; i < keys.length - 1; i++) current = current[keys[i]] = current[keys[i]] || {};
63
+ current[keys[keys.length - 1]] = value;
64
+ }
65
+ get(key) {
66
+ if (typeof key === "undefined") return this.config;
67
+ const keys = key.split(".");
68
+ let current = this.config;
69
+ for (const k of keys) {
70
+ if (current === null || current === void 0 || typeof current !== "object") return null;
71
+ current = current[k];
72
+ }
73
+ return current === void 0 ? null : current;
74
+ }
75
+ };
76
+ var configInstance = new Config();
77
+ var resetConfig = () => configInstance.reset();
78
+ var putConfig = (key, value) => configInstance.put(key, value);
79
+ var getConfig = (key) => configInstance.get(key);
80
+ var getConfigByType = (isSlideover, key) => configInstance.get(isSlideover ? `slideover.${key}` : `modal.${key}`);
81
+ //#endregion
82
+ //#region src/helpers.ts
83
+ var generateIdUsingCallback = null;
84
+ function generateId$1(prefix = "inertiaui_") {
85
+ if (generateIdUsingCallback) return generateIdUsingCallback();
86
+ return generateId(prefix);
82
87
  }
83
- const ModalStackContext = createContext(null);
88
+ //#endregion
89
+ //#region src/ModalRoot.tsx
90
+ var ModalStackContext = createContext(null);
84
91
  ModalStackContext.displayName = "ModalStackContext";
85
- let pageVersion = null;
86
- let resolveComponent = null;
87
- let baseUrl = null;
88
- let closingToBaseUrlTarget = null;
89
- const prefetchCache = /* @__PURE__ */ new Map();
90
- const prefetchInFlight = /* @__PURE__ */ new Map();
92
+ var pageVersion = null;
93
+ var resolveComponent = null;
94
+ var baseUrl = null;
95
+ var closingToBaseUrlTarget = null;
96
+ var prefetchCache = /* @__PURE__ */ new Map();
97
+ var prefetchInFlight = /* @__PURE__ */ new Map();
91
98
  function getPrefetchCacheKey(url, method, data) {
92
- return `${method}:${url}:${JSON.stringify(data)}`;
99
+ return `${method}:${url}:${JSON.stringify(data)}`;
93
100
  }
94
101
  function getCachedResponse(url, method, data) {
95
- const key = getPrefetchCacheKey(url, method, data);
96
- const cached = prefetchCache.get(key);
97
- if (!cached) {
98
- return null;
99
- }
100
- if (Date.now() > cached.expiresAt) {
101
- prefetchCache.delete(key);
102
- return null;
103
- }
104
- return cached.response;
102
+ const key = getPrefetchCacheKey(url, method, data);
103
+ const cached = prefetchCache.get(key);
104
+ if (!cached) return null;
105
+ if (Date.now() > cached.expiresAt) {
106
+ prefetchCache.delete(key);
107
+ return null;
108
+ }
109
+ return cached.response;
105
110
  }
106
111
  function setCachedResponse(url, method, data, response, cacheFor) {
107
- const key = getPrefetchCacheKey(url, method, data);
108
- prefetchCache.set(key, {
109
- response,
110
- timestamp: Date.now(),
111
- expiresAt: Date.now() + cacheFor
112
- });
112
+ const key = getPrefetchCacheKey(url, method, data);
113
+ prefetchCache.set(key, {
114
+ response,
115
+ timestamp: Date.now(),
116
+ expiresAt: Date.now() + cacheFor
117
+ });
113
118
  }
114
119
  function prefetch(href, options = {}) {
115
- if (href.startsWith("#")) {
116
- return Promise.resolve();
117
- }
118
- const method = (options.method ?? "get").toLowerCase();
119
- const data = options.data ?? {};
120
- const headers = options.headers ?? {};
121
- const queryStringArrayFormat = options.queryStringArrayFormat ?? "brackets";
122
- const cacheFor = options.cacheFor ?? 3e4;
123
- const [url, mergedData] = mergeDataIntoQueryString(method, href || "", data, queryStringArrayFormat);
124
- const cached = getCachedResponse(url, method, mergedData);
125
- if (cached) {
126
- return Promise.resolve();
127
- }
128
- const cacheKey = getPrefetchCacheKey(url, method, mergedData);
129
- const inFlight = prefetchInFlight.get(cacheKey);
130
- if (inFlight) {
131
- return inFlight.then(() => {
132
- });
133
- }
134
- options.onPrefetching?.();
135
- const requestHeaders = {
136
- ...headers,
137
- Accept: "text/html, application/xhtml+xml",
138
- "X-Requested-With": "XMLHttpRequest",
139
- "X-Inertia": "true",
140
- "X-Inertia-Version": pageVersion ?? "",
141
- "X-InertiaUI-Modal": generateId(),
142
- "X-InertiaUI-Modal-Base-Url": baseUrl ?? ""
143
- };
144
- const request = Axios({
145
- url,
146
- method,
147
- data: mergedData,
148
- headers: requestHeaders
149
- }).then((response) => {
150
- setCachedResponse(url, method, mergedData, response, cacheFor);
151
- options.onPrefetched?.();
152
- return response;
153
- }).finally(() => {
154
- prefetchInFlight.delete(cacheKey);
155
- });
156
- prefetchInFlight.set(cacheKey, request);
157
- return request.then(() => {
158
- });
120
+ if (href.startsWith("#")) return Promise.resolve();
121
+ const method = (options.method ?? "get").toLowerCase();
122
+ const data = options.data ?? {};
123
+ const headers = options.headers ?? {};
124
+ const queryStringArrayFormat = options.queryStringArrayFormat ?? "brackets";
125
+ const cacheFor = options.cacheFor ?? 3e4;
126
+ const [url, mergedData] = mergeDataIntoQueryString(method, href || "", data, queryStringArrayFormat);
127
+ if (getCachedResponse(url, method, mergedData)) return Promise.resolve();
128
+ const cacheKey = getPrefetchCacheKey(url, method, mergedData);
129
+ const inFlight = prefetchInFlight.get(cacheKey);
130
+ if (inFlight) return inFlight.then(() => {});
131
+ options.onPrefetching?.();
132
+ const request = Axios({
133
+ url,
134
+ method,
135
+ data: mergedData,
136
+ headers: {
137
+ ...headers,
138
+ Accept: "text/html, application/xhtml+xml",
139
+ "X-Requested-With": "XMLHttpRequest",
140
+ "X-Inertia": "true",
141
+ "X-Inertia-Version": pageVersion ?? "",
142
+ "X-InertiaUI-Modal": generateId$1(),
143
+ "X-InertiaUI-Modal-Base-Url": baseUrl ?? ""
144
+ }
145
+ }).then((response) => {
146
+ setCachedResponse(url, method, mergedData, response, cacheFor);
147
+ options.onPrefetched?.();
148
+ return response;
149
+ }).finally(() => {
150
+ prefetchInFlight.delete(cacheKey);
151
+ });
152
+ prefetchInFlight.set(cacheKey, request);
153
+ return request.then(() => {});
159
154
  }
160
- const ModalStackProvider = ({ children }) => {
161
- const stackRef = useRef([]);
162
- const [, forceUpdate] = useReducer((x) => x + 1, 0);
163
- const [localModals, setLocalModals] = useState({});
164
- const updateStack = (withStack) => {
165
- const newStack = withStack([...stackRef.current]);
166
- const isOnTopOfStack = (modalId) => {
167
- if (newStack.length < 2) {
168
- return true;
169
- }
170
- return newStack.map((modal) => ({ id: modal.id, shouldRender: modal.shouldRender })).reverse().find((modal) => modal.shouldRender)?.id === modalId;
171
- };
172
- newStack.forEach((modal, index) => {
173
- newStack[index].onTopOfStack = isOnTopOfStack(modal.id);
174
- newStack[index].getParentModal = () => {
175
- if (index < 1) {
176
- return null;
177
- }
178
- return stackRef.current.slice(0, index).reverse().find((m) => m.isOpen) ?? null;
179
- };
180
- newStack[index].getChildModal = () => {
181
- if (index === stackRef.current.length - 1) {
182
- return null;
183
- }
184
- return stackRef.current.slice(index + 1).find((m) => m.isOpen) ?? null;
185
- };
186
- });
187
- stackRef.current = newStack;
188
- forceUpdate();
189
- };
190
- class ModalClass {
191
- constructor(component, response, config, onClose, afterLeave) {
192
- this.show = () => {
193
- updateStack(
194
- (prevStack) => prevStack.map((modal) => {
195
- if (modal.id === this.id && !modal.isOpen) {
196
- modal.isOpen = true;
197
- modal.shouldRender = true;
198
- }
199
- return modal;
200
- })
201
- );
202
- };
203
- this.setOpen = (open) => {
204
- if (open) {
205
- this.show();
206
- } else {
207
- this.close();
208
- }
209
- };
210
- this.close = () => {
211
- updateStack((currentStack) => {
212
- let modalClosed = false;
213
- const newStack = currentStack.map((modal) => {
214
- if (modal.id === this.id && modal.isOpen) {
215
- Object.keys(modal.listeners).forEach((event) => {
216
- modal.off(event);
217
- });
218
- modal.isOpen = false;
219
- modal.onCloseCallback?.();
220
- modalClosed = true;
221
- }
222
- return modal;
223
- });
224
- return modalClosed ? newStack : currentStack;
225
- });
226
- };
227
- this.afterLeave = () => {
228
- if (this.isOpen) {
229
- return;
230
- }
231
- updateStack((prevStack) => {
232
- const updatedStack = prevStack.map((modal) => {
233
- if (modal.id === this.id && !modal.isOpen) {
234
- modal.shouldRender = false;
235
- modal.afterLeaveCallback?.();
236
- modal.afterLeaveCallback = null;
237
- }
238
- return modal;
239
- });
240
- if (this.index === 0) {
241
- const savedBaseUrl = baseUrl;
242
- baseUrl = null;
243
- closingToBaseUrlTarget = savedBaseUrl;
244
- if (savedBaseUrl && typeof window !== "undefined" && !sameUrlPath(savedBaseUrl, window.location.href)) {
245
- router.push({
246
- url: savedBaseUrl,
247
- preserveScroll: true,
248
- preserveState: true,
249
- // Clear _inertiaui_modal prop to prevent modal from reopening
250
- props: (currentProps) => {
251
- const { _inertiaui_modal, ...rest } = currentProps;
252
- return { ...rest, _inertiaui_modal: void 0 };
253
- }
254
- });
255
- }
256
- return [];
257
- }
258
- return updatedStack;
259
- });
260
- };
261
- this.on = (event, callback) => {
262
- event = kebabCase(event);
263
- this.listeners[event] = this.listeners[event] ?? [];
264
- this.listeners[event].push(callback);
265
- };
266
- this.off = (event, callback) => {
267
- event = kebabCase(event);
268
- if (callback) {
269
- this.listeners[event] = this.listeners[event]?.filter((cb) => cb !== callback) ?? [];
270
- } else {
271
- delete this.listeners[event];
272
- }
273
- };
274
- this.emit = (event, ...args) => {
275
- this.listeners[kebabCase(event)]?.forEach((callback) => callback(...args));
276
- };
277
- this.registerEventListenersFromProps = (props) => {
278
- const unsubscribers = [];
279
- Object.keys(props).filter((key) => key.startsWith("on")).forEach((key) => {
280
- const eventName = kebabCase(key).replace(/^on-/, "");
281
- const callback = props[key];
282
- this.on(eventName, callback);
283
- unsubscribers.push(() => this.off(eventName, callback));
284
- });
285
- return () => unsubscribers.forEach((unsub) => unsub());
286
- };
287
- this.reload = (options = {}) => {
288
- let keys = Object.keys(this.response.props);
289
- if (options.only) {
290
- keys = options.only;
291
- }
292
- if (options.except) {
293
- keys = except(keys, options.except);
294
- }
295
- if (!this.response?.url) {
296
- return;
297
- }
298
- const method = (options.method ?? "get").toLowerCase();
299
- const data = options.data ?? {};
300
- options.onStart?.();
301
- Axios({
302
- url: this.response.url,
303
- method,
304
- data: method === "get" ? {} : data,
305
- params: method === "get" ? data : {},
306
- headers: {
307
- ...options.headers ?? {},
308
- Accept: "text/html, application/xhtml+xml",
309
- "X-Inertia": "true",
310
- "X-Inertia-Partial-Component": this.response.component,
311
- "X-Inertia-Version": this.response.version ?? "",
312
- "X-Inertia-Partial-Data": keys.join(","),
313
- "X-InertiaUI-Modal": generateId(),
314
- "X-InertiaUI-Modal-Base-Url": baseUrl ?? ""
315
- }
316
- }).then((response2) => {
317
- this.updateProps(response2.data.props);
318
- options.onSuccess?.(response2);
319
- }).catch((error) => {
320
- options.onError?.(error);
321
- }).finally(() => {
322
- options.onFinish?.();
323
- });
324
- };
325
- this.updateProps = (props) => {
326
- Object.assign(this.props, props);
327
- updateStack((prevStack) => prevStack);
328
- };
329
- this.id = response.id ?? generateId();
330
- this.isOpen = false;
331
- this.shouldRender = false;
332
- this.listeners = {};
333
- this.component = component;
334
- this.props = response.props ?? {};
335
- this.response = response;
336
- this.config = config ?? {};
337
- this.onCloseCallback = onClose ?? null;
338
- this.afterLeaveCallback = afterLeave ?? null;
339
- this.index = -1;
340
- this.getParentModal = () => null;
341
- this.getChildModal = () => null;
342
- this.onTopOfStack = true;
343
- }
344
- }
345
- const isValidModalResponse = (data) => {
346
- return typeof data === "object" && data !== null && "component" in data && typeof data.component === "string";
347
- };
348
- const pushFromResponseData = (responseData, config = {}, onClose = null, onAfterLeave = null) => {
349
- if (!resolveComponent) {
350
- return Promise.reject(new Error("resolveComponent not set"));
351
- }
352
- if (!isValidModalResponse(responseData)) {
353
- return Promise.reject(
354
- new Error(
355
- "Invalid modal response. This usually happens when the server returns a redirect (e.g., due to session expiration). Check if the user is still authenticated."
356
- )
357
- );
358
- }
359
- return resolveComponent(responseData.component).then(
360
- (component) => push(component, responseData, config, onClose, onAfterLeave)
361
- );
362
- };
363
- const loadDeferredProps = (modal) => {
364
- const deferred = modal.response?.meta?.deferredProps;
365
- if (!deferred) {
366
- return;
367
- }
368
- Object.keys(deferred).forEach((key) => {
369
- modal.reload({ only: deferred[key] });
370
- });
371
- };
372
- const push = (component, response, config, onClose, afterLeave) => {
373
- const newModal = new ModalClass(component, response, config, onClose, afterLeave);
374
- newModal.index = stackRef.current.length;
375
- updateStack((prevStack) => [...prevStack, newModal]);
376
- loadDeferredProps(newModal);
377
- newModal.show();
378
- return newModal;
379
- };
380
- function pushLocalModal(name, config, onClose, afterLeave, props) {
381
- if (!localModals[name]) {
382
- throw new Error(`The local modal "${name}" has not been registered.`);
383
- }
384
- const responseData = { props: props ?? {} };
385
- const modal = push(null, responseData, config, onClose, afterLeave);
386
- modal.name = name;
387
- localModals[name].callback(modal);
388
- return modal;
389
- }
390
- const visitModal = (url, options = {}) => visit(
391
- url,
392
- options.method ?? "get",
393
- options.data ?? {},
394
- options.headers ?? {},
395
- options.config ?? {},
396
- options.onClose ?? null,
397
- options.onAfterLeave ?? null,
398
- options.queryStringArrayFormat ?? "brackets",
399
- options.navigate ?? getConfig("navigate"),
400
- options.onStart ?? null,
401
- options.onSuccess ?? null,
402
- options.onError ?? null,
403
- options.props ?? null
404
- ).then((modal) => {
405
- const listeners = options.listeners ?? {};
406
- Object.keys(listeners).forEach((event) => {
407
- const eventName = kebabCase(event);
408
- modal.on(eventName, listeners[event]);
409
- });
410
- return modal;
411
- });
412
- const updateBrowserUrl = (url, useBrowserHistory, modalData) => {
413
- if (!url || !useBrowserHistory || typeof window === "undefined") {
414
- return;
415
- }
416
- router.push({
417
- url,
418
- preserveScroll: true,
419
- preserveState: true,
420
- // Store modal data in page props for history navigation
421
- props: modalData ? (currentProps) => ({
422
- ...currentProps,
423
- _inertiaui_modal: {
424
- ...modalData,
425
- baseUrl
426
- }
427
- }) : void 0
428
- });
429
- };
430
- const visit = (href, method, payload = {}, headers = {}, config = {}, onClose = null, onAfterLeave = null, queryStringArrayFormat = "brackets", useBrowserHistory = false, onStart = null, onSuccess = null, onError = null, props = null) => {
431
- const modalId = generateId();
432
- return new Promise((resolve, reject) => {
433
- if (href.startsWith("#")) {
434
- resolve(pushLocalModal(href.substring(1), config, onClose, onAfterLeave, props));
435
- return;
436
- }
437
- const [url, data] = mergeDataIntoQueryString(method, href || "", payload, queryStringArrayFormat);
438
- const cachedResponse = getCachedResponse(url, method, data);
439
- if (cachedResponse) {
440
- onSuccess?.(cachedResponse);
441
- pushFromResponseData(cachedResponse.data, config, onClose, onAfterLeave).then((modal) => {
442
- updateBrowserUrl(cachedResponse.data.url, useBrowserHistory, cachedResponse.data);
443
- resolve(modal);
444
- }).catch(reject);
445
- return;
446
- }
447
- if (stackRef.current.length === 0) {
448
- baseUrl = typeof window !== "undefined" ? window.location.href : "";
449
- }
450
- const requestHeaders = {
451
- ...headers,
452
- Accept: "text/html, application/xhtml+xml",
453
- "X-Requested-With": "XMLHttpRequest",
454
- "X-Inertia": "true",
455
- "X-Inertia-Version": pageVersion ?? "",
456
- "X-InertiaUI-Modal": modalId,
457
- "X-InertiaUI-Modal-Base-Url": baseUrl ?? ""
458
- };
459
- onStart?.();
460
- progress?.start();
461
- Axios({
462
- url,
463
- method,
464
- data,
465
- headers: requestHeaders
466
- }).then((response) => {
467
- onSuccess?.(response);
468
- pushFromResponseData(response.data, config, onClose, onAfterLeave).then((modal) => {
469
- updateBrowserUrl(response.data.url, useBrowserHistory, response.data);
470
- resolve(modal);
471
- }).catch(reject);
472
- }).catch((...args) => {
473
- onError?.(...args);
474
- reject(args[0]);
475
- }).finally(() => {
476
- progress?.finish();
477
- });
478
- });
479
- };
480
- const registerLocalModal = (name, callback) => {
481
- setLocalModals((prevLocalModals) => ({
482
- ...prevLocalModals,
483
- [name]: { name, callback }
484
- }));
485
- };
486
- const removeLocalModal = (name) => {
487
- setLocalModals((prevLocalModals) => {
488
- const newLocalModals = { ...prevLocalModals };
489
- delete newLocalModals[name];
490
- return newLocalModals;
491
- });
492
- };
493
- const value = {
494
- get stack() {
495
- return stackRef.current;
496
- },
497
- localModals,
498
- push,
499
- pushFromResponseData,
500
- length: () => stackRef.current.length,
501
- closeAll: (force = false) => {
502
- if (force) {
503
- updateStack(() => []);
504
- } else {
505
- [...stackRef.current].reverse().forEach((modal) => modal.close());
506
- }
507
- },
508
- reset: () => updateStack(() => []),
509
- visit,
510
- visitModal,
511
- registerLocalModal,
512
- removeLocalModal
513
- };
514
- return /* @__PURE__ */ jsx(ModalStackContext.Provider, { value, children });
155
+ var ModalStackProvider = ({ children }) => {
156
+ const stackRef = useRef([]);
157
+ const [, forceUpdate] = useReducer((x) => x + 1, 0);
158
+ const [localModals, setLocalModals] = useState({});
159
+ const updateStack = (withStack) => {
160
+ const newStack = withStack([...stackRef.current]);
161
+ const isOnTopOfStack = (modalId) => {
162
+ if (newStack.length < 2) return true;
163
+ return newStack.map((modal) => ({
164
+ id: modal.id,
165
+ shouldRender: modal.shouldRender
166
+ })).reverse().find((modal) => modal.shouldRender)?.id === modalId;
167
+ };
168
+ newStack.forEach((modal, index) => {
169
+ newStack[index].onTopOfStack = isOnTopOfStack(modal.id);
170
+ newStack[index].getParentModal = () => {
171
+ if (index < 1) return null;
172
+ return stackRef.current.slice(0, index).reverse().find((m) => m.isOpen) ?? null;
173
+ };
174
+ newStack[index].getChildModal = () => {
175
+ if (index === stackRef.current.length - 1) return null;
176
+ return stackRef.current.slice(index + 1).find((m) => m.isOpen) ?? null;
177
+ };
178
+ });
179
+ stackRef.current = newStack;
180
+ forceUpdate();
181
+ };
182
+ class ModalClass {
183
+ constructor(component, response, config, onClose, afterLeave) {
184
+ this.show = () => {
185
+ updateStack((prevStack) => prevStack.map((modal) => {
186
+ if (modal.id === this.id && !modal.isOpen) {
187
+ modal.isOpen = true;
188
+ modal.shouldRender = true;
189
+ }
190
+ return modal;
191
+ }));
192
+ };
193
+ this.setOpen = (open) => {
194
+ if (open) this.show();
195
+ else this.close();
196
+ };
197
+ this.close = () => {
198
+ updateStack((currentStack) => {
199
+ let modalClosed = false;
200
+ const newStack = currentStack.map((modal) => {
201
+ if (modal.id === this.id && modal.isOpen) {
202
+ Object.keys(modal.listeners).forEach((event) => {
203
+ modal.off(event);
204
+ });
205
+ modal.isOpen = false;
206
+ modal.onCloseCallback?.();
207
+ modalClosed = true;
208
+ }
209
+ return modal;
210
+ });
211
+ return modalClosed ? newStack : currentStack;
212
+ });
213
+ };
214
+ this.afterLeave = () => {
215
+ if (this.isOpen) return;
216
+ updateStack((prevStack) => {
217
+ const updatedStack = prevStack.map((modal) => {
218
+ if (modal.id === this.id && !modal.isOpen) {
219
+ modal.shouldRender = false;
220
+ modal.afterLeaveCallback?.();
221
+ modal.afterLeaveCallback = null;
222
+ }
223
+ return modal;
224
+ });
225
+ if (this.index === 0) {
226
+ const savedBaseUrl = baseUrl;
227
+ baseUrl = null;
228
+ closingToBaseUrlTarget = savedBaseUrl;
229
+ if (savedBaseUrl && typeof window !== "undefined" && !sameUrlPath(savedBaseUrl, window.location.href)) router.push({
230
+ url: savedBaseUrl,
231
+ preserveScroll: true,
232
+ preserveState: true,
233
+ props: (currentProps) => {
234
+ const { _inertiaui_modal, ...rest } = currentProps;
235
+ return {
236
+ ...rest,
237
+ _inertiaui_modal: void 0
238
+ };
239
+ }
240
+ });
241
+ return [];
242
+ }
243
+ return updatedStack;
244
+ });
245
+ };
246
+ this.on = (event, callback) => {
247
+ event = kebabCase(event);
248
+ this.listeners[event] = this.listeners[event] ?? [];
249
+ this.listeners[event].push(callback);
250
+ };
251
+ this.off = (event, callback) => {
252
+ event = kebabCase(event);
253
+ if (callback) this.listeners[event] = this.listeners[event]?.filter((cb) => cb !== callback) ?? [];
254
+ else delete this.listeners[event];
255
+ };
256
+ this.emit = (event, ...args) => {
257
+ this.listeners[kebabCase(event)]?.forEach((callback) => callback(...args));
258
+ };
259
+ this.registerEventListenersFromProps = (props) => {
260
+ const unsubscribers = [];
261
+ Object.keys(props).filter((key) => key.startsWith("on")).forEach((key) => {
262
+ const eventName = kebabCase(key).replace(/^on-/, "");
263
+ const callback = props[key];
264
+ this.on(eventName, callback);
265
+ unsubscribers.push(() => this.off(eventName, callback));
266
+ });
267
+ return () => unsubscribers.forEach((unsub) => unsub());
268
+ };
269
+ this.reload = (options = {}) => {
270
+ let keys = Object.keys(this.response.props);
271
+ if (options.only) keys = options.only;
272
+ if (options.except) keys = except(keys, options.except);
273
+ if (!this.response?.url) return;
274
+ const method = (options.method ?? "get").toLowerCase();
275
+ const data = options.data ?? {};
276
+ options.onStart?.();
277
+ Axios({
278
+ url: this.response.url,
279
+ method,
280
+ data: method === "get" ? {} : data,
281
+ params: method === "get" ? data : {},
282
+ headers: {
283
+ ...options.headers,
284
+ Accept: "text/html, application/xhtml+xml",
285
+ "X-Inertia": "true",
286
+ "X-Inertia-Partial-Component": this.response.component,
287
+ "X-Inertia-Version": this.response.version ?? "",
288
+ "X-Inertia-Partial-Data": keys.join(","),
289
+ "X-InertiaUI-Modal": generateId$1(),
290
+ "X-InertiaUI-Modal-Base-Url": baseUrl ?? ""
291
+ }
292
+ }).then((response) => {
293
+ this.updateProps(response.data.props);
294
+ options.onSuccess?.(response);
295
+ }).catch((error) => {
296
+ options.onError?.(error);
297
+ }).finally(() => {
298
+ options.onFinish?.();
299
+ });
300
+ };
301
+ this.updateProps = (props) => {
302
+ Object.assign(this.props, props);
303
+ updateStack((prevStack) => prevStack);
304
+ };
305
+ this.id = response.id ?? generateId$1();
306
+ this.isOpen = false;
307
+ this.shouldRender = false;
308
+ this.listeners = {};
309
+ this.component = component;
310
+ this.props = response.props ?? {};
311
+ this.response = response;
312
+ this.config = config ?? {};
313
+ this.onCloseCallback = onClose ?? null;
314
+ this.afterLeaveCallback = afterLeave ?? null;
315
+ this.index = -1;
316
+ this.getParentModal = () => null;
317
+ this.getChildModal = () => null;
318
+ this.onTopOfStack = true;
319
+ }
320
+ }
321
+ const isValidModalResponse = (data) => {
322
+ return typeof data === "object" && data !== null && "component" in data && typeof data.component === "string";
323
+ };
324
+ const pushFromResponseData = (responseData, config = {}, onClose = null, onAfterLeave = null) => {
325
+ if (!resolveComponent) return Promise.reject(/* @__PURE__ */ new Error("resolveComponent not set"));
326
+ if (!isValidModalResponse(responseData)) return Promise.reject(/* @__PURE__ */ new Error("Invalid modal response. This usually happens when the server returns a redirect (e.g., due to session expiration). Check if the user is still authenticated."));
327
+ return resolveComponent(responseData.component).then((component) => push(component, responseData, config, onClose, onAfterLeave));
328
+ };
329
+ const loadDeferredProps = (modal) => {
330
+ const deferred = modal.response?.meta?.deferredProps;
331
+ if (!deferred) return;
332
+ Object.keys(deferred).forEach((key) => {
333
+ modal.reload({ only: deferred[key] });
334
+ });
335
+ };
336
+ const push = (component, response, config, onClose, afterLeave) => {
337
+ const newModal = new ModalClass(component, response, config, onClose, afterLeave);
338
+ newModal.index = stackRef.current.length;
339
+ updateStack((prevStack) => [...prevStack, newModal]);
340
+ loadDeferredProps(newModal);
341
+ newModal.show();
342
+ return newModal;
343
+ };
344
+ function pushLocalModal(name, config, onClose, afterLeave, props) {
345
+ if (!localModals[name]) throw new Error(`The local modal "${name}" has not been registered.`);
346
+ const modal = push(null, { props: props ?? {} }, config, onClose, afterLeave);
347
+ modal.name = name;
348
+ localModals[name].callback(modal);
349
+ return modal;
350
+ }
351
+ const visitModal = (url, options = {}) => visit(url, options.method ?? "get", options.data ?? {}, options.headers ?? {}, options.config ?? {}, options.onClose ?? null, options.onAfterLeave ?? null, options.queryStringArrayFormat ?? "brackets", options.navigate ?? getConfig("navigate"), options.onStart ?? null, options.onSuccess ?? null, options.onError ?? null, options.props ?? null).then((modal) => {
352
+ const listeners = options.listeners ?? {};
353
+ Object.keys(listeners).forEach((event) => {
354
+ const eventName = kebabCase(event);
355
+ modal.on(eventName, listeners[event]);
356
+ });
357
+ return modal;
358
+ });
359
+ const updateBrowserUrl = (url, useBrowserHistory, modalData) => {
360
+ if (!url || !useBrowserHistory || typeof window === "undefined") return;
361
+ router.push({
362
+ url,
363
+ preserveScroll: true,
364
+ preserveState: true,
365
+ props: modalData ? (currentProps) => ({
366
+ ...currentProps,
367
+ _inertiaui_modal: {
368
+ ...modalData,
369
+ baseUrl
370
+ }
371
+ }) : void 0
372
+ });
373
+ };
374
+ const visit = (href, method, payload = {}, headers = {}, config = {}, onClose = null, onAfterLeave = null, queryStringArrayFormat = "brackets", useBrowserHistory = false, onStart = null, onSuccess = null, onError = null, props = null) => {
375
+ const modalId = generateId$1();
376
+ return new Promise((resolve, reject) => {
377
+ if (href.startsWith("#")) {
378
+ resolve(pushLocalModal(href.substring(1), config, onClose, onAfterLeave, props));
379
+ return;
380
+ }
381
+ const [url, data] = mergeDataIntoQueryString(method, href || "", payload, queryStringArrayFormat);
382
+ const cachedResponse = getCachedResponse(url, method, data);
383
+ if (cachedResponse) {
384
+ onSuccess?.(cachedResponse);
385
+ pushFromResponseData(cachedResponse.data, config, onClose, onAfterLeave).then((modal) => {
386
+ updateBrowserUrl(cachedResponse.data.url, useBrowserHistory, cachedResponse.data);
387
+ resolve(modal);
388
+ }).catch(reject);
389
+ return;
390
+ }
391
+ if (stackRef.current.length === 0) baseUrl = typeof window !== "undefined" ? window.location.href : "";
392
+ const requestHeaders = {
393
+ ...headers,
394
+ Accept: "text/html, application/xhtml+xml",
395
+ "X-Requested-With": "XMLHttpRequest",
396
+ "X-Inertia": "true",
397
+ "X-Inertia-Version": pageVersion ?? "",
398
+ "X-InertiaUI-Modal": modalId,
399
+ "X-InertiaUI-Modal-Base-Url": baseUrl ?? ""
400
+ };
401
+ onStart?.();
402
+ progress?.start();
403
+ Axios({
404
+ url,
405
+ method,
406
+ data,
407
+ headers: requestHeaders
408
+ }).then((response) => {
409
+ onSuccess?.(response);
410
+ pushFromResponseData(response.data, config, onClose, onAfterLeave).then((modal) => {
411
+ updateBrowserUrl(response.data.url, useBrowserHistory, response.data);
412
+ resolve(modal);
413
+ }).catch(reject);
414
+ }).catch((...args) => {
415
+ onError?.(...args);
416
+ reject(args[0]);
417
+ }).finally(() => {
418
+ progress?.finish();
419
+ });
420
+ });
421
+ };
422
+ const registerLocalModal = (name, callback) => {
423
+ setLocalModals((prevLocalModals) => ({
424
+ ...prevLocalModals,
425
+ [name]: {
426
+ name,
427
+ callback
428
+ }
429
+ }));
430
+ };
431
+ const removeLocalModal = (name) => {
432
+ setLocalModals((prevLocalModals) => {
433
+ const newLocalModals = { ...prevLocalModals };
434
+ delete newLocalModals[name];
435
+ return newLocalModals;
436
+ });
437
+ };
438
+ const value = {
439
+ get stack() {
440
+ return stackRef.current;
441
+ },
442
+ localModals,
443
+ push,
444
+ pushFromResponseData,
445
+ length: () => stackRef.current.length,
446
+ closeAll: (force = false) => {
447
+ if (force) updateStack(() => []);
448
+ else [...stackRef.current].reverse().forEach((modal) => modal.close());
449
+ },
450
+ reset: () => updateStack(() => []),
451
+ visit,
452
+ visitModal,
453
+ registerLocalModal,
454
+ removeLocalModal
455
+ };
456
+ return /* @__PURE__ */ jsx(ModalStackContext.Provider, {
457
+ value,
458
+ children
459
+ });
515
460
  };
516
- const useModalStack = () => {
517
- const context = useContext(ModalStackContext);
518
- if (context === null) {
519
- throw new Error("useModalStack must be used within a ModalStackProvider");
520
- }
521
- return context;
461
+ var useModalStack = () => {
462
+ const context = useContext(ModalStackContext);
463
+ if (context === null) throw new Error("useModalStack must be used within a ModalStackProvider");
464
+ return context;
522
465
  };
523
- const modalPropNames = ["closeButton", "closeExplicitly", "closeOnClickOutside", "maxWidth", "paddingClasses", "panelClasses", "position", "slideover"];
524
- const initFromPageProps = (pageProps) => {
525
- if (pageProps.initialPage) {
526
- pageVersion = pageProps.initialPage.version ?? null;
527
- }
528
- if (pageProps.resolveComponent) {
529
- resolveComponent = pageProps.resolveComponent;
530
- }
466
+ var modalPropNames = [
467
+ "closeButton",
468
+ "closeExplicitly",
469
+ "closeOnClickOutside",
470
+ "maxWidth",
471
+ "paddingClasses",
472
+ "panelClasses",
473
+ "position",
474
+ "slideover"
475
+ ];
476
+ var initFromPageProps = (pageProps) => {
477
+ if (pageProps.initialPage) pageVersion = pageProps.initialPage.version ?? null;
478
+ if (pageProps.resolveComponent) resolveComponent = pageProps.resolveComponent;
531
479
  };
532
- const renderApp = (App, pageProps) => {
533
- initFromPageProps(pageProps);
534
- const renderInertiaApp = ({ Component, props, key }) => {
535
- const renderComponent = () => {
536
- const child = createElement(Component, { key, ...props });
537
- if (typeof Component.layout === "function") {
538
- return Component.layout(child);
539
- }
540
- if (Array.isArray(Component.layout)) {
541
- return Component.layout.slice().reverse().reduce(
542
- (acc, Layout) => createElement(Layout, props, acc),
543
- child
544
- );
545
- }
546
- return child;
547
- };
548
- return /* @__PURE__ */ jsxs(Fragment, { children: [
549
- renderComponent(),
550
- /* @__PURE__ */ jsx(ModalRoot, {})
551
- ] });
552
- };
553
- return /* @__PURE__ */ jsx(ModalStackProvider, { children: /* @__PURE__ */ jsx(App, { ...pageProps, children: renderInertiaApp }) });
480
+ var renderApp = (App, pageProps) => {
481
+ initFromPageProps(pageProps);
482
+ const renderInertiaApp = ({ Component, props, key }) => {
483
+ const renderComponent = () => {
484
+ const child = createElement(Component, {
485
+ key,
486
+ ...props
487
+ });
488
+ if (typeof Component.layout === "function") return Component.layout(child);
489
+ if (Array.isArray(Component.layout)) return Component.layout.slice().reverse().reduce((acc, Layout) => createElement(Layout, props, acc), child);
490
+ return child;
491
+ };
492
+ return /* @__PURE__ */ jsxs(Fragment, { children: [renderComponent(), /* @__PURE__ */ jsx(ModalRoot, {})] });
493
+ };
494
+ return /* @__PURE__ */ jsx(ModalStackProvider, { children: /* @__PURE__ */ jsx(App, {
495
+ ...pageProps,
496
+ children: renderInertiaApp
497
+ }) });
554
498
  };
555
- const ModalRoot = ({ children }) => {
556
- const context = useContext(ModalStackContext);
557
- const $page = usePage();
558
- const pendingModalKeysRef = useRef(/* @__PURE__ */ new Set());
559
- const getModalKey = (modalData) => modalData.id || `${modalData.component}:${modalData.url}`;
560
- const isNavigatingRef = useRef(false);
561
- const initialModalStillOpenedRef = useRef(!!$page.props?._inertiaui_modal);
562
- useEffect(() => router.on("start", () => isNavigatingRef.current = true), []);
563
- useEffect(() => router.on("finish", () => isNavigatingRef.current = false), []);
564
- useEffect(
565
- () => router.on("navigate", function($event) {
566
- const modalOnBase = $event.detail.page.props._inertiaui_modal;
567
- const pageUrl = $event.detail.page.url;
568
- if (closingToBaseUrlTarget) {
569
- const targetPath = new URL(closingToBaseUrlTarget, "http://x").pathname;
570
- const pagePath = new URL(pageUrl, "http://x").pathname;
571
- if (targetPath === pagePath) {
572
- closingToBaseUrlTarget = null;
573
- context?.closeAll(true);
574
- baseUrl = null;
575
- initialModalStillOpenedRef.current = false;
576
- return;
577
- }
578
- closingToBaseUrlTarget = null;
579
- }
580
- if (!modalOnBase) {
581
- context?.closeAll(true);
582
- baseUrl = null;
583
- initialModalStillOpenedRef.current = false;
584
- return;
585
- }
586
- if (!sameUrlPath(pageUrl, modalOnBase.url)) {
587
- context?.closeAll(true);
588
- baseUrl = null;
589
- initialModalStillOpenedRef.current = false;
590
- return;
591
- }
592
- const modalKey = getModalKey(modalOnBase);
593
- if (pendingModalKeysRef.current.has(modalKey)) {
594
- return;
595
- }
596
- if (modalOnBase.id && context?.stack.some((m) => m.id === modalOnBase.id)) {
597
- return;
598
- }
599
- if (context?.stack.some((m) => m.response?.component === modalOnBase.component && sameUrlPath(m.response?.url, modalOnBase.url))) {
600
- return;
601
- }
602
- baseUrl = modalOnBase.baseUrl;
603
- pendingModalKeysRef.current.add(modalKey);
604
- context?.pushFromResponseData(modalOnBase, {}, () => {
605
- if (!modalOnBase.baseUrl) {
606
- console.error("No base url in modal response data so cannot navigate back");
607
- return;
608
- }
609
- if (!isNavigatingRef.current && typeof window !== "undefined" && window.location.href !== modalOnBase.baseUrl) {
610
- router.visit(modalOnBase.baseUrl, {
611
- preserveScroll: true,
612
- preserveState: true
613
- });
614
- }
615
- }).finally(() => {
616
- pendingModalKeysRef.current.delete(modalKey);
617
- });
618
- }),
619
- []
620
- );
621
- const axiosRequestInterceptor = (config) => {
622
- const baseUrlValue = baseUrl ?? (initialModalStillOpenedRef.current ? $page.props._inertiaui_modal?.baseUrl : null);
623
- if (baseUrlValue) {
624
- config.headers["X-InertiaUI-Modal-Base-Url"] = baseUrlValue;
625
- }
626
- return config;
627
- };
628
- useEffect(() => {
629
- const interceptorId = Axios.interceptors.request.use(axiosRequestInterceptor);
630
- return () => Axios.interceptors.request.eject(interceptorId);
631
- }, []);
632
- const previousModalRef = useRef(void 0);
633
- useEffect(() => {
634
- const newModal = $page.props?._inertiaui_modal;
635
- const previousModal = previousModalRef.current;
636
- previousModalRef.current = newModal;
637
- if (!newModal) {
638
- return;
639
- }
640
- if (previousModal && newModal.component === previousModal.component && sameUrlPath(newModal.url, previousModal.url)) {
641
- context?.stack[0]?.updateProps(newModal.props ?? {});
642
- return;
643
- }
644
- if (!previousModal && context && context.stack.length > 0) {
645
- const existingModal = context.stack.find(
646
- (m) => m.response?.component === newModal.component && sameUrlPath(m.response?.url, newModal.url)
647
- );
648
- if (existingModal) {
649
- existingModal.updateProps(newModal.props ?? {});
650
- }
651
- }
652
- }, [$page.props?._inertiaui_modal]);
653
- return /* @__PURE__ */ jsxs(Fragment, { children: [
654
- children,
655
- context && context.stack.length > 0 && /* @__PURE__ */ jsx(ModalRenderer, { index: 0 })
656
- ] });
499
+ var ModalRoot = ({ children }) => {
500
+ const context = useContext(ModalStackContext);
501
+ const $page = usePage();
502
+ const pendingModalKeysRef = useRef(/* @__PURE__ */ new Set());
503
+ const getModalKey = (modalData) => modalData.id || `${modalData.component}:${modalData.url}`;
504
+ const isNavigatingRef = useRef(false);
505
+ const initialModalStillOpenedRef = useRef(!!$page.props?._inertiaui_modal);
506
+ useEffect(() => router.on("start", () => isNavigatingRef.current = true), []);
507
+ useEffect(() => router.on("finish", () => isNavigatingRef.current = false), []);
508
+ useEffect(() => router.on("navigate", function($event) {
509
+ const modalOnBase = $event.detail.page.props._inertiaui_modal;
510
+ const pageUrl = $event.detail.page.url;
511
+ if (closingToBaseUrlTarget) {
512
+ if (new URL(closingToBaseUrlTarget, "http://x").pathname === new URL(pageUrl, "http://x").pathname) {
513
+ closingToBaseUrlTarget = null;
514
+ context?.closeAll(true);
515
+ baseUrl = null;
516
+ initialModalStillOpenedRef.current = false;
517
+ return;
518
+ }
519
+ closingToBaseUrlTarget = null;
520
+ }
521
+ if (!modalOnBase) {
522
+ context?.closeAll(true);
523
+ baseUrl = null;
524
+ initialModalStillOpenedRef.current = false;
525
+ return;
526
+ }
527
+ if (!sameUrlPath(pageUrl, modalOnBase.url)) {
528
+ context?.closeAll(true);
529
+ baseUrl = null;
530
+ initialModalStillOpenedRef.current = false;
531
+ return;
532
+ }
533
+ const modalKey = getModalKey(modalOnBase);
534
+ if (pendingModalKeysRef.current.has(modalKey)) return;
535
+ if (modalOnBase.id && context?.stack.some((m) => m.id === modalOnBase.id)) return;
536
+ if (context?.stack.some((m) => m.response?.component === modalOnBase.component && sameUrlPath(m.response?.url, modalOnBase.url))) return;
537
+ baseUrl = modalOnBase.baseUrl;
538
+ pendingModalKeysRef.current.add(modalKey);
539
+ context?.pushFromResponseData(modalOnBase, {}, () => {
540
+ if (!modalOnBase.baseUrl) {
541
+ console.error("No base url in modal response data so cannot navigate back");
542
+ return;
543
+ }
544
+ if (!isNavigatingRef.current && typeof window !== "undefined" && window.location.href !== modalOnBase.baseUrl) router.visit(modalOnBase.baseUrl, {
545
+ preserveScroll: true,
546
+ preserveState: true
547
+ });
548
+ }).finally(() => {
549
+ pendingModalKeysRef.current.delete(modalKey);
550
+ });
551
+ }), []);
552
+ const axiosRequestInterceptor = (config) => {
553
+ const baseUrlValue = baseUrl ?? (initialModalStillOpenedRef.current ? $page.props._inertiaui_modal?.baseUrl : null);
554
+ if (baseUrlValue) config.headers["X-InertiaUI-Modal-Base-Url"] = baseUrlValue;
555
+ return config;
556
+ };
557
+ useEffect(() => {
558
+ const interceptorId = Axios.interceptors.request.use(axiosRequestInterceptor);
559
+ return () => Axios.interceptors.request.eject(interceptorId);
560
+ }, []);
561
+ const previousModalRef = useRef(void 0);
562
+ useEffect(() => {
563
+ const newModal = $page.props?._inertiaui_modal;
564
+ const previousModal = previousModalRef.current;
565
+ previousModalRef.current = newModal;
566
+ if (!newModal) return;
567
+ if (previousModal && newModal.component === previousModal.component && sameUrlPath(newModal.url, previousModal.url)) {
568
+ context?.stack[0]?.updateProps(newModal.props ?? {});
569
+ return;
570
+ }
571
+ if (!previousModal && context && context.stack.length > 0) {
572
+ const existingModal = context.stack.find((m) => m.response?.component === newModal.component && sameUrlPath(m.response?.url, newModal.url));
573
+ if (existingModal) existingModal.updateProps(newModal.props ?? {});
574
+ }
575
+ }, [$page.props?._inertiaui_modal]);
576
+ return /* @__PURE__ */ jsxs(Fragment, { children: [children, context && context.stack.length > 0 && /* @__PURE__ */ jsx(ModalRenderer, { index: 0 })] });
657
577
  };
658
- const ModalIndexContext = React.createContext(null);
578
+ //#endregion
579
+ //#region src/ModalRenderer.tsx
580
+ var ModalIndexContext = React.createContext(null);
659
581
  ModalIndexContext.displayName = "ModalIndexContext";
660
- const useModalIndex = () => {
661
- return React.useContext(ModalIndexContext);
582
+ var useModalIndex = () => {
583
+ return React.useContext(ModalIndexContext);
662
584
  };
663
- const ModalRenderer = ({ index }) => {
664
- const { stack } = useModalStack();
665
- const modalContext = useMemo(() => {
666
- return stack[index];
667
- }, [stack, index]);
668
- if (!modalContext?.component) {
669
- return null;
670
- }
671
- return /* @__PURE__ */ jsx(ModalIndexContext.Provider, { value: index, children: createElement(modalContext.component, {
672
- ...modalContext.props,
673
- onModalEvent: (...args) => modalContext.emit("modal-event", ...args)
674
- }) });
585
+ var ModalRenderer = ({ index }) => {
586
+ const { stack } = useModalStack();
587
+ const modalContext = useMemo(() => {
588
+ return stack[index];
589
+ }, [stack, index]);
590
+ if (!modalContext?.component) return null;
591
+ return /* @__PURE__ */ jsx(ModalIndexContext.Provider, {
592
+ value: index,
593
+ children: createElement(modalContext.component, {
594
+ ...modalContext.props,
595
+ onModalEvent: (...args) => modalContext.emit("modal-event", ...args)
596
+ })
597
+ });
675
598
  };
599
+ //#endregion
600
+ //#region src/useModal.ts
676
601
  function useModal() {
677
- return useModalStack().stack[useModalIndex()] ?? null;
602
+ return useModalStack().stack[useModalIndex()] ?? null;
678
603
  }
679
- const Deferred = ({ children, data, fallback }) => {
680
- if (!data) {
681
- throw new Error("`<Deferred>` requires a `data` prop to be a string or array of strings");
682
- }
683
- const [loaded, setLoaded] = useState(false);
684
- const keys = Array.isArray(data) ? data : [data];
685
- const modal = useModal();
686
- const modalProps = modal?.props ?? {};
687
- useEffect(() => {
688
- setLoaded(keys.every((key) => modalProps[key] !== void 0));
689
- }, [modalProps, keys]);
690
- return loaded ? children : fallback;
604
+ //#endregion
605
+ //#region src/Deferred.tsx
606
+ var Deferred = ({ children, data, fallback }) => {
607
+ if (!data) throw new Error("`<Deferred>` requires a `data` prop to be a string or array of strings");
608
+ const [loaded, setLoaded] = useState(false);
609
+ const keys = Array.isArray(data) ? data : [data];
610
+ const modalProps = useModal()?.props ?? {};
611
+ useEffect(() => {
612
+ setLoaded(keys.every((key) => modalProps[key] !== void 0));
613
+ }, [modalProps, keys]);
614
+ return loaded ? children : fallback;
691
615
  };
692
616
  Deferred.displayName = "InertiaModalDeferred";
693
- const HeadlessModal = forwardRef(
694
- (allProps, ref) => {
695
- const { name, children, onFocus, onBlur, onClose, onSuccess, ...props } = allProps;
696
- const modalIndex = useModalIndex();
697
- const { stack, registerLocalModal, removeLocalModal } = useModalStack();
698
- const [localModalContext, setLocalModalContext] = useState(null);
699
- const modalContext = useMemo(
700
- () => name ? localModalContext : stack[modalIndex],
701
- [name, localModalContext, modalIndex, stack]
702
- );
703
- const nextIndex = useMemo(() => {
704
- return stack.find((m) => m.shouldRender && m.index > (modalContext?.index ?? -1))?.index;
705
- }, [modalIndex, stack]);
706
- const configSlideover = useMemo(
707
- () => modalContext?.config.slideover ?? props.slideover ?? getConfig("type") === "slideover",
708
- [props.slideover, modalContext?.config.slideover]
709
- );
710
- const config = useMemo(
711
- () => ({
712
- slideover: configSlideover,
713
- closeButton: props.closeButton ?? getConfigByType(configSlideover, "closeButton"),
714
- closeExplicitly: props.closeExplicitly ?? getConfigByType(configSlideover, "closeExplicitly"),
715
- closeOnClickOutside: props.closeOnClickOutside ?? getConfigByType(configSlideover, "closeOnClickOutside"),
716
- maxWidth: props.maxWidth ?? getConfigByType(configSlideover, "maxWidth"),
717
- paddingClasses: props.paddingClasses ?? getConfigByType(configSlideover, "paddingClasses"),
718
- panelClasses: props.panelClasses ?? getConfigByType(configSlideover, "panelClasses"),
719
- position: props.position ?? getConfigByType(configSlideover, "position"),
720
- ...modalContext?.config
721
- }),
722
- [props, modalContext?.config, configSlideover]
723
- );
724
- useEffect(() => {
725
- if (name) {
726
- let removeListeners = null;
727
- registerLocalModal(name, (localContext) => {
728
- removeListeners = localContext.registerEventListenersFromProps(props);
729
- setLocalModalContext(localContext);
730
- });
731
- return () => {
732
- removeListeners?.();
733
- removeListeners = null;
734
- removeLocalModal(name);
735
- };
736
- }
737
- return modalContext?.registerEventListenersFromProps(props);
738
- }, [name]);
739
- const modalContextRef = useRef(modalContext);
740
- useEffect(() => {
741
- modalContextRef.current = modalContext;
742
- }, [modalContext]);
743
- const previousIsOpenRef = useRef(void 0);
744
- useEffect(() => {
745
- if (modalContext != null) {
746
- if (modalContext.isOpen) {
747
- onSuccess?.();
748
- } else if (previousIsOpenRef.current === true) {
749
- onClose?.();
750
- }
751
- previousIsOpenRef.current = modalContext.isOpen;
752
- }
753
- }, [modalContext?.isOpen]);
754
- const [rendered, setRendered] = useState(false);
755
- useEffect(() => {
756
- if (rendered && modalContext != null && modalContext.isOpen) {
757
- if (modalContext.onTopOfStack) {
758
- onFocus?.();
759
- } else {
760
- onBlur?.();
761
- }
762
- }
763
- setRendered(true);
764
- }, [modalContext?.onTopOfStack]);
765
- useImperativeHandle(
766
- ref,
767
- () => ({
768
- afterLeave: () => modalContextRef.current?.afterLeave(),
769
- close: () => modalContextRef.current?.close(),
770
- emit: (...args) => modalContextRef.current?.emit(...args),
771
- getChildModal: () => modalContextRef.current?.getChildModal(),
772
- getParentModal: () => modalContextRef.current?.getParentModal(),
773
- reload: (options) => modalContextRef.current?.reload(options),
774
- setOpen: (open) => modalContextRef.current?.setOpen(open),
775
- get id() {
776
- return modalContextRef.current?.id;
777
- },
778
- get index() {
779
- return modalContextRef.current?.index;
780
- },
781
- get isOpen() {
782
- return modalContextRef.current?.isOpen;
783
- },
784
- get config() {
785
- return modalContextRef.current?.config;
786
- },
787
- get modalContext() {
788
- return modalContextRef.current;
789
- },
790
- get onTopOfStack() {
791
- return modalContextRef.current?.onTopOfStack;
792
- },
793
- get shouldRender() {
794
- return modalContextRef.current?.shouldRender;
795
- }
796
- }),
797
- [modalContext]
798
- );
799
- if (!modalContext?.shouldRender) {
800
- return null;
801
- }
802
- return /* @__PURE__ */ jsxs(Fragment, { children: [
803
- typeof children === "function" ? children({
804
- // Spread props first so they can be overridden by built-in props
805
- ...modalContext.props,
806
- afterLeave: modalContext.afterLeave,
807
- close: modalContext.close,
808
- config,
809
- emit: modalContext.emit,
810
- getChildModal: modalContext.getChildModal,
811
- getParentModal: modalContext.getParentModal,
812
- id: modalContext.id,
813
- index: modalContext.index,
814
- isOpen: modalContext.isOpen,
815
- modalContext,
816
- onTopOfStack: modalContext.onTopOfStack,
817
- reload: modalContext.reload,
818
- setOpen: modalContext.setOpen,
819
- shouldRender: modalContext.shouldRender
820
- }) : children,
821
- nextIndex !== void 0 && /* @__PURE__ */ jsx(ModalRenderer, { index: nextIndex })
822
- ] });
823
- }
824
- );
617
+ //#endregion
618
+ //#region src/HeadlessModal.tsx
619
+ var HeadlessModal = forwardRef((allProps, ref) => {
620
+ const { name, children, onFocus, onBlur, onClose, onSuccess, ...props } = allProps;
621
+ const modalIndex = useModalIndex();
622
+ const { stack, registerLocalModal, removeLocalModal } = useModalStack();
623
+ const [localModalContext, setLocalModalContext] = useState(null);
624
+ const modalContext = useMemo(() => name ? localModalContext : stack[modalIndex], [
625
+ name,
626
+ localModalContext,
627
+ modalIndex,
628
+ stack
629
+ ]);
630
+ const nextIndex = useMemo(() => {
631
+ return stack.find((m) => m.shouldRender && m.index > (modalContext?.index ?? -1))?.index;
632
+ }, [modalIndex, stack]);
633
+ const configSlideover = useMemo(() => modalContext?.config.slideover ?? props.slideover ?? getConfig("type") === "slideover", [props.slideover, modalContext?.config.slideover]);
634
+ const config = useMemo(() => ({
635
+ slideover: configSlideover,
636
+ closeButton: props.closeButton ?? getConfigByType(configSlideover, "closeButton"),
637
+ closeExplicitly: props.closeExplicitly ?? getConfigByType(configSlideover, "closeExplicitly"),
638
+ closeOnClickOutside: props.closeOnClickOutside ?? getConfigByType(configSlideover, "closeOnClickOutside"),
639
+ maxWidth: props.maxWidth ?? getConfigByType(configSlideover, "maxWidth"),
640
+ paddingClasses: props.paddingClasses ?? getConfigByType(configSlideover, "paddingClasses"),
641
+ panelClasses: props.panelClasses ?? getConfigByType(configSlideover, "panelClasses"),
642
+ position: props.position ?? getConfigByType(configSlideover, "position"),
643
+ ...modalContext?.config
644
+ }), [
645
+ props,
646
+ modalContext?.config,
647
+ configSlideover
648
+ ]);
649
+ useEffect(() => {
650
+ if (name) {
651
+ let removeListeners = null;
652
+ registerLocalModal(name, (localContext) => {
653
+ removeListeners = localContext.registerEventListenersFromProps(props);
654
+ setLocalModalContext(localContext);
655
+ });
656
+ return () => {
657
+ removeListeners?.();
658
+ removeListeners = null;
659
+ removeLocalModal(name);
660
+ };
661
+ }
662
+ return modalContext?.registerEventListenersFromProps(props);
663
+ }, [name]);
664
+ const modalContextRef = useRef(modalContext);
665
+ useEffect(() => {
666
+ modalContextRef.current = modalContext;
667
+ }, [modalContext]);
668
+ const previousIsOpenRef = useRef(void 0);
669
+ useEffect(() => {
670
+ if (modalContext != null) {
671
+ if (modalContext.isOpen) onSuccess?.();
672
+ else if (previousIsOpenRef.current === true) onClose?.();
673
+ previousIsOpenRef.current = modalContext.isOpen;
674
+ }
675
+ }, [modalContext?.isOpen]);
676
+ const [rendered, setRendered] = useState(false);
677
+ useEffect(() => {
678
+ if (rendered && modalContext != null && modalContext.isOpen) if (modalContext.onTopOfStack) onFocus?.();
679
+ else onBlur?.();
680
+ setRendered(true);
681
+ }, [modalContext?.onTopOfStack]);
682
+ useImperativeHandle(ref, () => ({
683
+ afterLeave: () => modalContextRef.current?.afterLeave(),
684
+ close: () => modalContextRef.current?.close(),
685
+ emit: (...args) => modalContextRef.current?.emit(...args),
686
+ getChildModal: () => modalContextRef.current?.getChildModal(),
687
+ getParentModal: () => modalContextRef.current?.getParentModal(),
688
+ reload: (options) => modalContextRef.current?.reload(options),
689
+ setOpen: (open) => modalContextRef.current?.setOpen(open),
690
+ get id() {
691
+ return modalContextRef.current?.id;
692
+ },
693
+ get index() {
694
+ return modalContextRef.current?.index;
695
+ },
696
+ get isOpen() {
697
+ return modalContextRef.current?.isOpen;
698
+ },
699
+ get config() {
700
+ return modalContextRef.current?.config;
701
+ },
702
+ get modalContext() {
703
+ return modalContextRef.current;
704
+ },
705
+ get onTopOfStack() {
706
+ return modalContextRef.current?.onTopOfStack;
707
+ },
708
+ get shouldRender() {
709
+ return modalContextRef.current?.shouldRender;
710
+ }
711
+ }), [modalContext]);
712
+ if (!modalContext?.shouldRender) return null;
713
+ return /* @__PURE__ */ jsxs(Fragment, { children: [typeof children === "function" ? children({
714
+ ...modalContext.props,
715
+ afterLeave: modalContext.afterLeave,
716
+ close: modalContext.close,
717
+ config,
718
+ emit: modalContext.emit,
719
+ getChildModal: modalContext.getChildModal,
720
+ getParentModal: modalContext.getParentModal,
721
+ id: modalContext.id,
722
+ index: modalContext.index,
723
+ isOpen: modalContext.isOpen,
724
+ modalContext,
725
+ onTopOfStack: modalContext.onTopOfStack,
726
+ reload: modalContext.reload,
727
+ setOpen: modalContext.setOpen,
728
+ shouldRender: modalContext.shouldRender
729
+ }) : children, nextIndex !== void 0 && /* @__PURE__ */ jsx(ModalRenderer, { index: nextIndex })] });
730
+ });
825
731
  HeadlessModal.displayName = "HeadlessModal";
826
- function CloseButton({ onClick }) {
827
- return /* @__PURE__ */ jsxs(
828
- "button",
829
- {
830
- type: "button",
831
- className: "im-close-button text-gray-400 hover:text-gray-500",
832
- onClick,
833
- children: [
834
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" }),
835
- /* @__PURE__ */ jsx(
836
- "svg",
837
- {
838
- className: "size-6",
839
- xmlns: "http://www.w3.org/2000/svg",
840
- fill: "none",
841
- viewBox: "0 0 24 24",
842
- strokeWidth: "2",
843
- stroke: "currentColor",
844
- "aria-hidden": "true",
845
- children: /* @__PURE__ */ jsx(
846
- "path",
847
- {
848
- strokeLinecap: "round",
849
- strokeLinejoin: "round",
850
- d: "M6 18L18 6M6 6l12 12"
851
- }
852
- )
853
- }
854
- )
855
- ]
856
- }
857
- );
858
- }
732
+ //#endregion
733
+ //#region ../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
859
734
  function r(e) {
860
- var t, f, n = "";
861
- if ("string" == typeof e || "number" == typeof e) n += e;
862
- else if ("object" == typeof e) if (Array.isArray(e)) {
863
- var o = e.length;
864
- for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
865
- } else for (f in e) e[f] && (n && (n += " "), n += f);
866
- return n;
735
+ var t, f, n = "";
736
+ if ("string" == typeof e || "number" == typeof e) n += e;
737
+ else if ("object" == typeof e) if (Array.isArray(e)) {
738
+ var o = e.length;
739
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
740
+ } else for (f in e) e[f] && (n && (n += " "), n += f);
741
+ return n;
867
742
  }
868
743
  function clsx() {
869
- for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
870
- return n;
744
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
745
+ return n;
746
+ }
747
+ //#endregion
748
+ //#region src/CloseButton.tsx
749
+ function CloseButton({ onClick }) {
750
+ return /* @__PURE__ */ jsxs("button", {
751
+ type: "button",
752
+ className: "im-close-button text-gray-400 hover:text-gray-500",
753
+ onClick,
754
+ children: [/* @__PURE__ */ jsx("span", {
755
+ className: "sr-only",
756
+ children: "Close"
757
+ }), /* @__PURE__ */ jsx("svg", {
758
+ className: "size-6",
759
+ xmlns: "http://www.w3.org/2000/svg",
760
+ fill: "none",
761
+ viewBox: "0 0 24 24",
762
+ strokeWidth: "2",
763
+ stroke: "currentColor",
764
+ "aria-hidden": "true",
765
+ children: /* @__PURE__ */ jsx("path", {
766
+ strokeLinecap: "round",
767
+ strokeLinejoin: "round",
768
+ d: "M6 18L18 6M6 6l12 12"
769
+ })
770
+ })]
771
+ });
871
772
  }
872
- const maxWidthClasses = {
873
- sm: "sm:max-w-sm",
874
- md: "sm:max-w-md",
875
- lg: "sm:max-w-md md:max-w-lg",
876
- xl: "sm:max-w-md md:max-w-xl",
877
- "2xl": "sm:max-w-md md:max-w-xl lg:max-w-2xl",
878
- "3xl": "sm:max-w-md md:max-w-xl lg:max-w-3xl",
879
- "4xl": "sm:max-w-md md:max-w-xl lg:max-w-3xl xl:max-w-4xl",
880
- "5xl": "sm:max-w-md md:max-w-xl lg:max-w-3xl xl:max-w-5xl",
881
- "6xl": "sm:max-w-md md:max-w-xl lg:max-w-3xl xl:max-w-5xl 2xl:max-w-6xl",
882
- "7xl": "sm:max-w-md md:max-w-xl lg:max-w-3xl xl:max-w-5xl 2xl:max-w-7xl"
773
+ //#endregion
774
+ //#region src/constants.ts
775
+ /**
776
+ * Max width classes for modals and slideovers.
777
+ * Uses a map lookup for Tailwind 4 compatibility (scanner picks up full class strings).
778
+ */
779
+ var maxWidthClasses = {
780
+ sm: "sm:max-w-sm",
781
+ md: "sm:max-w-md",
782
+ lg: "sm:max-w-md md:max-w-lg",
783
+ xl: "sm:max-w-md md:max-w-xl",
784
+ "2xl": "sm:max-w-md md:max-w-xl lg:max-w-2xl",
785
+ "3xl": "sm:max-w-md md:max-w-xl lg:max-w-3xl",
786
+ "4xl": "sm:max-w-md md:max-w-xl lg:max-w-3xl xl:max-w-4xl",
787
+ "5xl": "sm:max-w-md md:max-w-xl lg:max-w-3xl xl:max-w-5xl",
788
+ "6xl": "sm:max-w-md md:max-w-xl lg:max-w-3xl xl:max-w-5xl 2xl:max-w-6xl",
789
+ "7xl": "sm:max-w-md md:max-w-xl lg:max-w-3xl xl:max-w-5xl 2xl:max-w-7xl"
883
790
  };
884
- const defaultMaxWidth = "2xl";
885
791
  function getMaxWidthClass(maxWidth) {
886
- return maxWidthClasses[maxWidth] || maxWidthClasses[defaultMaxWidth];
792
+ return maxWidthClasses[maxWidth] || maxWidthClasses["2xl"];
887
793
  }
888
- const ModalContent = ({ modalContext, config, useNativeDialog, isFirstModal, onAfterLeave, children }) => {
889
- const [isRendered, setIsRendered] = useState(false);
890
- const [isVisible, setIsVisible] = useState(false);
891
- const [entered, setEntered] = useState(false);
892
- const wrapperRef = useRef(null);
893
- const dialogRef = useRef(null);
894
- const nativeWrapperRef = useRef(null);
895
- const cleanupFocusTrapRef = useRef(null);
896
- const cleanupEscapeKeyRef = useRef(null);
897
- const maxWidthClass = useMemo(() => getMaxWidthClass(config.maxWidth), [config.maxWidth]);
898
- const animateIn = useCallback(async (element) => {
899
- if (!element) return;
900
- setIsVisible(true);
901
- await animate(element, [
902
- { transform: "translate3d(0, 1rem, 0) scale(0.95)", opacity: 0 },
903
- { transform: "translate3d(0, 0, 0) scale(1)", opacity: 1 }
904
- ]);
905
- setEntered(true);
906
- }, []);
907
- const animateOut = useCallback(
908
- async (element) => {
909
- if (!element) return;
910
- setIsVisible(false);
911
- await animate(element, [
912
- { transform: "translate3d(0, 0, 0) scale(1)", opacity: 1 },
913
- { transform: "translate3d(0, 1rem, 0) scale(0.95)", opacity: 0 }
914
- ]);
915
- setIsRendered(false);
916
- if (useNativeDialog && dialogRef.current) {
917
- dialogRef.current.close();
918
- }
919
- onAfterLeave?.();
920
- modalContext.afterLeave();
921
- },
922
- [useNativeDialog, onAfterLeave, modalContext]
923
- );
924
- const setupFocusTrap = useCallback(() => {
925
- if (useNativeDialog) return;
926
- if (!wrapperRef.current || !modalContext.onTopOfStack) return;
927
- if (cleanupFocusTrapRef.current) return;
928
- cleanupFocusTrapRef.current = createFocusTrap(wrapperRef.current, {
929
- initialFocus: true,
930
- returnFocus: false
931
- });
932
- }, [modalContext.onTopOfStack, useNativeDialog]);
933
- const cleanupFocusTrap = useCallback(() => {
934
- if (cleanupFocusTrapRef.current) {
935
- cleanupFocusTrapRef.current();
936
- cleanupFocusTrapRef.current = null;
937
- }
938
- }, []);
939
- const setupEscapeKey = useCallback(() => {
940
- if (useNativeDialog) return;
941
- if (cleanupEscapeKeyRef.current) return;
942
- if (config?.closeExplicitly) return;
943
- cleanupEscapeKeyRef.current = onEscapeKey(() => {
944
- if (modalContext.onTopOfStack) {
945
- modalContext.close();
946
- }
947
- });
948
- }, [config?.closeExplicitly, modalContext, useNativeDialog]);
949
- const cleanupEscapeKey = useCallback(() => {
950
- if (cleanupEscapeKeyRef.current) {
951
- cleanupEscapeKeyRef.current();
952
- cleanupEscapeKeyRef.current = null;
953
- }
954
- }, []);
955
- const handleClickOutside = useCallback(
956
- (event) => {
957
- if (useNativeDialog) return;
958
- if (!modalContext.onTopOfStack) return;
959
- if (config?.closeExplicitly) return;
960
- if (config?.closeOnClickOutside === false) return;
961
- if (!wrapperRef.current) return;
962
- if (!wrapperRef.current.contains(event.target)) {
963
- modalContext.close();
964
- }
965
- },
966
- [modalContext, config?.closeExplicitly, config?.closeOnClickOutside, useNativeDialog]
967
- );
968
- const handleCancel = useCallback(
969
- (event) => {
970
- event.preventDefault();
971
- if (modalContext.onTopOfStack && !config?.closeExplicitly) {
972
- modalContext.close();
973
- }
974
- },
975
- [modalContext, config?.closeExplicitly]
976
- );
977
- const handleDialogClick = useCallback(
978
- (event) => {
979
- if (event.target === dialogRef.current) {
980
- if (modalContext.onTopOfStack && !config?.closeExplicitly && config?.closeOnClickOutside !== false) {
981
- modalContext.close();
982
- }
983
- }
984
- },
985
- [modalContext, config?.closeExplicitly, config?.closeOnClickOutside]
986
- );
987
- const prevIsOpenRef = useRef(modalContext.isOpen);
988
- useEffect(() => {
989
- if (useNativeDialog) {
990
- if (modalContext.isOpen && !dialogRef.current?.open) {
991
- dialogRef.current?.showModal();
992
- animateIn(nativeWrapperRef.current);
993
- } else if (!modalContext.isOpen && prevIsOpenRef.current) {
994
- setEntered(false);
995
- animateOut(nativeWrapperRef.current);
996
- }
997
- } else {
998
- if (modalContext.isOpen && !isRendered) {
999
- setIsRendered(true);
1000
- } else if (!modalContext.isOpen && prevIsOpenRef.current) {
1001
- setEntered(false);
1002
- animateOut(wrapperRef.current);
1003
- }
1004
- }
1005
- prevIsOpenRef.current = modalContext.isOpen;
1006
- }, [modalContext.isOpen, useNativeDialog, animateIn, animateOut, isRendered]);
1007
- useEffect(() => {
1008
- if (!useNativeDialog && isRendered && !entered && modalContext.isOpen) {
1009
- animateIn(wrapperRef.current).then(() => {
1010
- setupFocusTrap();
1011
- });
1012
- }
1013
- }, [isRendered, useNativeDialog, entered, modalContext.isOpen, animateIn, setupFocusTrap]);
1014
- useEffect(() => {
1015
- if (!useNativeDialog) {
1016
- setupEscapeKey();
1017
- }
1018
- return () => {
1019
- cleanupEscapeKey();
1020
- };
1021
- }, [useNativeDialog, setupEscapeKey, cleanupEscapeKey]);
1022
- useEffect(() => {
1023
- if (useNativeDialog) return;
1024
- if (modalContext.onTopOfStack) {
1025
- setupEscapeKey();
1026
- if (entered) {
1027
- setupFocusTrap();
1028
- }
1029
- } else {
1030
- cleanupFocusTrap();
1031
- cleanupEscapeKey();
1032
- }
1033
- }, [modalContext.onTopOfStack, entered, setupEscapeKey, setupFocusTrap, cleanupFocusTrap, cleanupEscapeKey, useNativeDialog]);
1034
- useEffect(() => {
1035
- return () => {
1036
- const wrapper = useNativeDialog ? nativeWrapperRef.current : wrapperRef.current;
1037
- if (wrapper) {
1038
- cancelAnimations(wrapper);
1039
- }
1040
- if (useNativeDialog) {
1041
- if (dialogRef.current?.open) {
1042
- dialogRef.current.close();
1043
- }
1044
- } else {
1045
- cleanupFocusTrap();
1046
- cleanupEscapeKey();
1047
- }
1048
- };
1049
- }, [useNativeDialog, cleanupFocusTrap, cleanupEscapeKey]);
1050
- const renderContent = () => /* @__PURE__ */ jsxs(
1051
- "div",
1052
- {
1053
- className: `im-modal-content relative ${config.paddingClasses} ${config.panelClasses}`,
1054
- "data-inertiaui-modal-entered": entered,
1055
- children: [
1056
- config.closeButton && /* @__PURE__ */ jsx("div", { className: "absolute right-0 top-0 pr-3 pt-3", children: /* @__PURE__ */ jsx(CloseButton, { onClick: modalContext.close }) }),
1057
- typeof children === "function" ? children({ modalContext, config }) : children
1058
- ]
1059
- }
1060
- );
1061
- if (useNativeDialog) {
1062
- return /* @__PURE__ */ jsx(
1063
- "dialog",
1064
- {
1065
- ref: dialogRef,
1066
- className: clsx(
1067
- "im-modal-dialog m-0 overflow-visible bg-transparent p-0",
1068
- "size-full max-h-none max-w-none",
1069
- "backdrop:bg-black/75 backdrop:transition-opacity backdrop:duration-300",
1070
- isVisible ? "backdrop:opacity-100" : "backdrop:opacity-0",
1071
- !isFirstModal && "backdrop:bg-transparent"
1072
- ),
1073
- onCancel: handleCancel,
1074
- onClick: handleDialogClick,
1075
- children: /* @__PURE__ */ jsx("div", { className: "im-modal-container fixed inset-0 overflow-y-auto p-4", children: /* @__PURE__ */ jsx(
1076
- "div",
1077
- {
1078
- className: clsx("im-modal-positioner flex min-h-full justify-center", {
1079
- "items-start": config.position === "top",
1080
- "items-center": config.position === "center",
1081
- "items-end": config.position === "bottom"
1082
- }),
1083
- children: /* @__PURE__ */ jsx(
1084
- "div",
1085
- {
1086
- ref: nativeWrapperRef,
1087
- className: clsx("im-modal-wrapper w-full transition-[filter] duration-300", modalContext.onTopOfStack ? "" : "blur-xs", maxWidthClass),
1088
- children: renderContent()
1089
- }
1090
- )
1091
- }
1092
- ) })
1093
- }
1094
- );
1095
- }
1096
- if (!isRendered) return null;
1097
- return /* @__PURE__ */ jsx(
1098
- "div",
1099
- {
1100
- className: "im-modal-container fixed inset-0 z-40 overflow-y-auto p-4",
1101
- onMouseDown: handleClickOutside,
1102
- children: /* @__PURE__ */ jsx(
1103
- "div",
1104
- {
1105
- className: clsx("im-modal-positioner flex min-h-full justify-center", {
1106
- "items-start": config.position === "top",
1107
- "items-center": config.position === "center",
1108
- "items-end": config.position === "bottom"
1109
- }),
1110
- onMouseDown: handleClickOutside,
1111
- children: /* @__PURE__ */ jsxs(
1112
- "div",
1113
- {
1114
- ref: wrapperRef,
1115
- role: "dialog",
1116
- "aria-modal": "true",
1117
- className: clsx("im-modal-wrapper w-full transition-[filter] duration-300", modalContext.onTopOfStack ? "" : "blur-xs", maxWidthClass),
1118
- children: [
1119
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Dialog" }),
1120
- renderContent()
1121
- ]
1122
- }
1123
- )
1124
- }
1125
- )
1126
- }
1127
- );
794
+ //#endregion
795
+ //#region src/ModalContent.tsx
796
+ var ModalContent = ({ modalContext, config, useNativeDialog, isFirstModal, onAfterLeave, children }) => {
797
+ const [isRendered, setIsRendered] = useState(false);
798
+ const [isVisible, setIsVisible] = useState(false);
799
+ const [entered, setEntered] = useState(false);
800
+ const wrapperRef = useRef(null);
801
+ const dialogRef = useRef(null);
802
+ const nativeWrapperRef = useRef(null);
803
+ const cleanupFocusTrapRef = useRef(null);
804
+ const cleanupEscapeKeyRef = useRef(null);
805
+ const maxWidthClass = useMemo(() => getMaxWidthClass(config.maxWidth), [config.maxWidth]);
806
+ const animateIn = useCallback(async (element) => {
807
+ if (!element) return;
808
+ setIsVisible(true);
809
+ await animate(element, [{
810
+ transform: "translate3d(0, 1rem, 0) scale(0.95)",
811
+ opacity: 0
812
+ }, {
813
+ transform: "translate3d(0, 0, 0) scale(1)",
814
+ opacity: 1
815
+ }]);
816
+ setEntered(true);
817
+ }, []);
818
+ const animateOut = useCallback(async (element) => {
819
+ if (!element) return;
820
+ setIsVisible(false);
821
+ await animate(element, [{
822
+ transform: "translate3d(0, 0, 0) scale(1)",
823
+ opacity: 1
824
+ }, {
825
+ transform: "translate3d(0, 1rem, 0) scale(0.95)",
826
+ opacity: 0
827
+ }]);
828
+ setIsRendered(false);
829
+ if (useNativeDialog && dialogRef.current) dialogRef.current.close();
830
+ onAfterLeave?.();
831
+ modalContext.afterLeave();
832
+ }, [
833
+ useNativeDialog,
834
+ onAfterLeave,
835
+ modalContext
836
+ ]);
837
+ const setupFocusTrap = useCallback(() => {
838
+ if (useNativeDialog) return;
839
+ if (!wrapperRef.current || !modalContext.onTopOfStack) return;
840
+ if (cleanupFocusTrapRef.current) return;
841
+ cleanupFocusTrapRef.current = createFocusTrap(wrapperRef.current, {
842
+ initialFocus: true,
843
+ returnFocus: false
844
+ });
845
+ }, [modalContext.onTopOfStack, useNativeDialog]);
846
+ const cleanupFocusTrap = useCallback(() => {
847
+ if (cleanupFocusTrapRef.current) {
848
+ cleanupFocusTrapRef.current();
849
+ cleanupFocusTrapRef.current = null;
850
+ }
851
+ }, []);
852
+ const setupEscapeKey = useCallback(() => {
853
+ if (useNativeDialog) return;
854
+ if (cleanupEscapeKeyRef.current) return;
855
+ if (config?.closeExplicitly) return;
856
+ cleanupEscapeKeyRef.current = onEscapeKey(() => {
857
+ if (modalContext.onTopOfStack) modalContext.close();
858
+ });
859
+ }, [
860
+ config?.closeExplicitly,
861
+ modalContext,
862
+ useNativeDialog
863
+ ]);
864
+ const cleanupEscapeKey = useCallback(() => {
865
+ if (cleanupEscapeKeyRef.current) {
866
+ cleanupEscapeKeyRef.current();
867
+ cleanupEscapeKeyRef.current = null;
868
+ }
869
+ }, []);
870
+ const handleClickOutside = useCallback((event) => {
871
+ if (useNativeDialog) return;
872
+ if (!modalContext.onTopOfStack) return;
873
+ if (config?.closeExplicitly) return;
874
+ if (config?.closeOnClickOutside === false) return;
875
+ if (!wrapperRef.current) return;
876
+ if (!wrapperRef.current.contains(event.target)) modalContext.close();
877
+ }, [
878
+ modalContext,
879
+ config?.closeExplicitly,
880
+ config?.closeOnClickOutside,
881
+ useNativeDialog
882
+ ]);
883
+ const handleCancel = useCallback((event) => {
884
+ event.preventDefault();
885
+ if (modalContext.onTopOfStack && !config?.closeExplicitly) modalContext.close();
886
+ }, [modalContext, config?.closeExplicitly]);
887
+ const handleDialogClick = useCallback((event) => {
888
+ if (event.target === dialogRef.current) {
889
+ if (modalContext.onTopOfStack && !config?.closeExplicitly && config?.closeOnClickOutside !== false) modalContext.close();
890
+ }
891
+ }, [
892
+ modalContext,
893
+ config?.closeExplicitly,
894
+ config?.closeOnClickOutside
895
+ ]);
896
+ const prevIsOpenRef = useRef(modalContext.isOpen);
897
+ useEffect(() => {
898
+ if (useNativeDialog) {
899
+ if (modalContext.isOpen && !dialogRef.current?.open) {
900
+ dialogRef.current?.showModal();
901
+ animateIn(nativeWrapperRef.current);
902
+ } else if (!modalContext.isOpen && prevIsOpenRef.current) {
903
+ setEntered(false);
904
+ animateOut(nativeWrapperRef.current);
905
+ }
906
+ } else if (modalContext.isOpen && !isRendered) setIsRendered(true);
907
+ else if (!modalContext.isOpen && prevIsOpenRef.current) {
908
+ setEntered(false);
909
+ animateOut(wrapperRef.current);
910
+ }
911
+ prevIsOpenRef.current = modalContext.isOpen;
912
+ }, [
913
+ modalContext.isOpen,
914
+ useNativeDialog,
915
+ animateIn,
916
+ animateOut,
917
+ isRendered
918
+ ]);
919
+ useEffect(() => {
920
+ if (!useNativeDialog && isRendered && !entered && modalContext.isOpen) animateIn(wrapperRef.current).then(() => {
921
+ setupFocusTrap();
922
+ });
923
+ }, [
924
+ isRendered,
925
+ useNativeDialog,
926
+ entered,
927
+ modalContext.isOpen,
928
+ animateIn,
929
+ setupFocusTrap
930
+ ]);
931
+ useEffect(() => {
932
+ if (!useNativeDialog) setupEscapeKey();
933
+ return () => {
934
+ cleanupEscapeKey();
935
+ };
936
+ }, [
937
+ useNativeDialog,
938
+ setupEscapeKey,
939
+ cleanupEscapeKey
940
+ ]);
941
+ useEffect(() => {
942
+ if (useNativeDialog) return;
943
+ if (modalContext.onTopOfStack) {
944
+ setupEscapeKey();
945
+ if (entered) setupFocusTrap();
946
+ } else {
947
+ cleanupFocusTrap();
948
+ cleanupEscapeKey();
949
+ }
950
+ }, [
951
+ modalContext.onTopOfStack,
952
+ entered,
953
+ setupEscapeKey,
954
+ setupFocusTrap,
955
+ cleanupFocusTrap,
956
+ cleanupEscapeKey,
957
+ useNativeDialog
958
+ ]);
959
+ useEffect(() => {
960
+ return () => {
961
+ const wrapper = useNativeDialog ? nativeWrapperRef.current : wrapperRef.current;
962
+ if (wrapper) cancelAnimations(wrapper);
963
+ if (useNativeDialog) {
964
+ if (dialogRef.current?.open) dialogRef.current.close();
965
+ } else {
966
+ cleanupFocusTrap();
967
+ cleanupEscapeKey();
968
+ }
969
+ };
970
+ }, [
971
+ useNativeDialog,
972
+ cleanupFocusTrap,
973
+ cleanupEscapeKey
974
+ ]);
975
+ const renderContent = () => /* @__PURE__ */ jsxs("div", {
976
+ className: `im-modal-content relative ${config.paddingClasses} ${config.panelClasses}`,
977
+ "data-inertiaui-modal-entered": entered,
978
+ children: [config.closeButton && /* @__PURE__ */ jsx("div", {
979
+ className: "absolute top-0 right-0 pt-3 pr-3",
980
+ children: /* @__PURE__ */ jsx(CloseButton, { onClick: modalContext.close })
981
+ }), typeof children === "function" ? children({
982
+ modalContext,
983
+ config
984
+ }) : children]
985
+ });
986
+ if (useNativeDialog) return /* @__PURE__ */ jsx("dialog", {
987
+ ref: dialogRef,
988
+ className: clsx("im-modal-dialog m-0 overflow-visible bg-transparent p-0", "size-full max-h-none max-w-none", "backdrop:bg-black/75 backdrop:transition-opacity backdrop:duration-300", isVisible ? "backdrop:opacity-100" : "backdrop:opacity-0", !isFirstModal && "backdrop:bg-transparent"),
989
+ onCancel: handleCancel,
990
+ onClick: handleDialogClick,
991
+ children: /* @__PURE__ */ jsx("div", {
992
+ className: "im-modal-container fixed inset-0 overflow-y-auto p-4",
993
+ children: /* @__PURE__ */ jsx("div", {
994
+ className: clsx("im-modal-positioner flex min-h-full justify-center", {
995
+ "items-start": config.position === "top",
996
+ "items-center": config.position === "center",
997
+ "items-end": config.position === "bottom"
998
+ }),
999
+ children: /* @__PURE__ */ jsx("div", {
1000
+ ref: nativeWrapperRef,
1001
+ className: clsx("im-modal-wrapper w-full transition-[filter] duration-300", modalContext.onTopOfStack ? "" : "blur-xs", maxWidthClass),
1002
+ children: renderContent()
1003
+ })
1004
+ })
1005
+ })
1006
+ });
1007
+ if (!isRendered) return null;
1008
+ return /* @__PURE__ */ jsx("div", {
1009
+ className: "im-modal-container fixed inset-0 z-40 overflow-y-auto p-4",
1010
+ onMouseDown: handleClickOutside,
1011
+ children: /* @__PURE__ */ jsx("div", {
1012
+ className: clsx("im-modal-positioner flex min-h-full justify-center", {
1013
+ "items-start": config.position === "top",
1014
+ "items-center": config.position === "center",
1015
+ "items-end": config.position === "bottom"
1016
+ }),
1017
+ onMouseDown: handleClickOutside,
1018
+ children: /* @__PURE__ */ jsxs("div", {
1019
+ ref: wrapperRef,
1020
+ role: "dialog",
1021
+ "aria-modal": "true",
1022
+ className: clsx("im-modal-wrapper w-full transition-[filter] duration-300", modalContext.onTopOfStack ? "" : "blur-xs", maxWidthClass),
1023
+ children: [/* @__PURE__ */ jsx("span", {
1024
+ className: "sr-only",
1025
+ children: "Dialog"
1026
+ }), renderContent()]
1027
+ })
1028
+ })
1029
+ });
1128
1030
  };
1129
- const SlideoverContent = ({ modalContext, config, useNativeDialog, isFirstModal, onAfterLeave, children }) => {
1130
- const [isRendered, setIsRendered] = useState(false);
1131
- const [isVisible, setIsVisible] = useState(false);
1132
- const [entered, setEntered] = useState(false);
1133
- const wrapperRef = useRef(null);
1134
- const dialogRef = useRef(null);
1135
- const nativeWrapperRef = useRef(null);
1136
- const cleanupFocusTrapRef = useRef(null);
1137
- const cleanupEscapeKeyRef = useRef(null);
1138
- const isLeft = config.position === "left";
1139
- const maxWidthClass = useMemo(() => getMaxWidthClass(config.maxWidth), [config.maxWidth]);
1140
- const getTranslateX = useCallback(() => isLeft ? "-100%" : "100%", [isLeft]);
1141
- const animateIn = useCallback(
1142
- async (element) => {
1143
- if (!element) return;
1144
- setIsVisible(true);
1145
- const translateX = getTranslateX();
1146
- await animate(element, [
1147
- { transform: `translate3d(${translateX}, 0, 0)`, opacity: 0 },
1148
- { transform: "translate3d(0, 0, 0)", opacity: 1 }
1149
- ]);
1150
- setEntered(true);
1151
- },
1152
- [getTranslateX]
1153
- );
1154
- const animateOut = useCallback(
1155
- async (element) => {
1156
- if (!element) return;
1157
- setIsVisible(false);
1158
- const translateX = getTranslateX();
1159
- await animate(element, [
1160
- { transform: "translate3d(0, 0, 0)", opacity: 1 },
1161
- { transform: `translate3d(${translateX}, 0, 0)`, opacity: 0 }
1162
- ]);
1163
- setIsRendered(false);
1164
- if (useNativeDialog && dialogRef.current) {
1165
- dialogRef.current.close();
1166
- }
1167
- onAfterLeave?.();
1168
- modalContext.afterLeave();
1169
- },
1170
- [getTranslateX, useNativeDialog, onAfterLeave, modalContext]
1171
- );
1172
- const setupFocusTrap = useCallback(() => {
1173
- if (useNativeDialog) return;
1174
- if (!wrapperRef.current || !modalContext.onTopOfStack) return;
1175
- if (cleanupFocusTrapRef.current) return;
1176
- cleanupFocusTrapRef.current = createFocusTrap(wrapperRef.current, {
1177
- initialFocus: true,
1178
- returnFocus: false
1179
- });
1180
- }, [modalContext.onTopOfStack, useNativeDialog]);
1181
- const cleanupFocusTrap = useCallback(() => {
1182
- if (cleanupFocusTrapRef.current) {
1183
- cleanupFocusTrapRef.current();
1184
- cleanupFocusTrapRef.current = null;
1185
- }
1186
- }, []);
1187
- const setupEscapeKey = useCallback(() => {
1188
- if (useNativeDialog) return;
1189
- if (cleanupEscapeKeyRef.current) return;
1190
- if (config?.closeExplicitly) return;
1191
- cleanupEscapeKeyRef.current = onEscapeKey(() => {
1192
- if (modalContext.onTopOfStack) {
1193
- modalContext.close();
1194
- }
1195
- });
1196
- }, [config?.closeExplicitly, modalContext, useNativeDialog]);
1197
- const cleanupEscapeKey = useCallback(() => {
1198
- if (cleanupEscapeKeyRef.current) {
1199
- cleanupEscapeKeyRef.current();
1200
- cleanupEscapeKeyRef.current = null;
1201
- }
1202
- }, []);
1203
- const handleClickOutside = useCallback(
1204
- (event) => {
1205
- if (useNativeDialog) return;
1206
- if (!modalContext.onTopOfStack) return;
1207
- if (config?.closeExplicitly) return;
1208
- if (config?.closeOnClickOutside === false) return;
1209
- if (!wrapperRef.current) return;
1210
- if (!wrapperRef.current.contains(event.target)) {
1211
- modalContext.close();
1212
- }
1213
- },
1214
- [modalContext, config?.closeExplicitly, config?.closeOnClickOutside, useNativeDialog]
1215
- );
1216
- const handleCancel = useCallback(
1217
- (event) => {
1218
- event.preventDefault();
1219
- if (modalContext.onTopOfStack && !config?.closeExplicitly) {
1220
- modalContext.close();
1221
- }
1222
- },
1223
- [modalContext, config?.closeExplicitly]
1224
- );
1225
- const handleDialogClick = useCallback(
1226
- (event) => {
1227
- if (event.target === dialogRef.current) {
1228
- if (modalContext.onTopOfStack && !config?.closeExplicitly && config?.closeOnClickOutside !== false) {
1229
- modalContext.close();
1230
- }
1231
- }
1232
- },
1233
- [modalContext, config?.closeExplicitly, config?.closeOnClickOutside]
1234
- );
1235
- const prevIsOpenRef = useRef(modalContext.isOpen);
1236
- useEffect(() => {
1237
- if (useNativeDialog) {
1238
- if (modalContext.isOpen && !dialogRef.current?.open) {
1239
- dialogRef.current?.showModal();
1240
- animateIn(nativeWrapperRef.current);
1241
- } else if (!modalContext.isOpen && prevIsOpenRef.current) {
1242
- setEntered(false);
1243
- animateOut(nativeWrapperRef.current);
1244
- }
1245
- } else {
1246
- if (modalContext.isOpen && !isRendered) {
1247
- setIsRendered(true);
1248
- } else if (!modalContext.isOpen && prevIsOpenRef.current) {
1249
- setEntered(false);
1250
- animateOut(wrapperRef.current);
1251
- }
1252
- }
1253
- prevIsOpenRef.current = modalContext.isOpen;
1254
- }, [modalContext.isOpen, useNativeDialog, animateIn, animateOut, isRendered]);
1255
- useEffect(() => {
1256
- if (!useNativeDialog && isRendered && !entered && modalContext.isOpen) {
1257
- animateIn(wrapperRef.current).then(() => {
1258
- setupFocusTrap();
1259
- });
1260
- }
1261
- }, [isRendered, useNativeDialog, entered, modalContext.isOpen, animateIn, setupFocusTrap]);
1262
- useEffect(() => {
1263
- if (!useNativeDialog) {
1264
- setupEscapeKey();
1265
- }
1266
- return () => {
1267
- cleanupEscapeKey();
1268
- };
1269
- }, [useNativeDialog, setupEscapeKey, cleanupEscapeKey]);
1270
- useEffect(() => {
1271
- if (useNativeDialog) return;
1272
- if (modalContext.onTopOfStack) {
1273
- setupEscapeKey();
1274
- if (entered) {
1275
- setupFocusTrap();
1276
- }
1277
- } else {
1278
- cleanupFocusTrap();
1279
- cleanupEscapeKey();
1280
- }
1281
- }, [modalContext.onTopOfStack, entered, setupEscapeKey, setupFocusTrap, cleanupFocusTrap, cleanupEscapeKey, useNativeDialog]);
1282
- useEffect(() => {
1283
- return () => {
1284
- const wrapper = useNativeDialog ? nativeWrapperRef.current : wrapperRef.current;
1285
- if (wrapper) {
1286
- cancelAnimations(wrapper);
1287
- }
1288
- if (useNativeDialog) {
1289
- if (dialogRef.current?.open) {
1290
- dialogRef.current.close();
1291
- }
1292
- } else {
1293
- cleanupFocusTrap();
1294
- cleanupEscapeKey();
1295
- }
1296
- };
1297
- }, [useNativeDialog, cleanupFocusTrap, cleanupEscapeKey]);
1298
- const renderContent = () => /* @__PURE__ */ jsxs(
1299
- "div",
1300
- {
1301
- className: `im-slideover-content relative ${config.paddingClasses} ${config.panelClasses}`,
1302
- "data-inertiaui-modal-entered": entered,
1303
- children: [
1304
- config.closeButton && /* @__PURE__ */ jsx("div", { className: "absolute right-0 top-0 pr-3 pt-3", children: /* @__PURE__ */ jsx(CloseButton, { onClick: modalContext.close }) }),
1305
- typeof children === "function" ? children({ modalContext, config }) : children
1306
- ]
1307
- }
1308
- );
1309
- if (useNativeDialog) {
1310
- return /* @__PURE__ */ jsx(
1311
- "dialog",
1312
- {
1313
- ref: dialogRef,
1314
- className: clsx(
1315
- "im-slideover-dialog m-0 overflow-visible bg-transparent p-0",
1316
- "size-full max-h-none max-w-none",
1317
- "backdrop:bg-black/75 backdrop:transition-opacity backdrop:duration-300",
1318
- isVisible ? "backdrop:opacity-100" : "backdrop:opacity-0",
1319
- !isFirstModal && "backdrop:bg-transparent"
1320
- ),
1321
- onCancel: handleCancel,
1322
- onClick: handleDialogClick,
1323
- children: /* @__PURE__ */ jsx("div", { className: "im-slideover-container fixed inset-0 overflow-y-auto overflow-x-hidden", children: /* @__PURE__ */ jsx(
1324
- "div",
1325
- {
1326
- className: clsx("im-slideover-positioner flex min-h-full items-center", {
1327
- "justify-start rtl:justify-end": config?.position === "left",
1328
- "justify-end rtl:justify-start": config?.position === "right"
1329
- }),
1330
- children: /* @__PURE__ */ jsx(
1331
- "div",
1332
- {
1333
- ref: nativeWrapperRef,
1334
- className: clsx("im-slideover-wrapper w-full transition-[filter] duration-300", modalContext.onTopOfStack ? "" : "blur-xs", maxWidthClass),
1335
- children: renderContent()
1336
- }
1337
- )
1338
- }
1339
- ) })
1340
- }
1341
- );
1342
- }
1343
- if (!isRendered) return null;
1344
- return /* @__PURE__ */ jsx(
1345
- "div",
1346
- {
1347
- className: "im-slideover-container fixed inset-0 z-40 overflow-y-auto overflow-x-hidden",
1348
- onMouseDown: handleClickOutside,
1349
- children: /* @__PURE__ */ jsx(
1350
- "div",
1351
- {
1352
- className: clsx("im-slideover-positioner flex min-h-full items-center", {
1353
- "justify-start rtl:justify-end": config?.position === "left",
1354
- "justify-end rtl:justify-start": config?.position === "right"
1355
- }),
1356
- onMouseDown: handleClickOutside,
1357
- children: /* @__PURE__ */ jsxs(
1358
- "div",
1359
- {
1360
- ref: wrapperRef,
1361
- role: "dialog",
1362
- "aria-modal": "true",
1363
- className: clsx("im-slideover-wrapper w-full transition-[filter] duration-300", modalContext.onTopOfStack ? "" : "blur-xs", maxWidthClass),
1364
- children: [
1365
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Dialog" }),
1366
- renderContent()
1367
- ]
1368
- }
1369
- )
1370
- }
1371
- )
1372
- }
1373
- );
1031
+ //#endregion
1032
+ //#region src/SlideoverContent.tsx
1033
+ var SlideoverContent = ({ modalContext, config, useNativeDialog, isFirstModal, onAfterLeave, children }) => {
1034
+ const [isRendered, setIsRendered] = useState(false);
1035
+ const [isVisible, setIsVisible] = useState(false);
1036
+ const [entered, setEntered] = useState(false);
1037
+ const wrapperRef = useRef(null);
1038
+ const dialogRef = useRef(null);
1039
+ const nativeWrapperRef = useRef(null);
1040
+ const cleanupFocusTrapRef = useRef(null);
1041
+ const cleanupEscapeKeyRef = useRef(null);
1042
+ const isLeft = config.position === "left";
1043
+ const maxWidthClass = useMemo(() => getMaxWidthClass(config.maxWidth), [config.maxWidth]);
1044
+ const getTranslateX = useCallback(() => isLeft ? "-100%" : "100%", [isLeft]);
1045
+ const animateIn = useCallback(async (element) => {
1046
+ if (!element) return;
1047
+ setIsVisible(true);
1048
+ await animate(element, [{
1049
+ transform: `translate3d(${getTranslateX()}, 0, 0)`,
1050
+ opacity: 0
1051
+ }, {
1052
+ transform: "translate3d(0, 0, 0)",
1053
+ opacity: 1
1054
+ }]);
1055
+ setEntered(true);
1056
+ }, [getTranslateX]);
1057
+ const animateOut = useCallback(async (element) => {
1058
+ if (!element) return;
1059
+ setIsVisible(false);
1060
+ await animate(element, [{
1061
+ transform: "translate3d(0, 0, 0)",
1062
+ opacity: 1
1063
+ }, {
1064
+ transform: `translate3d(${getTranslateX()}, 0, 0)`,
1065
+ opacity: 0
1066
+ }]);
1067
+ setIsRendered(false);
1068
+ if (useNativeDialog && dialogRef.current) dialogRef.current.close();
1069
+ onAfterLeave?.();
1070
+ modalContext.afterLeave();
1071
+ }, [
1072
+ getTranslateX,
1073
+ useNativeDialog,
1074
+ onAfterLeave,
1075
+ modalContext
1076
+ ]);
1077
+ const setupFocusTrap = useCallback(() => {
1078
+ if (useNativeDialog) return;
1079
+ if (!wrapperRef.current || !modalContext.onTopOfStack) return;
1080
+ if (cleanupFocusTrapRef.current) return;
1081
+ cleanupFocusTrapRef.current = createFocusTrap(wrapperRef.current, {
1082
+ initialFocus: true,
1083
+ returnFocus: false
1084
+ });
1085
+ }, [modalContext.onTopOfStack, useNativeDialog]);
1086
+ const cleanupFocusTrap = useCallback(() => {
1087
+ if (cleanupFocusTrapRef.current) {
1088
+ cleanupFocusTrapRef.current();
1089
+ cleanupFocusTrapRef.current = null;
1090
+ }
1091
+ }, []);
1092
+ const setupEscapeKey = useCallback(() => {
1093
+ if (useNativeDialog) return;
1094
+ if (cleanupEscapeKeyRef.current) return;
1095
+ if (config?.closeExplicitly) return;
1096
+ cleanupEscapeKeyRef.current = onEscapeKey(() => {
1097
+ if (modalContext.onTopOfStack) modalContext.close();
1098
+ });
1099
+ }, [
1100
+ config?.closeExplicitly,
1101
+ modalContext,
1102
+ useNativeDialog
1103
+ ]);
1104
+ const cleanupEscapeKey = useCallback(() => {
1105
+ if (cleanupEscapeKeyRef.current) {
1106
+ cleanupEscapeKeyRef.current();
1107
+ cleanupEscapeKeyRef.current = null;
1108
+ }
1109
+ }, []);
1110
+ const handleClickOutside = useCallback((event) => {
1111
+ if (useNativeDialog) return;
1112
+ if (!modalContext.onTopOfStack) return;
1113
+ if (config?.closeExplicitly) return;
1114
+ if (config?.closeOnClickOutside === false) return;
1115
+ if (!wrapperRef.current) return;
1116
+ if (!wrapperRef.current.contains(event.target)) modalContext.close();
1117
+ }, [
1118
+ modalContext,
1119
+ config?.closeExplicitly,
1120
+ config?.closeOnClickOutside,
1121
+ useNativeDialog
1122
+ ]);
1123
+ const handleCancel = useCallback((event) => {
1124
+ event.preventDefault();
1125
+ if (modalContext.onTopOfStack && !config?.closeExplicitly) modalContext.close();
1126
+ }, [modalContext, config?.closeExplicitly]);
1127
+ const handleDialogClick = useCallback((event) => {
1128
+ if (event.target === dialogRef.current) {
1129
+ if (modalContext.onTopOfStack && !config?.closeExplicitly && config?.closeOnClickOutside !== false) modalContext.close();
1130
+ }
1131
+ }, [
1132
+ modalContext,
1133
+ config?.closeExplicitly,
1134
+ config?.closeOnClickOutside
1135
+ ]);
1136
+ const prevIsOpenRef = useRef(modalContext.isOpen);
1137
+ useEffect(() => {
1138
+ if (useNativeDialog) {
1139
+ if (modalContext.isOpen && !dialogRef.current?.open) {
1140
+ dialogRef.current?.showModal();
1141
+ animateIn(nativeWrapperRef.current);
1142
+ } else if (!modalContext.isOpen && prevIsOpenRef.current) {
1143
+ setEntered(false);
1144
+ animateOut(nativeWrapperRef.current);
1145
+ }
1146
+ } else if (modalContext.isOpen && !isRendered) setIsRendered(true);
1147
+ else if (!modalContext.isOpen && prevIsOpenRef.current) {
1148
+ setEntered(false);
1149
+ animateOut(wrapperRef.current);
1150
+ }
1151
+ prevIsOpenRef.current = modalContext.isOpen;
1152
+ }, [
1153
+ modalContext.isOpen,
1154
+ useNativeDialog,
1155
+ animateIn,
1156
+ animateOut,
1157
+ isRendered
1158
+ ]);
1159
+ useEffect(() => {
1160
+ if (!useNativeDialog && isRendered && !entered && modalContext.isOpen) animateIn(wrapperRef.current).then(() => {
1161
+ setupFocusTrap();
1162
+ });
1163
+ }, [
1164
+ isRendered,
1165
+ useNativeDialog,
1166
+ entered,
1167
+ modalContext.isOpen,
1168
+ animateIn,
1169
+ setupFocusTrap
1170
+ ]);
1171
+ useEffect(() => {
1172
+ if (!useNativeDialog) setupEscapeKey();
1173
+ return () => {
1174
+ cleanupEscapeKey();
1175
+ };
1176
+ }, [
1177
+ useNativeDialog,
1178
+ setupEscapeKey,
1179
+ cleanupEscapeKey
1180
+ ]);
1181
+ useEffect(() => {
1182
+ if (useNativeDialog) return;
1183
+ if (modalContext.onTopOfStack) {
1184
+ setupEscapeKey();
1185
+ if (entered) setupFocusTrap();
1186
+ } else {
1187
+ cleanupFocusTrap();
1188
+ cleanupEscapeKey();
1189
+ }
1190
+ }, [
1191
+ modalContext.onTopOfStack,
1192
+ entered,
1193
+ setupEscapeKey,
1194
+ setupFocusTrap,
1195
+ cleanupFocusTrap,
1196
+ cleanupEscapeKey,
1197
+ useNativeDialog
1198
+ ]);
1199
+ useEffect(() => {
1200
+ return () => {
1201
+ const wrapper = useNativeDialog ? nativeWrapperRef.current : wrapperRef.current;
1202
+ if (wrapper) cancelAnimations(wrapper);
1203
+ if (useNativeDialog) {
1204
+ if (dialogRef.current?.open) dialogRef.current.close();
1205
+ } else {
1206
+ cleanupFocusTrap();
1207
+ cleanupEscapeKey();
1208
+ }
1209
+ };
1210
+ }, [
1211
+ useNativeDialog,
1212
+ cleanupFocusTrap,
1213
+ cleanupEscapeKey
1214
+ ]);
1215
+ const renderContent = () => /* @__PURE__ */ jsxs("div", {
1216
+ className: `im-slideover-content relative ${config.paddingClasses} ${config.panelClasses}`,
1217
+ "data-inertiaui-modal-entered": entered,
1218
+ children: [config.closeButton && /* @__PURE__ */ jsx("div", {
1219
+ className: "absolute top-0 right-0 pt-3 pr-3",
1220
+ children: /* @__PURE__ */ jsx(CloseButton, { onClick: modalContext.close })
1221
+ }), typeof children === "function" ? children({
1222
+ modalContext,
1223
+ config
1224
+ }) : children]
1225
+ });
1226
+ if (useNativeDialog) return /* @__PURE__ */ jsx("dialog", {
1227
+ ref: dialogRef,
1228
+ className: clsx("im-slideover-dialog m-0 overflow-visible bg-transparent p-0", "size-full max-h-none max-w-none", "backdrop:bg-black/75 backdrop:transition-opacity backdrop:duration-300", isVisible ? "backdrop:opacity-100" : "backdrop:opacity-0", !isFirstModal && "backdrop:bg-transparent"),
1229
+ onCancel: handleCancel,
1230
+ onClick: handleDialogClick,
1231
+ children: /* @__PURE__ */ jsx("div", {
1232
+ className: "im-slideover-container fixed inset-0 overflow-x-hidden overflow-y-auto",
1233
+ children: /* @__PURE__ */ jsx("div", {
1234
+ className: clsx("im-slideover-positioner flex min-h-full items-center", {
1235
+ "justify-start rtl:justify-end": config?.position === "left",
1236
+ "justify-end rtl:justify-start": config?.position === "right"
1237
+ }),
1238
+ children: /* @__PURE__ */ jsx("div", {
1239
+ ref: nativeWrapperRef,
1240
+ className: clsx("im-slideover-wrapper w-full transition-[filter] duration-300", modalContext.onTopOfStack ? "" : "blur-xs", maxWidthClass),
1241
+ children: renderContent()
1242
+ })
1243
+ })
1244
+ })
1245
+ });
1246
+ if (!isRendered) return null;
1247
+ return /* @__PURE__ */ jsx("div", {
1248
+ className: "im-slideover-container fixed inset-0 z-40 overflow-x-hidden overflow-y-auto",
1249
+ onMouseDown: handleClickOutside,
1250
+ children: /* @__PURE__ */ jsx("div", {
1251
+ className: clsx("im-slideover-positioner flex min-h-full items-center", {
1252
+ "justify-start rtl:justify-end": config?.position === "left",
1253
+ "justify-end rtl:justify-start": config?.position === "right"
1254
+ }),
1255
+ onMouseDown: handleClickOutside,
1256
+ children: /* @__PURE__ */ jsxs("div", {
1257
+ ref: wrapperRef,
1258
+ role: "dialog",
1259
+ "aria-modal": "true",
1260
+ className: clsx("im-slideover-wrapper w-full transition-[filter] duration-300", modalContext.onTopOfStack ? "" : "blur-xs", maxWidthClass),
1261
+ children: [/* @__PURE__ */ jsx("span", {
1262
+ className: "sr-only",
1263
+ children: "Dialog"
1264
+ }), renderContent()]
1265
+ })
1266
+ })
1267
+ });
1374
1268
  };
1375
- const Modal = forwardRef(
1376
- (allProps, ref) => {
1377
- const { name, children, onFocus, onBlur, onClose, onSuccess, onAfterLeave, ...props } = allProps;
1378
- const renderChildren = (contentProps) => {
1379
- if (typeof children === "function") {
1380
- return children(contentProps);
1381
- }
1382
- return children;
1383
- };
1384
- const headlessModalRef = useRef(null);
1385
- const cleanupScrollLockRef = useRef(null);
1386
- const cleanupAriaHiddenRef = useRef(null);
1387
- const [rendered, setRendered] = useState(false);
1388
- const useNativeDialog = useMemo(() => getConfig("useNativeDialog"), []);
1389
- useImperativeHandle(ref, () => headlessModalRef.current, [headlessModalRef]);
1390
- useEffect(() => {
1391
- return () => {
1392
- cleanupScrollLockRef.current?.();
1393
- cleanupAriaHiddenRef.current?.();
1394
- };
1395
- }, []);
1396
- const handleSuccess = useCallback(() => {
1397
- onSuccess?.();
1398
- if (!cleanupScrollLockRef.current) {
1399
- cleanupScrollLockRef.current = lockScroll();
1400
- cleanupAriaHiddenRef.current = markAriaHidden(getConfig("appElement"));
1401
- }
1402
- }, [onSuccess]);
1403
- const handleClose = useCallback(() => {
1404
- onClose?.();
1405
- cleanupScrollLockRef.current?.();
1406
- cleanupAriaHiddenRef.current?.();
1407
- cleanupScrollLockRef.current = null;
1408
- cleanupAriaHiddenRef.current = null;
1409
- }, [onClose]);
1410
- const handleAfterLeave = useCallback(() => {
1411
- onAfterLeave?.();
1412
- }, [onAfterLeave]);
1413
- return /* @__PURE__ */ jsx(
1414
- HeadlessModal,
1415
- {
1416
- ref: headlessModalRef,
1417
- name,
1418
- onFocus: onFocus ?? void 0,
1419
- onBlur: onBlur ?? void 0,
1420
- onClose: handleClose,
1421
- onSuccess: handleSuccess,
1422
- ...props,
1423
- children: ({
1424
- afterLeave,
1425
- close,
1426
- config,
1427
- emit,
1428
- getChildModal,
1429
- getParentModal,
1430
- id,
1431
- index,
1432
- isOpen,
1433
- modalContext,
1434
- onTopOfStack,
1435
- reload,
1436
- setOpen,
1437
- shouldRender,
1438
- ...extraProps
1439
- }) => /* @__PURE__ */ jsx(ModalPortal, { children: /* @__PURE__ */ jsxs(
1440
- "div",
1441
- {
1442
- className: "im-dialog relative z-20",
1443
- "data-inertiaui-modal-id": id,
1444
- "data-inertiaui-modal-index": index,
1445
- "aria-hidden": !onTopOfStack,
1446
- children: [
1447
- index === 0 && !useNativeDialog && /* @__PURE__ */ jsx(
1448
- BackdropTransition,
1449
- {
1450
- show: isOpen,
1451
- appear: !rendered,
1452
- onAfterAppear: () => setRendered(true)
1453
- }
1454
- ),
1455
- config.slideover ? /* @__PURE__ */ jsx(
1456
- SlideoverContent,
1457
- {
1458
- modalContext,
1459
- config,
1460
- useNativeDialog,
1461
- isFirstModal: index === 0,
1462
- onAfterLeave: handleAfterLeave,
1463
- children: renderChildren({
1464
- ...extraProps,
1465
- afterLeave,
1466
- close,
1467
- config,
1468
- emit,
1469
- getChildModal,
1470
- getParentModal,
1471
- id,
1472
- index,
1473
- isOpen,
1474
- modalContext,
1475
- onTopOfStack,
1476
- reload,
1477
- setOpen,
1478
- shouldRender
1479
- })
1480
- }
1481
- ) : /* @__PURE__ */ jsx(
1482
- ModalContent,
1483
- {
1484
- modalContext,
1485
- config,
1486
- useNativeDialog,
1487
- isFirstModal: index === 0,
1488
- onAfterLeave: handleAfterLeave,
1489
- children: renderChildren({
1490
- ...extraProps,
1491
- afterLeave,
1492
- close,
1493
- config,
1494
- emit,
1495
- getChildModal,
1496
- getParentModal,
1497
- id,
1498
- index,
1499
- isOpen,
1500
- modalContext,
1501
- onTopOfStack,
1502
- reload,
1503
- setOpen,
1504
- shouldRender
1505
- })
1506
- }
1507
- )
1508
- ]
1509
- }
1510
- ) })
1511
- }
1512
- );
1513
- }
1514
- );
1269
+ //#endregion
1270
+ //#region src/Modal.tsx
1271
+ var Modal = forwardRef((allProps, ref) => {
1272
+ const { name, children, onFocus, onBlur, onClose, onSuccess, onAfterLeave, ...props } = allProps;
1273
+ const renderChildren = (contentProps) => {
1274
+ if (typeof children === "function") return children(contentProps);
1275
+ return children;
1276
+ };
1277
+ const headlessModalRef = useRef(null);
1278
+ const cleanupScrollLockRef = useRef(null);
1279
+ const cleanupAriaHiddenRef = useRef(null);
1280
+ const [rendered, setRendered] = useState(false);
1281
+ const useNativeDialog = useMemo(() => getConfig("useNativeDialog"), []);
1282
+ useImperativeHandle(ref, () => headlessModalRef.current, [headlessModalRef]);
1283
+ useEffect(() => {
1284
+ return () => {
1285
+ cleanupScrollLockRef.current?.();
1286
+ cleanupAriaHiddenRef.current?.();
1287
+ };
1288
+ }, []);
1289
+ const handleSuccess = useCallback(() => {
1290
+ onSuccess?.();
1291
+ if (!cleanupScrollLockRef.current) {
1292
+ cleanupScrollLockRef.current = lockScroll();
1293
+ cleanupAriaHiddenRef.current = markAriaHidden(getConfig("appElement"));
1294
+ }
1295
+ }, [onSuccess]);
1296
+ const handleClose = useCallback(() => {
1297
+ onClose?.();
1298
+ cleanupScrollLockRef.current?.();
1299
+ cleanupAriaHiddenRef.current?.();
1300
+ cleanupScrollLockRef.current = null;
1301
+ cleanupAriaHiddenRef.current = null;
1302
+ }, [onClose]);
1303
+ const handleAfterLeave = useCallback(() => {
1304
+ onAfterLeave?.();
1305
+ }, [onAfterLeave]);
1306
+ return /* @__PURE__ */ jsx(HeadlessModal, {
1307
+ ref: headlessModalRef,
1308
+ name,
1309
+ onFocus: onFocus ?? void 0,
1310
+ onBlur: onBlur ?? void 0,
1311
+ onClose: handleClose,
1312
+ onSuccess: handleSuccess,
1313
+ ...props,
1314
+ children: ({ afterLeave, close, config, emit, getChildModal, getParentModal, id, index, isOpen, modalContext, onTopOfStack, reload, setOpen, shouldRender, ...extraProps }) => /* @__PURE__ */ jsx(ModalPortal, { children: /* @__PURE__ */ jsxs("div", {
1315
+ className: "im-dialog relative z-20",
1316
+ "data-inertiaui-modal-id": id,
1317
+ "data-inertiaui-modal-index": index,
1318
+ "aria-hidden": !onTopOfStack,
1319
+ children: [index === 0 && !useNativeDialog && /* @__PURE__ */ jsx(BackdropTransition, {
1320
+ show: isOpen,
1321
+ appear: !rendered,
1322
+ onAfterAppear: () => setRendered(true)
1323
+ }), config.slideover ? /* @__PURE__ */ jsx(SlideoverContent, {
1324
+ modalContext,
1325
+ config,
1326
+ useNativeDialog,
1327
+ isFirstModal: index === 0,
1328
+ onAfterLeave: handleAfterLeave,
1329
+ children: renderChildren({
1330
+ ...extraProps,
1331
+ afterLeave,
1332
+ close,
1333
+ config,
1334
+ emit,
1335
+ getChildModal,
1336
+ getParentModal,
1337
+ id,
1338
+ index,
1339
+ isOpen,
1340
+ modalContext,
1341
+ onTopOfStack,
1342
+ reload,
1343
+ setOpen,
1344
+ shouldRender
1345
+ })
1346
+ }) : /* @__PURE__ */ jsx(ModalContent, {
1347
+ modalContext,
1348
+ config,
1349
+ useNativeDialog,
1350
+ isFirstModal: index === 0,
1351
+ onAfterLeave: handleAfterLeave,
1352
+ children: renderChildren({
1353
+ ...extraProps,
1354
+ afterLeave,
1355
+ close,
1356
+ config,
1357
+ emit,
1358
+ getChildModal,
1359
+ getParentModal,
1360
+ id,
1361
+ index,
1362
+ isOpen,
1363
+ modalContext,
1364
+ onTopOfStack,
1365
+ reload,
1366
+ setOpen,
1367
+ shouldRender
1368
+ })
1369
+ })]
1370
+ }) })
1371
+ });
1372
+ });
1515
1373
  function ModalPortal({ children }) {
1516
- const [mounted, setMounted] = useState(false);
1517
- useEffect(() => {
1518
- setMounted(true);
1519
- }, []);
1520
- if (!mounted) return null;
1521
- return createPortal(children, document.body);
1374
+ const [mounted, setMounted] = useState(false);
1375
+ useEffect(() => {
1376
+ setMounted(true);
1377
+ }, []);
1378
+ if (!mounted) return null;
1379
+ return createPortal(children, document.body);
1522
1380
  }
1523
1381
  function BackdropTransition({ show, appear, onAfterAppear }) {
1524
- const [state, setState] = useState(() => {
1525
- if (appear && show) return "entering";
1526
- return show ? "entered" : "exited";
1527
- });
1528
- const initialRender = useRef(true);
1529
- const backdropRef = useRef(null);
1530
- useEffect(() => {
1531
- if (initialRender.current) {
1532
- initialRender.current = false;
1533
- if (appear && show) {
1534
- requestAnimationFrame(() => {
1535
- setState("entered");
1536
- const backdrop = backdropRef.current;
1537
- if (backdrop) {
1538
- const onTransitionEnd = (e) => {
1539
- if (e.target !== backdrop) return;
1540
- backdrop.removeEventListener("transitionend", onTransitionEnd);
1541
- onAfterAppear?.();
1542
- };
1543
- backdrop.addEventListener("transitionend", onTransitionEnd);
1544
- }
1545
- });
1546
- }
1547
- return;
1548
- }
1549
- if (show) {
1550
- setState("entering");
1551
- requestAnimationFrame(() => {
1552
- setState("entered");
1553
- });
1554
- } else {
1555
- setState("leaving");
1556
- const backdrop = backdropRef.current;
1557
- if (backdrop) {
1558
- const onTransitionEnd = (e) => {
1559
- if (e.target !== backdrop) return;
1560
- backdrop.removeEventListener("transitionend", onTransitionEnd);
1561
- setState("exited");
1562
- };
1563
- backdrop.addEventListener("transitionend", onTransitionEnd);
1564
- }
1565
- }
1566
- }, [show, appear, onAfterAppear]);
1567
- if (state === "exited") return null;
1568
- const isVisible = state === "entered";
1569
- return /* @__PURE__ */ jsx(
1570
- "div",
1571
- {
1572
- ref: backdropRef,
1573
- className: `im-backdrop fixed inset-0 z-30 bg-black/75 transition-opacity duration-300 ease-in-out ${isVisible ? "opacity-100" : "opacity-0"}`,
1574
- "aria-hidden": "true"
1575
- }
1576
- );
1382
+ const [state, setState] = useState(() => {
1383
+ if (appear && show) return "entering";
1384
+ return show ? "entered" : "exited";
1385
+ });
1386
+ const initialRender = useRef(true);
1387
+ const backdropRef = useRef(null);
1388
+ useEffect(() => {
1389
+ if (initialRender.current) {
1390
+ initialRender.current = false;
1391
+ if (appear && show) requestAnimationFrame(() => {
1392
+ setState("entered");
1393
+ const backdrop = backdropRef.current;
1394
+ if (backdrop) {
1395
+ const onTransitionEnd = (e) => {
1396
+ if (e.target !== backdrop) return;
1397
+ backdrop.removeEventListener("transitionend", onTransitionEnd);
1398
+ onAfterAppear?.();
1399
+ };
1400
+ backdrop.addEventListener("transitionend", onTransitionEnd);
1401
+ }
1402
+ });
1403
+ return;
1404
+ }
1405
+ if (show) {
1406
+ setState("entering");
1407
+ requestAnimationFrame(() => {
1408
+ setState("entered");
1409
+ });
1410
+ } else {
1411
+ setState("leaving");
1412
+ const backdrop = backdropRef.current;
1413
+ if (backdrop) {
1414
+ const onTransitionEnd = (e) => {
1415
+ if (e.target !== backdrop) return;
1416
+ backdrop.removeEventListener("transitionend", onTransitionEnd);
1417
+ setState("exited");
1418
+ };
1419
+ backdrop.addEventListener("transitionend", onTransitionEnd);
1420
+ }
1421
+ }
1422
+ }, [
1423
+ show,
1424
+ appear,
1425
+ onAfterAppear
1426
+ ]);
1427
+ if (state === "exited") return null;
1428
+ return /* @__PURE__ */ jsx("div", {
1429
+ ref: backdropRef,
1430
+ className: `im-backdrop fixed inset-0 z-30 bg-black/75 transition-opacity duration-300 ease-in-out ${state === "entered" ? "opacity-100" : "opacity-0"}`,
1431
+ "aria-hidden": "true"
1432
+ });
1577
1433
  }
1578
1434
  Modal.displayName = "Modal";
1579
- const ModalLink = ({
1580
- href,
1581
- method = "get",
1582
- data = {},
1583
- as: Component = "a",
1584
- headers = {},
1585
- queryStringArrayFormat = "brackets",
1586
- onAfterLeave,
1587
- onBlur,
1588
- onClose,
1589
- onError,
1590
- onFocus,
1591
- onStart,
1592
- onSuccess,
1593
- onPrefetching,
1594
- onPrefetched,
1595
- navigate,
1596
- prefetch: prefetch$1 = false,
1597
- cacheFor = 3e4,
1598
- children,
1599
- ...props
1600
- }) => {
1601
- const [loading, setLoading] = useState(false);
1602
- const [modalContext, setModalContext] = useState(null);
1603
- const { stack, visit } = useModalStack();
1604
- const hoverTimeout = useRef(null);
1605
- const shouldNavigate = useMemo(() => {
1606
- return navigate ?? getConfig("navigate");
1607
- }, [navigate]);
1608
- const prefetchModes = useMemo(() => {
1609
- if (prefetch$1 === true) {
1610
- return ["hover"];
1611
- }
1612
- if (prefetch$1 === false) {
1613
- return [];
1614
- }
1615
- if (Array.isArray(prefetch$1)) {
1616
- return prefetch$1;
1617
- }
1618
- return [prefetch$1];
1619
- }, [prefetch$1]);
1620
- const doPrefetch = useCallback(() => {
1621
- prefetch(href, {
1622
- method,
1623
- data,
1624
- headers,
1625
- queryStringArrayFormat,
1626
- cacheFor,
1627
- onPrefetching: onPrefetching ?? void 0,
1628
- onPrefetched: onPrefetched ?? void 0
1629
- });
1630
- }, [href, method, data, headers, queryStringArrayFormat, cacheFor, onPrefetching, onPrefetched]);
1631
- const handleMouseEnter = useCallback(() => {
1632
- if (!prefetchModes.includes("hover")) return;
1633
- hoverTimeout.current = setTimeout(() => {
1634
- doPrefetch();
1635
- }, 75);
1636
- }, [prefetchModes, doPrefetch]);
1637
- const handleMouseLeave = useCallback(() => {
1638
- if (hoverTimeout.current) {
1639
- clearTimeout(hoverTimeout.current);
1640
- hoverTimeout.current = null;
1641
- }
1642
- }, []);
1643
- const handleMouseDown = useCallback(
1644
- (event) => {
1645
- if (!prefetchModes.includes("click")) return;
1646
- if (event.button !== 0) return;
1647
- doPrefetch();
1648
- },
1649
- [prefetchModes, doPrefetch]
1650
- );
1651
- useEffect(() => {
1652
- if (prefetchModes.includes("mount")) {
1653
- doPrefetch();
1654
- }
1655
- }, []);
1656
- useEffect(() => {
1657
- return () => {
1658
- if (hoverTimeout.current) {
1659
- clearTimeout(hoverTimeout.current);
1660
- }
1661
- };
1662
- }, []);
1663
- const standardProps = {};
1664
- const customEvents = {};
1665
- Object.keys(props).forEach((key) => {
1666
- if (modalPropNames.includes(key)) {
1667
- return;
1668
- }
1669
- if (key.startsWith("on") && typeof props[key] === "function") {
1670
- if (isStandardDomEvent(key)) {
1671
- standardProps[key] = props[key];
1672
- } else {
1673
- customEvents[key] = props[key];
1674
- }
1675
- } else {
1676
- standardProps[key] = props[key];
1677
- }
1678
- });
1679
- const [isBlurred, setIsBlurred] = useState(false);
1680
- useEffect(() => {
1681
- if (!modalContext) {
1682
- return;
1683
- }
1684
- if (modalContext.onTopOfStack && isBlurred) {
1685
- onFocus?.();
1686
- } else if (!modalContext.onTopOfStack && !isBlurred) {
1687
- onBlur?.();
1688
- }
1689
- setIsBlurred(!modalContext.onTopOfStack);
1690
- }, [stack]);
1691
- const onCloseCallback = useCallback(() => {
1692
- onClose?.();
1693
- }, [onClose]);
1694
- const onAfterLeaveCallback = useCallback(() => {
1695
- setModalContext(null);
1696
- onAfterLeave?.();
1697
- }, [onAfterLeave]);
1698
- const handle = useCallback(
1699
- (e) => {
1700
- e?.preventDefault();
1701
- if (loading) return;
1702
- if (!href.startsWith("#")) {
1703
- setLoading(true);
1704
- onStart?.();
1705
- }
1706
- visit(
1707
- href,
1708
- method,
1709
- data,
1710
- headers,
1711
- rejectNullValues(only(props, modalPropNames)),
1712
- () => onCloseCallback(),
1713
- onAfterLeaveCallback,
1714
- queryStringArrayFormat,
1715
- shouldNavigate
1716
- ).then((newModalContext) => {
1717
- setModalContext(newModalContext);
1718
- newModalContext.registerEventListenersFromProps(customEvents);
1719
- onSuccess?.();
1720
- }).catch((error) => {
1721
- console.error(error);
1722
- onError?.(error);
1723
- }).finally(() => setLoading(false));
1724
- },
1725
- [href, method, data, headers, queryStringArrayFormat, props, onCloseCallback, onAfterLeaveCallback]
1726
- );
1727
- return /* @__PURE__ */ jsx(
1728
- Component,
1729
- {
1730
- ...standardProps,
1731
- href,
1732
- onClick: handle,
1733
- onMouseEnter: handleMouseEnter,
1734
- onMouseLeave: handleMouseLeave,
1735
- onMouseDown: handleMouseDown,
1736
- children: typeof children === "function" ? children({ loading }) : children
1737
- }
1738
- );
1435
+ //#endregion
1436
+ //#region src/ModalLink.tsx
1437
+ var ModalLink = ({ href, method = "get", data = {}, as: Component = "a", headers = {}, queryStringArrayFormat = "brackets", onAfterLeave, onBlur, onClose, onError, onFocus, onStart, onSuccess, onPrefetching, onPrefetched, navigate, prefetch: prefetch$1 = false, cacheFor = 3e4, children, ...props }) => {
1438
+ const [loading, setLoading] = useState(false);
1439
+ const [modalContext, setModalContext] = useState(null);
1440
+ const { stack, visit } = useModalStack();
1441
+ const hoverTimeout = useRef(null);
1442
+ const shouldNavigate = useMemo(() => {
1443
+ return navigate ?? getConfig("navigate");
1444
+ }, [navigate]);
1445
+ const prefetchModes = useMemo(() => {
1446
+ if (prefetch$1 === true) return ["hover"];
1447
+ if (prefetch$1 === false) return [];
1448
+ if (Array.isArray(prefetch$1)) return prefetch$1;
1449
+ return [prefetch$1];
1450
+ }, [prefetch$1]);
1451
+ const doPrefetch = useCallback(() => {
1452
+ prefetch(href, {
1453
+ method,
1454
+ data,
1455
+ headers,
1456
+ queryStringArrayFormat,
1457
+ cacheFor,
1458
+ onPrefetching: onPrefetching ?? void 0,
1459
+ onPrefetched: onPrefetched ?? void 0
1460
+ });
1461
+ }, [
1462
+ href,
1463
+ method,
1464
+ data,
1465
+ headers,
1466
+ queryStringArrayFormat,
1467
+ cacheFor,
1468
+ onPrefetching,
1469
+ onPrefetched
1470
+ ]);
1471
+ const handleMouseEnter = useCallback(() => {
1472
+ if (!prefetchModes.includes("hover")) return;
1473
+ hoverTimeout.current = setTimeout(() => {
1474
+ doPrefetch();
1475
+ }, 75);
1476
+ }, [prefetchModes, doPrefetch]);
1477
+ const handleMouseLeave = useCallback(() => {
1478
+ if (hoverTimeout.current) {
1479
+ clearTimeout(hoverTimeout.current);
1480
+ hoverTimeout.current = null;
1481
+ }
1482
+ }, []);
1483
+ const handleMouseDown = useCallback((event) => {
1484
+ if (!prefetchModes.includes("click")) return;
1485
+ if (event.button !== 0) return;
1486
+ doPrefetch();
1487
+ }, [prefetchModes, doPrefetch]);
1488
+ useEffect(() => {
1489
+ if (prefetchModes.includes("mount")) doPrefetch();
1490
+ }, []);
1491
+ useEffect(() => {
1492
+ return () => {
1493
+ if (hoverTimeout.current) clearTimeout(hoverTimeout.current);
1494
+ };
1495
+ }, []);
1496
+ const standardProps = {};
1497
+ const customEvents = {};
1498
+ Object.keys(props).forEach((key) => {
1499
+ if (modalPropNames.includes(key)) return;
1500
+ if (key.startsWith("on") && typeof props[key] === "function") if (isStandardDomEvent(key)) standardProps[key] = props[key];
1501
+ else customEvents[key] = props[key];
1502
+ else standardProps[key] = props[key];
1503
+ });
1504
+ const [isBlurred, setIsBlurred] = useState(false);
1505
+ useEffect(() => {
1506
+ if (!modalContext) return;
1507
+ if (modalContext.onTopOfStack && isBlurred) onFocus?.();
1508
+ else if (!modalContext.onTopOfStack && !isBlurred) onBlur?.();
1509
+ setIsBlurred(!modalContext.onTopOfStack);
1510
+ }, [stack]);
1511
+ const onCloseCallback = useCallback(() => {
1512
+ onClose?.();
1513
+ }, [onClose]);
1514
+ const onAfterLeaveCallback = useCallback(() => {
1515
+ setModalContext(null);
1516
+ onAfterLeave?.();
1517
+ }, [onAfterLeave]);
1518
+ const handle = useCallback((e) => {
1519
+ e?.preventDefault();
1520
+ if (loading) return;
1521
+ if (!href.startsWith("#")) {
1522
+ setLoading(true);
1523
+ onStart?.();
1524
+ }
1525
+ visit(href, method, data, headers, rejectNullValues(only(props, modalPropNames)), () => onCloseCallback(), onAfterLeaveCallback, queryStringArrayFormat, shouldNavigate).then((newModalContext) => {
1526
+ setModalContext(newModalContext);
1527
+ newModalContext.registerEventListenersFromProps(customEvents);
1528
+ onSuccess?.();
1529
+ }).catch((error) => {
1530
+ console.error(error);
1531
+ onError?.(error);
1532
+ }).finally(() => setLoading(false));
1533
+ }, [
1534
+ href,
1535
+ method,
1536
+ data,
1537
+ headers,
1538
+ queryStringArrayFormat,
1539
+ props,
1540
+ onCloseCallback,
1541
+ onAfterLeaveCallback
1542
+ ]);
1543
+ return /* @__PURE__ */ jsx(Component, {
1544
+ ...standardProps,
1545
+ href,
1546
+ onClick: handle,
1547
+ onMouseEnter: handleMouseEnter,
1548
+ onMouseLeave: handleMouseLeave,
1549
+ onMouseDown: handleMouseDown,
1550
+ children: typeof children === "function" ? children({ loading }) : children
1551
+ });
1739
1552
  };
1740
- const WhenVisible = ({ children, data, params, buffer, as, always, fallback }) => {
1741
- always = always ?? false;
1742
- as = as ?? "div";
1743
- fallback = fallback ?? null;
1744
- const [loaded, setLoaded] = useState(false);
1745
- const hasFetched = useRef(false);
1746
- const fetching = useRef(false);
1747
- const ref = useRef(null);
1748
- const modal = useModal();
1749
- const getReloadParams = useCallback(() => {
1750
- if (data) {
1751
- return {
1752
- only: Array.isArray(data) ? data : [data]
1753
- };
1754
- }
1755
- if (!params) {
1756
- throw new Error("You must provide either a `data` or `params` prop.");
1757
- }
1758
- return params;
1759
- }, [params, data]);
1760
- useEffect(() => {
1761
- if (!ref.current) {
1762
- return;
1763
- }
1764
- const observer = new IntersectionObserver(
1765
- (entries) => {
1766
- if (!entries[0].isIntersecting) {
1767
- return;
1768
- }
1769
- if (!always && hasFetched.current) {
1770
- observer.disconnect();
1771
- }
1772
- if (fetching.current) {
1773
- return;
1774
- }
1775
- hasFetched.current = true;
1776
- fetching.current = true;
1777
- const reloadParams = getReloadParams();
1778
- modal?.reload({
1779
- ...reloadParams,
1780
- onStart: () => {
1781
- fetching.current = true;
1782
- reloadParams.onStart?.();
1783
- },
1784
- onFinish: () => {
1785
- setLoaded(true);
1786
- fetching.current = false;
1787
- reloadParams.onFinish?.();
1788
- if (!always) {
1789
- observer.disconnect();
1790
- }
1791
- }
1792
- });
1793
- },
1794
- {
1795
- rootMargin: `${buffer || 0}px`
1796
- }
1797
- );
1798
- observer.observe(ref.current);
1799
- return () => {
1800
- observer.disconnect();
1801
- };
1802
- }, [ref, getReloadParams, buffer]);
1803
- if (always || !loaded) {
1804
- return createElement(
1805
- as,
1806
- {
1807
- props: null,
1808
- ref
1809
- },
1810
- loaded ? children : fallback
1811
- );
1812
- }
1813
- return loaded ? children : null;
1553
+ //#endregion
1554
+ //#region src/WhenVisible.tsx
1555
+ var WhenVisible = ({ children, data, params, buffer, as, always, fallback }) => {
1556
+ always = always ?? false;
1557
+ as = as ?? "div";
1558
+ fallback = fallback ?? null;
1559
+ const [loaded, setLoaded] = useState(false);
1560
+ const hasFetched = useRef(false);
1561
+ const fetching = useRef(false);
1562
+ const ref = useRef(null);
1563
+ const modal = useModal();
1564
+ const getReloadParams = useCallback(() => {
1565
+ if (data) return { only: Array.isArray(data) ? data : [data] };
1566
+ if (!params) throw new Error("You must provide either a `data` or `params` prop.");
1567
+ return params;
1568
+ }, [params, data]);
1569
+ useEffect(() => {
1570
+ if (!ref.current) return;
1571
+ const observer = new IntersectionObserver((entries) => {
1572
+ if (!entries[0].isIntersecting) return;
1573
+ if (!always && hasFetched.current) observer.disconnect();
1574
+ if (fetching.current) return;
1575
+ hasFetched.current = true;
1576
+ fetching.current = true;
1577
+ const reloadParams = getReloadParams();
1578
+ modal?.reload({
1579
+ ...reloadParams,
1580
+ onStart: () => {
1581
+ fetching.current = true;
1582
+ reloadParams.onStart?.();
1583
+ },
1584
+ onFinish: () => {
1585
+ setLoaded(true);
1586
+ fetching.current = false;
1587
+ reloadParams.onFinish?.();
1588
+ if (!always) observer.disconnect();
1589
+ }
1590
+ });
1591
+ }, { rootMargin: `${buffer || 0}px` });
1592
+ observer.observe(ref.current);
1593
+ return () => {
1594
+ observer.disconnect();
1595
+ };
1596
+ }, [
1597
+ ref,
1598
+ getReloadParams,
1599
+ buffer
1600
+ ]);
1601
+ if (always || !loaded) return createElement(as, {
1602
+ props: null,
1603
+ ref
1604
+ }, loaded ? children : fallback);
1605
+ return loaded ? children : null;
1814
1606
  };
1815
1607
  WhenVisible.displayName = "InertiaWhenVisible";
1816
- const setPageLayout = (layout) => (module) => {
1817
- module.default.layout = (page) => createElement(layout, { children: page });
1818
- return module;
1819
- };
1820
- export {
1821
- Deferred,
1822
- HeadlessModal,
1823
- Modal,
1824
- ModalLink,
1825
- ModalRoot,
1826
- ModalStackProvider,
1827
- WhenVisible,
1828
- vanilla as dialogUtils,
1829
- getConfig,
1830
- initFromPageProps,
1831
- modalPropNames,
1832
- prefetch,
1833
- putConfig,
1834
- renderApp,
1835
- resetConfig,
1836
- setPageLayout,
1837
- useModal,
1838
- useModalIndex,
1839
- useModalStack
1608
+ //#endregion
1609
+ //#region src/inertiauiModal.ts
1610
+ var setPageLayout = (layout) => (module) => {
1611
+ module.default.layout = (page) => createElement(layout, { children: page });
1612
+ return module;
1840
1613
  };
1841
- //# sourceMappingURL=inertiaui-modal.js.map
1614
+ //#endregion
1615
+ export { Deferred, HeadlessModal, Modal, ModalLink, ModalRoot, ModalStackProvider, WhenVisible, dialogUtils, getConfig, initFromPageProps, modalPropNames, prefetch, putConfig, renderApp, resetConfig, setPageLayout, useModal, useModalIndex, useModalStack };
1616
+
1617
+ //# sourceMappingURL=inertiaui-modal.js.map