From 480367a1bab9a077bb06c5fab5c0e9ecb0b5c6fc Mon Sep 17 00:00:00 2001 From: Pascal Baljet Date: Wed, 20 Nov 2024 22:43:15 +0100 Subject: [PATCH] Refactor --- demo-app/resources/js/Pages/Local.jsx | 7 +++ demo-app/resources/js/Pages/Local.vue | 8 ++++ demo-app/tests/Browser/LocalModalTest.php | 17 +++++++ react/src/HeadlessModal.jsx | 57 ++++++++++++++++------- vue/src/HeadlessModal.vue | 35 ++++++++++---- vue/src/Modal.vue | 31 ++++++++---- 6 files changed, 119 insertions(+), 36 deletions(-) diff --git a/demo-app/resources/js/Pages/Local.jsx b/demo-app/resources/js/Pages/Local.jsx index 73c23cd..df72e62 100644 --- a/demo-app/resources/js/Pages/Local.jsx +++ b/demo-app/resources/js/Pages/Local.jsx @@ -9,6 +9,10 @@ export default function Local() { modalRef.current.close(); } + function alertModalId() { + alert(modalRef.current.id); + } + return ( <> @@ -30,6 +34,9 @@ export default function Local() { + ); diff --git a/demo-app/resources/js/Pages/Local.vue b/demo-app/resources/js/Pages/Local.vue index feee565..dc6f1ab 100644 --- a/demo-app/resources/js/Pages/Local.vue +++ b/demo-app/resources/js/Pages/Local.vue @@ -8,6 +8,10 @@ const modalRef = ref(null); function closeModal() { modalRef.value.close(); } + +function alertModalId() { + alert(modalRef.value.id); +} diff --git a/demo-app/tests/Browser/LocalModalTest.php b/demo-app/tests/Browser/LocalModalTest.php index 2e8c0c8..c22265c 100644 --- a/demo-app/tests/Browser/LocalModalTest.php +++ b/demo-app/tests/Browser/LocalModalTest.php @@ -21,6 +21,23 @@ public function it_can_open_a_local_modal_and_a_nested_one() }); } + #[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() { diff --git a/react/src/HeadlessModal.jsx b/react/src/HeadlessModal.jsx index 9109a1b..dab2cce 100644 --- a/react/src/HeadlessModal.jsx +++ b/react/src/HeadlessModal.jsx @@ -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' @@ -9,7 +9,6 @@ const HeadlessModal = forwardRef(({ name, children, ...props }, ref) => { const { stack, registerLocalModal, removeLocalModal } = useModalStack() const [localModalContext, setLocalModalContext] = useState(null) - let modalContextCopy = name ? localModalContext : stack[modalIndex] const modalContext = useMemo(() => (name ? localModalContext : stack[modalIndex]), [name, localModalContext, modalIndex, stack]) const nextIndex = useMemo(() => { @@ -39,7 +38,6 @@ const HeadlessModal = forwardRef(({ name, children, ...props }, ref) => { registerLocalModal(name, (localContext) => { removeListeners = localContext.registerEventListenersFromProps(props) setLocalModalContext(localContext) - modalContextCopy = localContext }) return () => { @@ -52,25 +50,48 @@ 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: () => modalContextCopy.afterLeave(), - close: () => modalContextCopy.close(), - config, - emit: (...args) => modalContextCopy.emit(...args), - getChildModal: () => modalContextCopy.getChildModal(), - getParentModal: () => modalContextCopy.getParentModal(), - id: modalContextCopy?.id, - index: modalContextCopy?.index, - isOpen: modalContextCopy?.isOpen, - modalContext: modalContextCopy, - onTopOfStack: modalContextCopy?.onTopOfStack, - reload: () => modalContextCopy.reload(), - setOpen: () => modalContextCopy.setOpen(), - shouldRender: modalContextCopy?.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 + }, }), - [modalContextCopy], + [modalContext], ) return ( diff --git a/vue/src/HeadlessModal.vue b/vue/src/HeadlessModal.vue index 2b49d9e..a74e85e 100644 --- a/vue/src/HeadlessModal.vue +++ b/vue/src/HeadlessModal.vue @@ -92,20 +92,35 @@ function emit(event, ...args) { } defineExpose({ + emit, afterLeave: () => modalContext.value?.afterLeave(), close: () => modalContext.value?.close(), - config: computed(() => modalContext.value?.config), - emit, - getChildModal: () => modalContext.value?.getChildModal(), - getParentModal: () => modalContext.value?.getParentModal(), - id: computed(() => modalContext.value?.id), - index: computed(() => modalContext.value?.index), - isOpen: computed(() => modalContext.value?.isOpen), - modalContext: computed(() => modalContext.value?.modalContext), - onTopOfStack: computed(() => modalContext.value?.onTopOfStack), reload: (...args) => modalContext.value?.reload(...args), setOpen: (...args) => modalContext.value?.setOpen(...args), - shouldRender: computed(() => modalContext.value?.shouldRender), + 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(() => { diff --git a/vue/src/Modal.vue b/vue/src/Modal.vue index 19414ca..8d5b649 100644 --- a/vue/src/Modal.vue +++ b/vue/src/Modal.vue @@ -3,7 +3,7 @@ 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) @@ -11,18 +11,33 @@ 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 + }, })