@inertiaui/modal-react 1.0.0-beta-4 → 2.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CloseButton.d.ts +5 -0
- package/dist/Deferred.d.ts +11 -0
- package/dist/HeadlessModal.d.ts +64 -0
- package/dist/Modal.d.ts +48 -0
- package/dist/ModalContent.d.ts +24 -0
- package/dist/ModalLink.d.ts +29 -0
- package/dist/ModalRenderer.d.ts +4 -0
- package/dist/ModalRoot.d.ts +22 -0
- package/dist/SlideoverContent.d.ts +24 -0
- package/dist/WhenVisible.d.ts +16 -0
- package/dist/config.d.ts +21 -0
- package/dist/constants.d.ts +7 -0
- package/dist/helpers.d.ts +3 -0
- package/dist/inertiaui-modal.d.ts +2 -0
- package/dist/inertiaui-modal.js +1680 -2147
- package/dist/inertiaui-modal.js.map +1 -0
- package/dist/inertiaui-modal.umd.cjs +1854 -21
- package/dist/inertiaui-modal.umd.cjs.map +1 -0
- package/dist/inertiauiModal.d.ts +21 -0
- package/dist/types.d.ts +111 -0
- package/dist/useModal.d.ts +2 -0
- package/package.json +33 -23
- package/src/{CloseButton.jsx → CloseButton.tsx} +5 -1
- package/src/{Deferred.jsx → Deferred.tsx} +10 -3
- package/src/HeadlessModal.tsx +238 -0
- package/src/Modal.tsx +292 -0
- package/src/ModalContent.tsx +311 -0
- package/src/ModalLink.tsx +224 -0
- package/src/ModalRenderer.tsx +33 -0
- package/src/ModalRoot.tsx +880 -0
- package/src/SlideoverContent.tsx +319 -0
- package/src/{WhenVisible.jsx → WhenVisible.tsx} +20 -9
- package/src/config.ts +99 -0
- package/src/constants.ts +22 -0
- package/src/helpers.ts +17 -0
- package/src/inertiauiModal.ts +65 -0
- package/src/types.ts +150 -0
- package/src/useModal.ts +7 -0
- package/src/HeadlessModal.jsx +0 -143
- package/src/Modal.jsx +0 -136
- package/src/ModalContent.jsx +0 -56
- package/src/ModalLink.jsx +0 -123
- package/src/ModalRenderer.jsx +0 -34
- package/src/ModalRoot.jsx +0 -625
- package/src/SlideoverContent.jsx +0 -55
- package/src/config.js +0 -3
- package/src/helpers.js +0 -2
- package/src/inertiauiModal.js +0 -34
- package/src/useModal.js +0 -6
package/src/ModalRoot.jsx
DELETED
|
@@ -1,625 +0,0 @@
|
|
|
1
|
-
import { createElement, useEffect, useState, useRef } from 'react'
|
|
2
|
-
import { default as Axios } from 'axios'
|
|
3
|
-
import { except, kebabCase, generateId, sameUrlPath } from './helpers'
|
|
4
|
-
import { router, usePage } from '@inertiajs/react'
|
|
5
|
-
import * as InertiaReact from '@inertiajs/react'
|
|
6
|
-
import { mergeDataIntoQueryString } from '@inertiajs/core'
|
|
7
|
-
import { createContext, useContext } from 'react'
|
|
8
|
-
import ModalRenderer from './ModalRenderer'
|
|
9
|
-
import { getConfig } from './config'
|
|
10
|
-
|
|
11
|
-
const ModalStackContext = createContext(null)
|
|
12
|
-
ModalStackContext.displayName = 'ModalStackContext'
|
|
13
|
-
|
|
14
|
-
let pageVersion = null
|
|
15
|
-
let resolveComponent = null
|
|
16
|
-
let baseUrl = null
|
|
17
|
-
let baseModalsToWaitFor = {}
|
|
18
|
-
let localStackCopy = []
|
|
19
|
-
let pendingModalUpdates = {}
|
|
20
|
-
|
|
21
|
-
export const ModalStackProvider = ({ children }) => {
|
|
22
|
-
const [stack, setStack] = useState([])
|
|
23
|
-
const [localModals, setLocalModals] = useState({})
|
|
24
|
-
|
|
25
|
-
const updateStack = (withStack) => {
|
|
26
|
-
setStack((prevStack) => {
|
|
27
|
-
const newStack = withStack([...prevStack])
|
|
28
|
-
|
|
29
|
-
const isOnTopOfStack = (modalId) => {
|
|
30
|
-
if (newStack.length < 2) {
|
|
31
|
-
return true
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
newStack
|
|
36
|
-
.map((modal) => ({ id: modal.id, shouldRender: modal.shouldRender }))
|
|
37
|
-
.reverse()
|
|
38
|
-
.find((modal) => modal.shouldRender)?.id === modalId
|
|
39
|
-
)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
newStack.forEach((modal, index) => {
|
|
43
|
-
newStack[index].onTopOfStack = isOnTopOfStack(modal.id)
|
|
44
|
-
newStack[index].getParentModal = () => {
|
|
45
|
-
if (index < 1) {
|
|
46
|
-
// This is the first modal in the stack
|
|
47
|
-
return null
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Find the first open modal before this one
|
|
51
|
-
return newStack
|
|
52
|
-
.slice(0, index)
|
|
53
|
-
.reverse()
|
|
54
|
-
.find((modal) => modal.isOpen)
|
|
55
|
-
}
|
|
56
|
-
newStack[index].getChildModal = () => {
|
|
57
|
-
if (index === newStack.length - 1) {
|
|
58
|
-
// This is the last modal in the stack
|
|
59
|
-
return null
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Find the first open modal after this one
|
|
63
|
-
return newStack.slice(index + 1).find((modal) => modal.isOpen)
|
|
64
|
-
}
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
return newStack
|
|
68
|
-
})
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
useEffect(() => {
|
|
72
|
-
localStackCopy = stack
|
|
73
|
-
}, [stack])
|
|
74
|
-
|
|
75
|
-
class Modal {
|
|
76
|
-
constructor(component, response, config, onClose, afterLeave) {
|
|
77
|
-
this.id = response.id ?? generateId()
|
|
78
|
-
this.isOpen = false
|
|
79
|
-
this.shouldRender = false
|
|
80
|
-
this.listeners = {}
|
|
81
|
-
|
|
82
|
-
this.component = component
|
|
83
|
-
this.props = response.props
|
|
84
|
-
this.response = response
|
|
85
|
-
this.config = config ?? {}
|
|
86
|
-
this.onCloseCallback = onClose
|
|
87
|
-
this.afterLeaveCallback = afterLeave
|
|
88
|
-
|
|
89
|
-
if (pendingModalUpdates[this.id]) {
|
|
90
|
-
this.config = {
|
|
91
|
-
...this.config,
|
|
92
|
-
...(pendingModalUpdates[this.id].config ?? {}),
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const pendingOnClose = pendingModalUpdates[this.id].onClose
|
|
96
|
-
const pendingOnAfterLeave = pendingModalUpdates[this.id].onAfterLeave
|
|
97
|
-
|
|
98
|
-
if (pendingOnClose) {
|
|
99
|
-
this.onCloseCallback = onClose
|
|
100
|
-
? () => {
|
|
101
|
-
onClose()
|
|
102
|
-
pendingOnClose()
|
|
103
|
-
}
|
|
104
|
-
: pendingOnClose
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (pendingOnAfterLeave) {
|
|
108
|
-
this.afterLeaveCallback = afterLeave
|
|
109
|
-
? () => {
|
|
110
|
-
afterLeave()
|
|
111
|
-
pendingOnAfterLeave()
|
|
112
|
-
}
|
|
113
|
-
: pendingOnAfterLeave
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
delete pendingModalUpdates[this.id]
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
this.index = -1 // Will be set when added to the stack
|
|
120
|
-
this.getParentModal = () => null // Will be set in push()
|
|
121
|
-
this.getChildModal = () => null // Will be set in push()
|
|
122
|
-
this.onTopOfStack = true // Will be updated in push()
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
static generateId() {
|
|
126
|
-
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
|
|
127
|
-
return `inertiaui_modal_${crypto.randomUUID()}`
|
|
128
|
-
}
|
|
129
|
-
// Fallback for environments where crypto.randomUUID is not available
|
|
130
|
-
return `inertiaui_modal_${Date.now().toString(36)}_${Math.random().toString(36).substr(2, 9)}`
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
show = () => {
|
|
134
|
-
updateStack((prevStack) =>
|
|
135
|
-
prevStack.map((modal) => {
|
|
136
|
-
if (modal.id === this.id && !modal.isOpen) {
|
|
137
|
-
modal.isOpen = true
|
|
138
|
-
modal.shouldRender = true
|
|
139
|
-
}
|
|
140
|
-
return modal
|
|
141
|
-
}),
|
|
142
|
-
)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
setOpen = (open) => {
|
|
146
|
-
open ? this.show() : this.close()
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
close = () => {
|
|
150
|
-
updateStack((currentStack) => {
|
|
151
|
-
let modalClosed = false
|
|
152
|
-
|
|
153
|
-
const newStack = currentStack.map((modal) => {
|
|
154
|
-
if (modal.id === this.id && modal.isOpen) {
|
|
155
|
-
Object.keys(modal.listeners).forEach((event) => {
|
|
156
|
-
modal.off(event)
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
modal.isOpen = false
|
|
160
|
-
modal.onCloseCallback?.()
|
|
161
|
-
modalClosed = true
|
|
162
|
-
}
|
|
163
|
-
return modal
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
return modalClosed ? newStack : currentStack
|
|
167
|
-
})
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
afterLeave = () => {
|
|
171
|
-
if (this.isOpen) {
|
|
172
|
-
return
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
updateStack((prevStack) => {
|
|
176
|
-
const updatedStack = prevStack.map((modal) => {
|
|
177
|
-
if (modal.id === this.id && !modal.isOpen) {
|
|
178
|
-
modal.shouldRender = false
|
|
179
|
-
modal.afterLeaveCallback?.()
|
|
180
|
-
modal.afterLeaveCallback = null
|
|
181
|
-
}
|
|
182
|
-
return modal
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
return this.index === 0 ? [] : updatedStack
|
|
186
|
-
})
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
on = (event, callback) => {
|
|
190
|
-
event = kebabCase(event)
|
|
191
|
-
this.listeners[event] = this.listeners[event] ?? []
|
|
192
|
-
this.listeners[event].push(callback)
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
off = (event, callback) => {
|
|
196
|
-
event = kebabCase(event)
|
|
197
|
-
if (callback) {
|
|
198
|
-
this.listeners[event] = this.listeners[event]?.filter((cb) => cb !== callback) ?? []
|
|
199
|
-
} else {
|
|
200
|
-
delete this.listeners[event]
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
emit = (event, ...args) => {
|
|
205
|
-
this.listeners[kebabCase(event)]?.forEach((callback) => callback(...args))
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
registerEventListenersFromProps = (props) => {
|
|
209
|
-
const unsubscribers = []
|
|
210
|
-
|
|
211
|
-
Object.keys(props)
|
|
212
|
-
.filter((key) => key.startsWith('on'))
|
|
213
|
-
.forEach((key) => {
|
|
214
|
-
// e.g. onRefreshKey -> refresh-key
|
|
215
|
-
const eventName = kebabCase(key).replace(/^on-/, '')
|
|
216
|
-
this.on(eventName, props[key])
|
|
217
|
-
unsubscribers.push(() => this.off(eventName, props[key]))
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
return () => unsubscribers.forEach((unsub) => unsub())
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
reload = (options = {}) => {
|
|
224
|
-
let keys = Object.keys(this.response.props)
|
|
225
|
-
|
|
226
|
-
if (options.only) {
|
|
227
|
-
keys = options.only
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (options.except) {
|
|
231
|
-
keys = except(keys, options.except)
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
if (!this.response?.url) {
|
|
235
|
-
return
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const method = (options.method ?? 'get').toLowerCase()
|
|
239
|
-
const data = options.data ?? {}
|
|
240
|
-
|
|
241
|
-
options.onStart?.()
|
|
242
|
-
|
|
243
|
-
Axios({
|
|
244
|
-
url: this.response.url,
|
|
245
|
-
method,
|
|
246
|
-
data: method === 'get' ? {} : data,
|
|
247
|
-
params: method === 'get' ? data : {},
|
|
248
|
-
headers: {
|
|
249
|
-
...(options.headers ?? {}),
|
|
250
|
-
Accept: 'text/html, application/xhtml+xml',
|
|
251
|
-
'X-Inertia': true,
|
|
252
|
-
'X-Inertia-Partial-Component': this.response.component,
|
|
253
|
-
'X-Inertia-Version': this.response.version,
|
|
254
|
-
'X-Inertia-Partial-Data': keys.join(','),
|
|
255
|
-
'X-InertiaUI-Modal': generateId(),
|
|
256
|
-
'X-InertiaUI-Modal-Use-Router': 0,
|
|
257
|
-
'X-InertiaUI-Modal-Base-Url': baseUrl,
|
|
258
|
-
},
|
|
259
|
-
})
|
|
260
|
-
.then((response) => {
|
|
261
|
-
this.updateProps(response.data.props)
|
|
262
|
-
|
|
263
|
-
options.onSuccess?.(response)
|
|
264
|
-
})
|
|
265
|
-
.catch((error) => {
|
|
266
|
-
options.onError?.(error)
|
|
267
|
-
})
|
|
268
|
-
.finally(() => {
|
|
269
|
-
options.onFinish?.()
|
|
270
|
-
})
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
updateProps = (props) => {
|
|
274
|
-
Object.assign(this.props, props)
|
|
275
|
-
updateStack((prevStack) => prevStack) // Trigger re-render
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
const pushFromResponseData = (responseData, config = {}, onClose = null, onAfterLeave = null) => {
|
|
280
|
-
return resolveComponent(responseData.component).then((component) => push(component, responseData, config, onClose, onAfterLeave))
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
const loadDeferredProps = (modal) => {
|
|
284
|
-
const deferred = modal.response?.meta?.deferredProps
|
|
285
|
-
|
|
286
|
-
if (!deferred) {
|
|
287
|
-
return
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
Object.keys(deferred).forEach((key) => {
|
|
291
|
-
modal.reload({ only: deferred[key] })
|
|
292
|
-
})
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
const push = (component, response, config, onClose, afterLeave) => {
|
|
296
|
-
const newModal = new Modal(component, response, config, onClose, afterLeave)
|
|
297
|
-
newModal.index = stack.length
|
|
298
|
-
|
|
299
|
-
updateStack((prevStack) => [...prevStack, newModal])
|
|
300
|
-
loadDeferredProps(newModal)
|
|
301
|
-
|
|
302
|
-
newModal.show()
|
|
303
|
-
|
|
304
|
-
return newModal
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
function pushLocalModal(name, config, onClose, afterLeave) {
|
|
308
|
-
if (!localModals[name]) {
|
|
309
|
-
throw new Error(`The local modal "${name}" has not been registered.`)
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
const modal = push(null, {}, config, onClose, afterLeave)
|
|
313
|
-
modal.name = name
|
|
314
|
-
localModals[name].callback(modal)
|
|
315
|
-
return modal
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
const visitModal = (url, options = {}) =>
|
|
319
|
-
visit(
|
|
320
|
-
url,
|
|
321
|
-
options.method ?? 'get',
|
|
322
|
-
options.data ?? {},
|
|
323
|
-
options.headers ?? {},
|
|
324
|
-
options.config ?? {},
|
|
325
|
-
options.onClose,
|
|
326
|
-
options.onAfterLeave,
|
|
327
|
-
options.queryStringArrayFormat ?? 'brackets',
|
|
328
|
-
options.navigate ?? getConfig('navigate'),
|
|
329
|
-
options.onStart,
|
|
330
|
-
options.onSuccess,
|
|
331
|
-
options.onError,
|
|
332
|
-
).then((modal) => {
|
|
333
|
-
const listeners = options.listeners ?? {}
|
|
334
|
-
|
|
335
|
-
Object.keys(listeners).forEach((event) => {
|
|
336
|
-
// e.g. refreshKey -> refresh-key
|
|
337
|
-
const eventName = kebabCase(event)
|
|
338
|
-
modal.on(eventName, listeners[event])
|
|
339
|
-
})
|
|
340
|
-
|
|
341
|
-
return modal
|
|
342
|
-
})
|
|
343
|
-
|
|
344
|
-
const visit = (
|
|
345
|
-
href,
|
|
346
|
-
method,
|
|
347
|
-
payload = {},
|
|
348
|
-
headers = {},
|
|
349
|
-
config = {},
|
|
350
|
-
onClose = null,
|
|
351
|
-
onAfterLeave = null,
|
|
352
|
-
queryStringArrayFormat = 'brackets',
|
|
353
|
-
useBrowserHistory = false,
|
|
354
|
-
onStart = null,
|
|
355
|
-
onSuccess = null,
|
|
356
|
-
onError = null,
|
|
357
|
-
) => {
|
|
358
|
-
const modalId = generateId()
|
|
359
|
-
|
|
360
|
-
return new Promise((resolve, reject) => {
|
|
361
|
-
if (href.startsWith('#')) {
|
|
362
|
-
resolve(pushLocalModal(href.substring(1), config, onClose, onAfterLeave))
|
|
363
|
-
return
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
const [url, data] = mergeDataIntoQueryString(method, href || '', payload, queryStringArrayFormat)
|
|
367
|
-
|
|
368
|
-
let useInertiaRouter = useBrowserHistory && stack.length === 0
|
|
369
|
-
|
|
370
|
-
if (stack.length === 0) {
|
|
371
|
-
baseUrl = typeof window !== 'undefined' ? window.location.href : ''
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
headers = {
|
|
375
|
-
...headers,
|
|
376
|
-
Accept: 'text/html, application/xhtml+xml',
|
|
377
|
-
'X-Requested-With': 'XMLHttpRequest',
|
|
378
|
-
'X-Inertia': true,
|
|
379
|
-
'X-Inertia-Version': pageVersion,
|
|
380
|
-
'X-InertiaUI-Modal': modalId,
|
|
381
|
-
'X-InertiaUI-Modal-Use-Router': useInertiaRouter ? 1 : 0,
|
|
382
|
-
'X-InertiaUI-Modal-Base-Url': baseUrl,
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
if (useInertiaRouter) {
|
|
386
|
-
baseModalsToWaitFor = {}
|
|
387
|
-
|
|
388
|
-
pendingModalUpdates[modalId] = {
|
|
389
|
-
config,
|
|
390
|
-
onClose,
|
|
391
|
-
onAfterLeave,
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
// Pushing the modal to the stack will be handled by the ModalRoot...
|
|
395
|
-
return router.visit(url, {
|
|
396
|
-
method,
|
|
397
|
-
data,
|
|
398
|
-
headers,
|
|
399
|
-
preserveScroll: true,
|
|
400
|
-
preserveState: true,
|
|
401
|
-
onError(...args) {
|
|
402
|
-
onError?.(...args)
|
|
403
|
-
reject(...args)
|
|
404
|
-
},
|
|
405
|
-
onStart(...args) {
|
|
406
|
-
onStart?.(...args)
|
|
407
|
-
},
|
|
408
|
-
onSuccess(...args) {
|
|
409
|
-
onSuccess?.(...args)
|
|
410
|
-
},
|
|
411
|
-
onBefore: () => {
|
|
412
|
-
baseModalsToWaitFor[modalId] = resolve
|
|
413
|
-
},
|
|
414
|
-
})
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
onStart?.()
|
|
418
|
-
|
|
419
|
-
const withProgress = (callback) => {
|
|
420
|
-
try {
|
|
421
|
-
InertiaReact.progress ? callback(InertiaReact.progress) : null
|
|
422
|
-
} catch (e) {
|
|
423
|
-
// ignore
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
withProgress((progress) => progress.start())
|
|
428
|
-
|
|
429
|
-
Axios({
|
|
430
|
-
url,
|
|
431
|
-
method,
|
|
432
|
-
data,
|
|
433
|
-
headers,
|
|
434
|
-
})
|
|
435
|
-
.then((response) => {
|
|
436
|
-
onSuccess?.(response)
|
|
437
|
-
resolve(pushFromResponseData(response.data, config, onClose, onAfterLeave))
|
|
438
|
-
})
|
|
439
|
-
.catch((...args) => {
|
|
440
|
-
onError?.(...args)
|
|
441
|
-
reject(...args)
|
|
442
|
-
})
|
|
443
|
-
.finally(() => {
|
|
444
|
-
withProgress((progress) => progress.finish())
|
|
445
|
-
})
|
|
446
|
-
})
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
const registerLocalModal = (name, callback) => {
|
|
450
|
-
setLocalModals((prevLocalModals) => ({
|
|
451
|
-
...prevLocalModals,
|
|
452
|
-
[name]: { name, callback },
|
|
453
|
-
}))
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
const removeLocalModal = (name) => {
|
|
457
|
-
setLocalModals((prevLocalModals) => {
|
|
458
|
-
const newLocalModals = { ...prevLocalModals }
|
|
459
|
-
delete newLocalModals[name]
|
|
460
|
-
return newLocalModals
|
|
461
|
-
})
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
const value = {
|
|
465
|
-
stack,
|
|
466
|
-
localModals,
|
|
467
|
-
push,
|
|
468
|
-
pushFromResponseData,
|
|
469
|
-
length: () => localStackCopy.length,
|
|
470
|
-
closeAll: () => {
|
|
471
|
-
localStackCopy.reverse().forEach((modal) => modal.close())
|
|
472
|
-
},
|
|
473
|
-
reset: () => updateStack(() => []),
|
|
474
|
-
visit,
|
|
475
|
-
visitModal,
|
|
476
|
-
registerLocalModal,
|
|
477
|
-
removeLocalModal,
|
|
478
|
-
onModalOnBase: (modalOnBase) => {
|
|
479
|
-
const resolve = baseModalsToWaitFor[modalOnBase.id]
|
|
480
|
-
|
|
481
|
-
if (resolve) {
|
|
482
|
-
resolve(modalOnBase)
|
|
483
|
-
delete baseModalsToWaitFor[modalOnBase.id]
|
|
484
|
-
}
|
|
485
|
-
},
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
return <ModalStackContext.Provider value={value}>{children}</ModalStackContext.Provider>
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
export const useModalStack = () => {
|
|
492
|
-
const context = useContext(ModalStackContext)
|
|
493
|
-
if (context === null) {
|
|
494
|
-
throw new Error('useModalStack must be used within a ModalStackProvider')
|
|
495
|
-
}
|
|
496
|
-
return context
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
export const modalPropNames = ['closeButton', 'closeExplicitly', 'maxWidth', 'paddingClasses', 'panelClasses', 'position', 'slideover']
|
|
500
|
-
|
|
501
|
-
export const initFromPageProps = (pageProps) => {
|
|
502
|
-
if (pageProps.initialPage) {
|
|
503
|
-
pageVersion = pageProps.initialPage.version
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
if (pageProps.resolveComponent) {
|
|
507
|
-
resolveComponent = pageProps.resolveComponent
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
export const renderApp = (App, pageProps) => {
|
|
512
|
-
initFromPageProps(pageProps)
|
|
513
|
-
|
|
514
|
-
const renderInertiaApp = ({ Component, props, key }) => {
|
|
515
|
-
const renderComponent = () => {
|
|
516
|
-
const child = createElement(Component, { key, ...props })
|
|
517
|
-
|
|
518
|
-
if (typeof Component.layout === 'function') {
|
|
519
|
-
return Component.layout(child)
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
if (Array.isArray(Component.layout)) {
|
|
523
|
-
const layouts = Component.layout
|
|
524
|
-
.concat(child)
|
|
525
|
-
.reverse()
|
|
526
|
-
.reduce((children, Layout) => createElement(Layout, props, children))
|
|
527
|
-
|
|
528
|
-
return layouts
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
return child
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
return (
|
|
535
|
-
<>
|
|
536
|
-
{renderComponent()}
|
|
537
|
-
<ModalRoot />
|
|
538
|
-
</>
|
|
539
|
-
)
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
return (
|
|
543
|
-
<ModalStackProvider>
|
|
544
|
-
<App {...pageProps}>{renderInertiaApp}</App>
|
|
545
|
-
</ModalStackProvider>
|
|
546
|
-
)
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
export const ModalRoot = ({ children }) => {
|
|
550
|
-
const context = useContext(ModalStackContext)
|
|
551
|
-
const $page = usePage()
|
|
552
|
-
|
|
553
|
-
let isNavigating = false
|
|
554
|
-
let previousModalOnBase = false
|
|
555
|
-
let initialModalStillOpened = $page.props?._inertiaui_modal ? true : false
|
|
556
|
-
|
|
557
|
-
useEffect(() => router.on('start', () => (isNavigating = true)), [])
|
|
558
|
-
useEffect(() => router.on('finish', () => (isNavigating = false)), [])
|
|
559
|
-
useEffect(
|
|
560
|
-
() =>
|
|
561
|
-
router.on('navigate', function ($event) {
|
|
562
|
-
const modalOnBase = $event.detail.page.props._inertiaui_modal
|
|
563
|
-
|
|
564
|
-
if (!modalOnBase) {
|
|
565
|
-
previousModalOnBase && context.closeAll()
|
|
566
|
-
baseUrl = null
|
|
567
|
-
initialModalStillOpened = false
|
|
568
|
-
return
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
previousModalOnBase = modalOnBase
|
|
572
|
-
baseUrl = modalOnBase.baseUrl
|
|
573
|
-
|
|
574
|
-
context
|
|
575
|
-
.pushFromResponseData(modalOnBase, {}, () => {
|
|
576
|
-
if (!modalOnBase.baseUrl) {
|
|
577
|
-
console.error('No base url in modal response data so cannot navigate back')
|
|
578
|
-
return
|
|
579
|
-
}
|
|
580
|
-
if (!isNavigating && typeof window !== 'undefined' && window.location.href !== modalOnBase.baseUrl) {
|
|
581
|
-
router.visit(modalOnBase.baseUrl, {
|
|
582
|
-
preserveScroll: true,
|
|
583
|
-
preserveState: true,
|
|
584
|
-
})
|
|
585
|
-
}
|
|
586
|
-
})
|
|
587
|
-
.then(context.onModalOnBase)
|
|
588
|
-
}),
|
|
589
|
-
[],
|
|
590
|
-
)
|
|
591
|
-
|
|
592
|
-
const axiosRequestInterceptor = (config) => {
|
|
593
|
-
// A Modal is opened on top of a base route, so we need to pass this base route
|
|
594
|
-
// so it can redirect back with the back() helper method...
|
|
595
|
-
config.headers['X-InertiaUI-Modal-Base-Url'] = baseUrl ?? (initialModalStillOpened ? $page.props._inertiaui_modal?.baseUrl : null)
|
|
596
|
-
|
|
597
|
-
return config
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
useEffect(() => {
|
|
601
|
-
Axios.interceptors.request.use(axiosRequestInterceptor)
|
|
602
|
-
return () => Axios.interceptors.request.eject(axiosRequestInterceptor)
|
|
603
|
-
}, [])
|
|
604
|
-
|
|
605
|
-
const previousModalRef = useRef()
|
|
606
|
-
|
|
607
|
-
useEffect(() => {
|
|
608
|
-
const newModal = $page.props?._inertiaui_modal
|
|
609
|
-
const previousModal = previousModalRef.current
|
|
610
|
-
|
|
611
|
-
// Store the current value for the next render
|
|
612
|
-
previousModalRef.current = newModal
|
|
613
|
-
|
|
614
|
-
if (newModal && previousModal && newModal.component === previousModal.component && sameUrlPath(newModal.url, previousModal.url)) {
|
|
615
|
-
context.stack[0]?.updateProps(newModal.props ?? {})
|
|
616
|
-
}
|
|
617
|
-
}, [$page.props?._inertiaui_modal])
|
|
618
|
-
|
|
619
|
-
return (
|
|
620
|
-
<>
|
|
621
|
-
{children}
|
|
622
|
-
{context.stack.length > 0 && <ModalRenderer index={0} />}
|
|
623
|
-
</>
|
|
624
|
-
)
|
|
625
|
-
}
|
package/src/SlideoverContent.jsx
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { TransitionChild, DialogPanel } from '@headlessui/react'
|
|
2
|
-
import CloseButton from './CloseButton'
|
|
3
|
-
import clsx from 'clsx'
|
|
4
|
-
import { useState } from 'react'
|
|
5
|
-
|
|
6
|
-
const SlideoverContent = ({ modalContext, config, children }) => {
|
|
7
|
-
const [entered, setEntered] = useState(false)
|
|
8
|
-
|
|
9
|
-
return (
|
|
10
|
-
<div className="im-slideover-container fixed inset-0 z-40 overflow-y-auto overflow-x-hidden">
|
|
11
|
-
<div
|
|
12
|
-
className={clsx('im-slideover-positioner flex min-h-full items-center', {
|
|
13
|
-
'justify-start rtl:justify-end': config?.position === 'left',
|
|
14
|
-
'justify-end rtl:justify-start': config?.position === 'right',
|
|
15
|
-
})}
|
|
16
|
-
>
|
|
17
|
-
<TransitionChild
|
|
18
|
-
as="div"
|
|
19
|
-
enterFrom={`opacity-0 ${config.position === 'left' ? '-translate-x-full' : 'translate-x-full'}`}
|
|
20
|
-
enterTo="opacity-100 translate-x-0"
|
|
21
|
-
leaveFrom="opacity-100 translate-x-0"
|
|
22
|
-
leaveTo={`opacity-0 ${config.position === 'left' ? '-translate-x-full' : 'translate-x-full'}`}
|
|
23
|
-
afterEnter={() => setEntered(true)}
|
|
24
|
-
afterLeave={modalContext.afterLeave}
|
|
25
|
-
className={clsx('im-slideover-wrapper w-full transition duration-300 ease-in-out', modalContext.onTopOfStack ? '' : 'blur-sm', {
|
|
26
|
-
'sm:max-w-sm': config.maxWidth === 'sm',
|
|
27
|
-
'sm:max-w-md': config.maxWidth === 'md',
|
|
28
|
-
'sm:max-w-md md:max-w-lg': config.maxWidth === 'lg',
|
|
29
|
-
'sm:max-w-md md:max-w-xl': config.maxWidth === 'xl',
|
|
30
|
-
'sm:max-w-md md:max-w-xl lg:max-w-2xl': config.maxWidth === '2xl',
|
|
31
|
-
'sm:max-w-md md:max-w-xl lg:max-w-3xl': config.maxWidth === '3xl',
|
|
32
|
-
'sm:max-w-md md:max-w-xl lg:max-w-3xl xl:max-w-4xl': config.maxWidth === '4xl',
|
|
33
|
-
'sm:max-w-md md:max-w-xl lg:max-w-3xl xl:max-w-5xl': config.maxWidth === '5xl',
|
|
34
|
-
'sm:max-w-md md:max-w-xl lg:max-w-3xl xl:max-w-5xl 2xl:max-w-6xl': config.maxWidth === '6xl',
|
|
35
|
-
'sm:max-w-md md:max-w-xl lg:max-w-3xl xl:max-w-5xl 2xl:max-w-7xl': config.maxWidth === '7xl',
|
|
36
|
-
})}
|
|
37
|
-
>
|
|
38
|
-
<DialogPanel
|
|
39
|
-
className={`im-slideover-content relative ${config.paddingClasses} ${config.panelClasses}`}
|
|
40
|
-
data-inertiaui-modal-entered={entered}
|
|
41
|
-
>
|
|
42
|
-
{config.closeButton && (
|
|
43
|
-
<div className="absolute right-0 top-0 pr-3 pt-3">
|
|
44
|
-
<CloseButton onClick={modalContext.close} />
|
|
45
|
-
</div>
|
|
46
|
-
)}
|
|
47
|
-
{typeof children === 'function' ? children({ modalContext, config }) : children}
|
|
48
|
-
</DialogPanel>
|
|
49
|
-
</TransitionChild>
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export default SlideoverContent
|
package/src/config.js
DELETED
package/src/helpers.js
DELETED