Skip to content

Commit 8225483

Browse files
committed
WIP
1 parent a9cbc87 commit 8225483

File tree

6 files changed

+72
-18
lines changed

6 files changed

+72
-18
lines changed

demo-app/resources/js/app.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ import { createApp, h } from 'vue'
55
import { createInertiaApp } from '@inertiajs/vue3'
66
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'
77
import { ZiggyVue } from '../../vendor/tightenco/ziggy'
8-
import { putConfig } from 'inertiaui/modal'
8+
import { putConfig, ModalRoot } from 'inertiaui/modal'
99

1010
const appName = import.meta.env.VITE_APP_NAME || 'Laravel'
1111

1212
createInertiaApp({
1313
title: (title) => `${title} - ${appName}`,
1414
resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
1515
setup({ el, App, props, plugin }) {
16-
return createApp({ render: () => h(App, props) })
16+
return createApp({ render: () => h(ModalRoot, [h(App, props)]) })
1717
.use(plugin)
1818
.use(ZiggyVue)
1919
.mount(el)

vue/src/ModalLink.vue

+16-14
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,19 @@ onMounted(() => {
102102
103103
const $attrs = useAttrs()
104104
105-
function handleEmittedEvent(event, ...args) {
106-
// // e.g. refresh-key -> onRefreshKey
107-
const kebabEvent = event.replace(/-([a-z])/g, (g) => g[1].toUpperCase())
108-
const listener = `on${kebabEvent.charAt(0).toUpperCase()}${kebabEvent.slice(1)}`
109-
if (listener in $attrs) {
110-
$attrs[listener](...args)
111-
}
105+
function registerEventListeners() {
106+
Object.keys($attrs)
107+
.filter((key) => key.startsWith('on'))
108+
.forEach((key) => {
109+
// e.g. onRefreshKey -> refresh-key
110+
const snakeCaseKey = key
111+
.replace(/^on/, '')
112+
.replace(/^./, (firstLetter) => firstLetter.toLowerCase())
113+
.replace(/([A-Z])/g, '-$1')
114+
.toLowerCase()
115+
116+
modalContext.value.on(snakeCaseKey, $attrs[key])
117+
})
112118
}
113119
114120
watch(modalContext, (value, oldValue) => {
@@ -117,6 +123,9 @@ watch(modalContext, (value, oldValue) => {
117123
window.location.hash = props.fragment
118124
}
119125
126+
// TODO: after unmounting, remove event listeners
127+
registerEventListeners()
128+
120129
nextTick(() => {
121130
modalContext.value.open = true
122131
emit('success')
@@ -168,11 +177,4 @@ function handle() {
168177
>
169178
<slot :loading="loading" />
170179
</component>
171-
172-
<modalContext.component
173-
v-if="modalContext?.component"
174-
v-show="false"
175-
v-bind="modalContext.componentProps"
176-
@emit="handleEmittedEvent"
177-
/>
178180
</template>

vue/src/ModalResolver.vue

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<script setup>
2+
import { useModalStack } from './modalStack'
3+
import { computed, provide } from 'vue'
4+
5+
const props = defineProps({
6+
index: Number,
7+
})
8+
9+
const modalStack = useModalStack()
10+
11+
const modalContext = computed(() => {
12+
return modalStack.stack.value[props.index]
13+
})
14+
15+
provide('modalContext', modalContext)
16+
17+
function handleEmittedEvent(event, ...args) {
18+
modalContext.value.emit(event, ...args)
19+
}
20+
</script>
21+
22+
<template>
23+
<modalContext.component
24+
v-if="modalContext?.component"
25+
v-bind="modalContext.componentProps"
26+
@emit="handleEmittedEvent"
27+
/>
28+
</template>

vue/src/ModalRoot.vue

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<script setup>
2+
import { useModalStack } from './modalStack'
3+
import ModalResolver from './ModalResolver.vue'
4+
5+
const modalStack = useModalStack()
6+
</script>
7+
8+
<template>
9+
<slot />
10+
11+
<ModalResolver
12+
v-if="modalStack.stack.value.length"
13+
:index="0"
14+
/>
15+
</template>

vue/src/ModalWrapper.vue

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
<script setup>
22
import { getConfig, getConfigByType } from './config'
33
import { computed, inject, useAttrs } from 'vue'
4-
import { modalPropNames } from './modalStack'
4+
import { modalPropNames, useModalStack } from './modalStack'
55
import { only } from './helpers'
66
import { TransitionRoot, TransitionChild, Dialog } from '@headlessui/vue'
7+
import ModalResolver from './ModalResolver.vue'
78
89
const props = defineProps({
910
// The slideover prop in on top because we need to know if it's a slideover
@@ -38,6 +39,7 @@ const props = defineProps({
3839
},
3940
})
4041
42+
const modalStack = useModalStack()
4143
const modalContext = inject('modalContext')
4244
const modalProps = computed(() => {
4345
return {
@@ -64,6 +66,7 @@ Object.keys($attrs)
6466
.replace(/([A-Z])/g, '-$1')
6567
.toLowerCase()
6668
69+
// TODO: after unmounting, we need to remove the event listener
6770
modalContext.value.on(snakeCaseKey, $attrs[key])
6871
})
6972
</script>
@@ -113,6 +116,11 @@ Object.keys($attrs)
113116
:modal-context="modalContext"
114117
:modal-props="modalProps"
115118
/>
119+
120+
<ModalResolver
121+
v-if="modalContext && modalStack.stack.value[modalContext?.index + 1]"
122+
:index="modalContext.index + 1"
123+
/>
116124
</Dialog>
117125
</TransitionRoot>
118126
</template>

vue/src/inertiauiModal.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { getConfig, putConfig, resetConfig } from './config.js'
22
import Modal from './Modal.vue'
33
import ModalLink from './ModalLink.vue'
4+
import ModalRoot from './ModalRoot.vue'
45

5-
export { Modal, ModalLink, getConfig, putConfig, resetConfig }
6+
export { Modal, ModalLink, ModalRoot, getConfig, putConfig, resetConfig }

0 commit comments

Comments
 (0)