Skip to content

Commit

Permalink
Fix for referring local modal (see #53) (#57)
Browse files Browse the repository at this point in the history
  • Loading branch information
pascalbaljet authored Nov 20, 2024
1 parent 44485be commit e5e33e9
Show file tree
Hide file tree
Showing 9 changed files with 160 additions and 42 deletions.
19 changes: 18 additions & 1 deletion demo-app/resources/js/Pages/Local.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
import { Modal, ModalLink } from '@inertiaui/modal-react';
import Container from './Container';
import { useRef } from 'react';

export default function Local() {
const modalRef = useRef(null);

function closeModal() {
modalRef.current.close();
}

function alertModalId() {
alert(modalRef.current.id);
}

return (
<>
<Container>
Expand All @@ -15,11 +26,17 @@ export default function Local() {
</ModalLink>
</div>
</Container>
<Modal name="local">
<Modal name="local" ref={modalRef}>
This is a local modal
<ModalLink href="/roles/create">
Create Role
</ModalLink>
<button onClick={closeModal}>
Close Modal through Ref
</button>
<button onClick={alertModalId}>
Alert Modal ID
</button>
</Modal>
</>
);
Expand Down
21 changes: 20 additions & 1 deletion demo-app/resources/js/Pages/Local.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
<script setup>
import Container from './Container.vue'
import { Modal, ModalLink } from '@inertiaui/modal-vue'
import { ref } from 'vue';
const modalRef = ref(null);
function closeModal() {
modalRef.value.close();
}
function alertModalId() {
alert(modalRef.value.id);
}
</script>

<template>
Expand All @@ -14,11 +25,19 @@ import { Modal, ModalLink } from '@inertiaui/modal-vue'
</div>
</Container>

<Modal name="local">
<Modal name="local" ref="modalRef">
This is a local modal

<ModalLink href="/roles/create">
Create Role
</ModalLink>

<button @click="closeModal">
Close Modal through Ref
</button>

<button @click="alertModalId">
Alert Modal ID
</button>
</Modal>
</template>
29 changes: 29 additions & 0 deletions demo-app/tests/Browser/LocalModalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,33 @@ public function it_can_open_a_local_modal_and_a_nested_one()
->waitUntilMissingModal(1);
});
}

#[Test]
public function it_can_access_a_prop_through_a_template_ref()
{
$this->browse(function (Browser $browser) {
$browser->visit('/local')
->clickLink('Open Local Modal')
->waitForTextIn('.im-modal-content', 'This is a local modal')
->press('Alert Modal ID');

$message = $browser->driver->switchTo()->alert()->getText();

$this->assertStringStartsWith('inertiaui_modal_', $message);

$browser->dismissDialog();
});
}

#[Test]
public function it_can_close_a_local_modal_through_a_template_ref()
{
$this->browse(function (Browser $browser) {
$browser->visit('/local')
->clickLink('Open Local Modal')
->waitForTextIn('.im-modal-content', 'This is a local modal')
->press('Close Modal through Ref')
->waitUntilMissingModal(1);
});
}
}
2 changes: 1 addition & 1 deletion demo-app/tests/Feature/DispatchBaseUrlRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class DispatchBaseUrlRequestTest extends TestCase
{
protected DispatchBaseUrlRequest $dispatcher;

public function setUp(): void
protected function setUp(): void
{
parent::setUp();

Expand Down
2 changes: 1 addition & 1 deletion demo-app/tests/Feature/RedirectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class RedirectorTest extends TestCase

protected Request $request;

public function setUp(): void
protected function setUp(): void
{
parent::setUp();
$this->urlGenerator = app(UrlGenerator::class);
Expand Down
4 changes: 2 additions & 2 deletions demo-app/tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ abstract class TestCase extends BaseTestCase
use ModalTestCase;
use RefreshDatabase;

public function setUp(): void
protected function setUp(): void
{
parent::setUp();

$this->withoutVite();
Carbon::setTestNow('2024-06-01 12:00:00');
}

public function tearDown(): void
protected function tearDown(): void
{
Carbon::setTestNow();
parent::tearDown();
Expand Down
53 changes: 38 additions & 15 deletions react/src/HeadlessModal.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useMemo, useState, forwardRef, useImperativeHandle, useEffect } from 'react'
import { useMemo, useState, forwardRef, useImperativeHandle, useEffect, useRef } from 'react'
import { getConfig, getConfigByType } from './config'
import { useModalIndex } from './ModalRenderer.jsx'
import { useModalStack } from './ModalRoot.jsx'
Expand Down Expand Up @@ -50,23 +50,46 @@ const HeadlessModal = forwardRef(({ name, children, ...props }, ref) => {
return modalContext.registerEventListenersFromProps(props)
}, [name])

// Store the latest modalContext in a ref to maintain reference
const modalContextRef = useRef(modalContext)

// Update the ref whenever modalContext changes
useEffect(() => {
modalContextRef.current = modalContext
}, [modalContext])

useImperativeHandle(
ref,
() => ({
afterLeave: () => modalContext.afterLeave(),
close: () => modalContext.close(),
config,
emit: (...args) => modalContext.emit(...args),
getChildModal: () => modalContext.getChildModal(),
getParentModal: () => modalContext.getParentModal(),
id: modalContext?.id,
index: modalContext?.index,
isOpen: modalContext?.isOpen,
modalContext,
onTopOfStack: modalContext?.onTopOfStack,
reload: () => modalContext.reload(),
setOpen: () => modalContext.setOpen(),
shouldRender: modalContext?.shouldRender,
afterLeave: () => modalContextRef.current?.afterLeave(),
close: () => modalContextRef.current?.close(),
emit: (...args) => modalContextRef.current?.emit(...args),
getChildModal: () => modalContextRef.current?.getChildModal(),
getParentModal: () => modalContextRef.current?.getParentModal(),
reload: (...args) => modalContextRef.current?.reload(...args),
setOpen: () => modalContextRef.current?.setOpen(),

get id() {
return modalContextRef.current?.id
},
get index() {
return modalContextRef.current?.index
},
get isOpen() {
return modalContextRef.current?.isOpen
},
get config() {
return modalContextRef.current?.config
},
get modalContext() {
return modalContextRef.current
},
get onTopOfStack() {
return modalContextRef.current?.onTopOfStack
},
get shouldRender() {
return modalContextRef.current?.shouldRender
},
}),
[modalContext],
)
Expand Down
41 changes: 28 additions & 13 deletions vue/src/HeadlessModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -92,20 +92,35 @@ function emit(event, ...args) {
}
defineExpose({
afterLeave: modalContext.value.afterLeave,
close: modalContext.value.close,
config: config.value,
emit,
getChildModal: modalContext.value.getChildModal,
getParentModal: modalContext.value.getParentModal,
id: modalContext.value.id,
index: modalContext.value.index,
isOpen: modalContext.value.isOpen,
modalContext: modalContext.value,
onTopOfStack: modalContext.value.onTopOfStack,
reload: modalContext.value.reload,
setOpen: modalContext.value.setOpen,
shouldRender: modalContext.value.shouldRender,
afterLeave: () => modalContext.value?.afterLeave(),
close: () => modalContext.value?.close(),
reload: (...args) => modalContext.value?.reload(...args),
setOpen: (...args) => modalContext.value?.setOpen(...args),
getChildModal: () => modalContext.value?.getChildModal(),
getParentModal: () => modalContext.value?.getParentModal(),
get config() {
return modalContext.value?.config
},
get id() {
return modalContext.value?.id
},
get index() {
return modalContext.value?.index
},
get isOpen() {
return modalContext.value?.isOpen
},
get modalContext() {
return modalContext.value?.modalContext
},
get onTopOfStack() {
return modalContext.value?.onTopOfStack
},
get shouldRender() {
return modalContext.value?.shouldRender
},
})
const nextIndex = computed(() => {
Expand Down
31 changes: 23 additions & 8 deletions vue/src/Modal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,41 @@ import { DialogOverlay, DialogPortal, DialogRoot } from 'radix-vue'
import ModalContent from './ModalContent.vue'
import HeadlessModal from './HeadlessModal.vue'
import SlideoverContent from './SlideoverContent.vue'
import { computed, ref } from 'vue'
import { ref } from 'vue'
const modal = ref(null)
const rendered = ref(false)
defineExpose({
afterLeave: () => modal.value?.afterLeave(),
close: () => modal.value?.close(),
config: computed(() => modal.value?.config),
emit: (...args) => modal.value?.emit(...args),
getChildModal: () => modal.value?.getChildModal(),
getParentModal: () => modal.value?.getParentModal(),
id: computed(() => modal.value?.id),
index: computed(() => modal.value?.index),
isOpen: computed(() => modal.value?.isOpen),
modalContext: computed(() => modal.value?.modalContext),
onTopOfStack: computed(() => modal.value?.onTopOfStack),
reload: (...args) => modal.value?.reload(...args),
setOpen: (...args) => modal.value?.setOpen(...args),
shouldRender: computed(() => modal.value?.shouldRender),
get config() {
return modal.value?.config
},
get id() {
return modal.value?.id
},
get index() {
return modal.value?.index
},
get isOpen() {
return modal.value?.isOpen
},
get modalContext() {
return modal.value?.modalContext
},
get onTopOfStack() {
return modal.value?.onTopOfStack
},
get shouldRender() {
return modal.value?.shouldRender
},
})
</script>
Expand Down

0 comments on commit e5e33e9

Please sign in to comment.