@inertiaui/modal-react 2.0.0-beta.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ModalLink.d.ts +2 -2
- package/dist/cache.d.ts +12 -0
- package/dist/helpers.d.ts +1 -0
- package/dist/inertiaui-modal.js +92 -75
- package/dist/inertiaui-modal.js.map +1 -1
- package/dist/inertiaui-modal.umd.cjs +92 -74
- package/dist/inertiaui-modal.umd.cjs.map +1 -1
- package/dist/inertiauiModal.d.ts +1 -1
- package/dist/types.d.ts +12 -12
- package/package.json +11 -8
- package/src/ModalLink.tsx +2 -2
- package/src/ModalRoot.tsx +92 -126
- package/src/cache.ts +64 -0
- package/src/helpers.ts +3 -0
- package/src/inertiauiModal.ts +1 -0
- package/src/types.ts +13 -13
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function(global, factory) {
|
|
2
|
-
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("react"), require("react/jsx-runtime"), require("
|
|
3
|
-
})(this, (function(exports2, React, jsxRuntime,
|
|
2
|
+
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("react"), require("react/jsx-runtime"), require("@inertiaui/vanilla"), require("@inertiajs/react"), require("@inertiajs/core"), require("react-dom")) : typeof define === "function" && define.amd ? define(["exports", "react", "react/jsx-runtime", "@inertiaui/vanilla", "@inertiajs/react", "@inertiajs/core", "react-dom"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.InertiaUIModal = {}, global.React, global.ReactJSXRuntime, global.InertiaUIVanilla, global.InertiaReact, global.InertiaCore, global.ReactDOM));
|
|
3
|
+
})(this, (function(exports2, React, jsxRuntime, vanilla, react, core, reactDom) {
|
|
4
4
|
"use strict";
|
|
5
5
|
function _interopNamespaceDefault(e) {
|
|
6
6
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
@@ -90,56 +90,81 @@
|
|
|
90
90
|
const putConfig = (key, value) => configInstance.put(key, value);
|
|
91
91
|
const getConfig = (key) => configInstance.get(key);
|
|
92
92
|
const getConfigByType = (isSlideover, key) => configInstance.get(isSlideover ? `slideover.${key}` : `modal.${key}`);
|
|
93
|
+
function parseResponseData(data) {
|
|
94
|
+
return typeof data === "string" ? JSON.parse(data) : data;
|
|
95
|
+
}
|
|
93
96
|
function generateId(prefix = "inertiaui_") {
|
|
94
97
|
return vanilla.generateId(prefix);
|
|
95
98
|
}
|
|
99
|
+
class ResponseCache {
|
|
100
|
+
constructor() {
|
|
101
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
102
|
+
this.timers = /* @__PURE__ */ new Map();
|
|
103
|
+
this.inFlight = /* @__PURE__ */ new Map();
|
|
104
|
+
}
|
|
105
|
+
static key(method, url, data) {
|
|
106
|
+
return `${method}:${url}:${JSON.stringify(data)}`;
|
|
107
|
+
}
|
|
108
|
+
get(key) {
|
|
109
|
+
const cached = this.cache.get(key);
|
|
110
|
+
if (!cached) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
if (Date.now() > cached.expiresAt) {
|
|
114
|
+
this.delete(key);
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
return cached.response;
|
|
118
|
+
}
|
|
119
|
+
set(key, response, cacheFor) {
|
|
120
|
+
this.delete(key);
|
|
121
|
+
this.cache.set(key, {
|
|
122
|
+
response,
|
|
123
|
+
expiresAt: Date.now() + cacheFor
|
|
124
|
+
});
|
|
125
|
+
if (cacheFor > 0) {
|
|
126
|
+
this.timers.set(key, setTimeout(() => this.delete(key), cacheFor));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
delete(key) {
|
|
130
|
+
this.cache.delete(key);
|
|
131
|
+
const timer = this.timers.get(key);
|
|
132
|
+
if (timer) {
|
|
133
|
+
clearTimeout(timer);
|
|
134
|
+
this.timers.delete(key);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
getInFlight(key) {
|
|
138
|
+
return this.inFlight.get(key);
|
|
139
|
+
}
|
|
140
|
+
setInFlight(key, promise) {
|
|
141
|
+
this.inFlight.set(key, promise);
|
|
142
|
+
}
|
|
143
|
+
deleteInFlight(key) {
|
|
144
|
+
this.inFlight.delete(key);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
96
147
|
const ModalStackContext = React.createContext(null);
|
|
97
148
|
ModalStackContext.displayName = "ModalStackContext";
|
|
98
|
-
let pageVersion = null;
|
|
99
|
-
let resolveComponent = null;
|
|
100
149
|
let baseUrl = null;
|
|
150
|
+
let currentPageVersion = null;
|
|
101
151
|
let closingToBaseUrlTarget = null;
|
|
102
|
-
const prefetchCache =
|
|
103
|
-
const prefetchInFlight = /* @__PURE__ */ new Map();
|
|
104
|
-
function getPrefetchCacheKey(url, method, data) {
|
|
105
|
-
return `${method}:${url}:${JSON.stringify(data)}`;
|
|
106
|
-
}
|
|
107
|
-
function getCachedResponse(url, method, data) {
|
|
108
|
-
const key = getPrefetchCacheKey(url, method, data);
|
|
109
|
-
const cached = prefetchCache.get(key);
|
|
110
|
-
if (!cached) {
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
if (Date.now() > cached.expiresAt) {
|
|
114
|
-
prefetchCache.delete(key);
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
|
-
return cached.response;
|
|
118
|
-
}
|
|
119
|
-
function setCachedResponse(url, method, data, response, cacheFor) {
|
|
120
|
-
const key = getPrefetchCacheKey(url, method, data);
|
|
121
|
-
prefetchCache.set(key, {
|
|
122
|
-
response,
|
|
123
|
-
timestamp: Date.now(),
|
|
124
|
-
expiresAt: Date.now() + cacheFor
|
|
125
|
-
});
|
|
126
|
-
}
|
|
152
|
+
const prefetchCache = new ResponseCache();
|
|
127
153
|
function prefetch(href, options = {}) {
|
|
128
154
|
if (href.startsWith("#")) {
|
|
129
155
|
return Promise.resolve();
|
|
130
156
|
}
|
|
131
|
-
const method =
|
|
157
|
+
const method = options.method ?? "get";
|
|
132
158
|
const data = options.data ?? {};
|
|
133
159
|
const headers = options.headers ?? {};
|
|
134
160
|
const queryStringArrayFormat = options.queryStringArrayFormat ?? "brackets";
|
|
135
161
|
const cacheFor = options.cacheFor ?? 3e4;
|
|
136
162
|
const [url, mergedData] = core.mergeDataIntoQueryString(method, href || "", data, queryStringArrayFormat);
|
|
137
|
-
const
|
|
138
|
-
if (
|
|
163
|
+
const cacheKey = ResponseCache.key(method, url, mergedData);
|
|
164
|
+
if (prefetchCache.get(cacheKey)) {
|
|
139
165
|
return Promise.resolve();
|
|
140
166
|
}
|
|
141
|
-
const
|
|
142
|
-
const inFlight = prefetchInFlight.get(cacheKey);
|
|
167
|
+
const inFlight = prefetchCache.getInFlight(cacheKey);
|
|
143
168
|
if (inFlight) {
|
|
144
169
|
return inFlight.then(() => {
|
|
145
170
|
});
|
|
@@ -150,23 +175,23 @@
|
|
|
150
175
|
Accept: "text/html, application/xhtml+xml",
|
|
151
176
|
"X-Requested-With": "XMLHttpRequest",
|
|
152
177
|
"X-Inertia": "true",
|
|
153
|
-
"X-Inertia-Version":
|
|
178
|
+
"X-Inertia-Version": currentPageVersion ?? "",
|
|
154
179
|
"X-InertiaUI-Modal": generateId(),
|
|
155
180
|
"X-InertiaUI-Modal-Base-Url": baseUrl ?? ""
|
|
156
181
|
};
|
|
157
|
-
const request =
|
|
182
|
+
const request = react.http.getClient().request({
|
|
158
183
|
url,
|
|
159
184
|
method,
|
|
160
185
|
data: mergedData,
|
|
161
186
|
headers: requestHeaders
|
|
162
187
|
}).then((response) => {
|
|
163
|
-
|
|
188
|
+
prefetchCache.set(cacheKey, response, cacheFor);
|
|
164
189
|
options.onPrefetched?.();
|
|
165
190
|
return response;
|
|
166
191
|
}).finally(() => {
|
|
167
|
-
|
|
192
|
+
prefetchCache.deleteInFlight(cacheKey);
|
|
168
193
|
});
|
|
169
|
-
|
|
194
|
+
prefetchCache.setInFlight(cacheKey, request);
|
|
170
195
|
return request.then(() => {
|
|
171
196
|
});
|
|
172
197
|
}
|
|
@@ -308,14 +333,14 @@
|
|
|
308
333
|
if (!this.response?.url) {
|
|
309
334
|
return;
|
|
310
335
|
}
|
|
311
|
-
const method =
|
|
336
|
+
const method = options.method ?? "get";
|
|
312
337
|
const data = options.data ?? {};
|
|
313
338
|
options.onStart?.();
|
|
314
|
-
|
|
339
|
+
react.http.getClient().request({
|
|
315
340
|
url: this.response.url,
|
|
316
341
|
method,
|
|
317
|
-
data: method === "get" ?
|
|
318
|
-
params: method === "get" ? data :
|
|
342
|
+
data: method === "get" ? void 0 : data,
|
|
343
|
+
params: method === "get" ? data : void 0,
|
|
319
344
|
headers: {
|
|
320
345
|
...options.headers ?? {},
|
|
321
346
|
Accept: "text/html, application/xhtml+xml",
|
|
@@ -327,7 +352,7 @@
|
|
|
327
352
|
"X-InertiaUI-Modal-Base-Url": baseUrl ?? ""
|
|
328
353
|
}
|
|
329
354
|
}).then((response2) => {
|
|
330
|
-
this.updateProps(response2.data.props);
|
|
355
|
+
this.updateProps(parseResponseData(response2.data).props);
|
|
331
356
|
options.onSuccess?.(response2);
|
|
332
357
|
}).catch((error) => {
|
|
333
358
|
options.onError?.(error);
|
|
@@ -359,9 +384,6 @@
|
|
|
359
384
|
return typeof data === "object" && data !== null && "component" in data && typeof data.component === "string";
|
|
360
385
|
};
|
|
361
386
|
const pushFromResponseData = (responseData, config = {}, onClose = null, onAfterLeave = null) => {
|
|
362
|
-
if (!resolveComponent) {
|
|
363
|
-
return Promise.reject(new Error("resolveComponent not set"));
|
|
364
|
-
}
|
|
365
387
|
if (!isValidModalResponse(responseData)) {
|
|
366
388
|
return Promise.reject(
|
|
367
389
|
new Error(
|
|
@@ -369,7 +391,7 @@
|
|
|
369
391
|
)
|
|
370
392
|
);
|
|
371
393
|
}
|
|
372
|
-
return resolveComponent(responseData.component).then(
|
|
394
|
+
return react.router.resolveComponent(responseData.component).then(
|
|
373
395
|
(component) => push(component, responseData, config, onClose, onAfterLeave)
|
|
374
396
|
);
|
|
375
397
|
};
|
|
@@ -448,11 +470,12 @@
|
|
|
448
470
|
return;
|
|
449
471
|
}
|
|
450
472
|
const [url, data] = core.mergeDataIntoQueryString(method, href || "", payload, queryStringArrayFormat);
|
|
451
|
-
const cachedResponse =
|
|
473
|
+
const cachedResponse = prefetchCache.get(ResponseCache.key(method, url, data));
|
|
452
474
|
if (cachedResponse) {
|
|
475
|
+
const cachedData = parseResponseData(cachedResponse.data);
|
|
453
476
|
onSuccess?.(cachedResponse);
|
|
454
|
-
pushFromResponseData(
|
|
455
|
-
updateBrowserUrl(
|
|
477
|
+
pushFromResponseData(cachedData, config, onClose, onAfterLeave).then((modal) => {
|
|
478
|
+
updateBrowserUrl(cachedData.url, useBrowserHistory, cachedData);
|
|
456
479
|
resolve(modal);
|
|
457
480
|
}).catch(reject);
|
|
458
481
|
return;
|
|
@@ -465,21 +488,22 @@
|
|
|
465
488
|
Accept: "text/html, application/xhtml+xml",
|
|
466
489
|
"X-Requested-With": "XMLHttpRequest",
|
|
467
490
|
"X-Inertia": "true",
|
|
468
|
-
"X-Inertia-Version":
|
|
491
|
+
"X-Inertia-Version": currentPageVersion ?? "",
|
|
469
492
|
"X-InertiaUI-Modal": modalId,
|
|
470
493
|
"X-InertiaUI-Modal-Base-Url": baseUrl ?? ""
|
|
471
494
|
};
|
|
472
495
|
onStart?.();
|
|
473
496
|
react.progress?.start();
|
|
474
|
-
|
|
497
|
+
react.http.getClient().request({
|
|
475
498
|
url,
|
|
476
499
|
method,
|
|
477
500
|
data,
|
|
478
501
|
headers: requestHeaders
|
|
479
502
|
}).then((response) => {
|
|
503
|
+
const responseData = parseResponseData(response.data);
|
|
480
504
|
onSuccess?.(response);
|
|
481
|
-
pushFromResponseData(
|
|
482
|
-
updateBrowserUrl(
|
|
505
|
+
pushFromResponseData(responseData, config, onClose, onAfterLeave).then((modal) => {
|
|
506
|
+
updateBrowserUrl(responseData.url, useBrowserHistory, responseData);
|
|
483
507
|
resolve(modal);
|
|
484
508
|
}).catch(reject);
|
|
485
509
|
}).catch((...args) => {
|
|
@@ -536,10 +560,7 @@
|
|
|
536
560
|
const modalPropNames = ["closeButton", "closeExplicitly", "closeOnClickOutside", "maxWidth", "paddingClasses", "panelClasses", "position", "slideover"];
|
|
537
561
|
const initFromPageProps = (pageProps) => {
|
|
538
562
|
if (pageProps.initialPage) {
|
|
539
|
-
|
|
540
|
-
}
|
|
541
|
-
if (pageProps.resolveComponent) {
|
|
542
|
-
resolveComponent = pageProps.resolveComponent;
|
|
563
|
+
currentPageVersion = pageProps.initialPage.version ?? null;
|
|
543
564
|
}
|
|
544
565
|
};
|
|
545
566
|
const renderApp = (App, pageProps) => {
|
|
@@ -569,9 +590,19 @@
|
|
|
569
590
|
const context = React.useContext(ModalStackContext);
|
|
570
591
|
const $page = react.usePage();
|
|
571
592
|
const pendingModalKeysRef = React.useRef(/* @__PURE__ */ new Set());
|
|
593
|
+
currentPageVersion = $page.version ?? null;
|
|
572
594
|
const getModalKey = (modalData) => modalData.id || `${modalData.component}:${modalData.url}`;
|
|
573
595
|
const isNavigatingRef = React.useRef(false);
|
|
574
|
-
const
|
|
596
|
+
const pageRef = React.useRef($page);
|
|
597
|
+
pageRef.current = $page;
|
|
598
|
+
React.useLayoutEffect(() => react.http.onRequest((config) => {
|
|
599
|
+
const baseUrlValue = baseUrl ?? pageRef.current.props._inertiaui_modal?.baseUrl ?? null;
|
|
600
|
+
if (baseUrlValue) {
|
|
601
|
+
config.headers = config.headers ?? {};
|
|
602
|
+
config.headers["X-InertiaUI-Modal-Base-Url"] = baseUrlValue;
|
|
603
|
+
}
|
|
604
|
+
return config;
|
|
605
|
+
}), []);
|
|
575
606
|
React.useEffect(() => react.router.on("start", () => isNavigatingRef.current = true), []);
|
|
576
607
|
React.useEffect(() => react.router.on("finish", () => isNavigatingRef.current = false), []);
|
|
577
608
|
React.useEffect(
|
|
@@ -585,7 +616,6 @@
|
|
|
585
616
|
closingToBaseUrlTarget = null;
|
|
586
617
|
context?.closeAll(true);
|
|
587
618
|
baseUrl = null;
|
|
588
|
-
initialModalStillOpenedRef.current = false;
|
|
589
619
|
return;
|
|
590
620
|
}
|
|
591
621
|
closingToBaseUrlTarget = null;
|
|
@@ -593,13 +623,11 @@
|
|
|
593
623
|
if (!modalOnBase) {
|
|
594
624
|
context?.closeAll(true);
|
|
595
625
|
baseUrl = null;
|
|
596
|
-
initialModalStillOpenedRef.current = false;
|
|
597
626
|
return;
|
|
598
627
|
}
|
|
599
628
|
if (!vanilla.sameUrlPath(pageUrl, modalOnBase.url)) {
|
|
600
629
|
context?.closeAll(true);
|
|
601
630
|
baseUrl = null;
|
|
602
|
-
initialModalStillOpenedRef.current = false;
|
|
603
631
|
return;
|
|
604
632
|
}
|
|
605
633
|
const modalKey = getModalKey(modalOnBase);
|
|
@@ -619,6 +647,7 @@
|
|
|
619
647
|
console.error("No base url in modal response data so cannot navigate back");
|
|
620
648
|
return;
|
|
621
649
|
}
|
|
650
|
+
baseUrl = null;
|
|
622
651
|
if (!isNavigatingRef.current && typeof window !== "undefined" && window.location.href !== modalOnBase.baseUrl) {
|
|
623
652
|
react.router.visit(modalOnBase.baseUrl, {
|
|
624
653
|
preserveScroll: true,
|
|
@@ -631,17 +660,6 @@
|
|
|
631
660
|
}),
|
|
632
661
|
[]
|
|
633
662
|
);
|
|
634
|
-
const axiosRequestInterceptor = (config) => {
|
|
635
|
-
const baseUrlValue = baseUrl ?? (initialModalStillOpenedRef.current ? $page.props._inertiaui_modal?.baseUrl : null);
|
|
636
|
-
if (baseUrlValue) {
|
|
637
|
-
config.headers["X-InertiaUI-Modal-Base-Url"] = baseUrlValue;
|
|
638
|
-
}
|
|
639
|
-
return config;
|
|
640
|
-
};
|
|
641
|
-
React.useEffect(() => {
|
|
642
|
-
const interceptorId = Axios.interceptors.request.use(axiosRequestInterceptor);
|
|
643
|
-
return () => Axios.interceptors.request.eject(interceptorId);
|
|
644
|
-
}, []);
|
|
645
663
|
const previousModalRef = React.useRef(void 0);
|
|
646
664
|
React.useEffect(() => {
|
|
647
665
|
const newModal = $page.props?._inertiaui_modal;
|