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