🎨 Refactor code style for consistency and readability in BaseModal component
This commit is contained in:
@@ -60,7 +60,7 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modal title (alternative to header slot)
|
* Modal title (alternative to header slot)
|
||||||
*/
|
*/
|
||||||
@@ -68,7 +68,7 @@ const props = defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modal size
|
* Modal size
|
||||||
* @type {'small' | 'medium' | 'large' | 'full'}
|
* @type {'small' | 'medium' | 'large' | 'full'}
|
||||||
@@ -76,9 +76,9 @@ const props = defineProps({
|
|||||||
size: {
|
size: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'medium',
|
default: 'medium',
|
||||||
validator: (value) => ['small', 'medium', 'large', 'full'].includes(value)
|
validator: value => ['small', 'medium', 'large', 'full'].includes(value)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether clicking overlay closes the modal
|
* Whether clicking overlay closes the modal
|
||||||
*/
|
*/
|
||||||
@@ -86,7 +86,7 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether modal can be closed (hides X button, prevents ESC/overlay close)
|
* Whether modal can be closed (hides X button, prevents ESC/overlay close)
|
||||||
*/
|
*/
|
||||||
@@ -94,7 +94,7 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to show the close X button
|
* Whether to show the close X button
|
||||||
*/
|
*/
|
||||||
@@ -123,7 +123,7 @@ const handleOverlayClick = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEscapeKey = (event) => {
|
const handleEscapeKey = event => {
|
||||||
if (event.key === 'Escape' && props.modelValue && !props.persistent) {
|
if (event.key === 'Escape' && props.modelValue && !props.persistent) {
|
||||||
handleClose();
|
handleClose();
|
||||||
}
|
}
|
||||||
@@ -132,7 +132,7 @@ const handleEscapeKey = (event) => {
|
|||||||
// Focus management
|
// Focus management
|
||||||
const getFocusableElements = () => {
|
const getFocusableElements = () => {
|
||||||
if (!modalRef.value) return [];
|
if (!modalRef.value) return [];
|
||||||
|
|
||||||
const focusableSelectors = [
|
const focusableSelectors = [
|
||||||
'a[href]',
|
'a[href]',
|
||||||
'area[href]',
|
'area[href]',
|
||||||
@@ -143,21 +143,21 @@ const getFocusableElements = () => {
|
|||||||
'[tabindex]:not([tabindex="-1"])',
|
'[tabindex]:not([tabindex="-1"])',
|
||||||
'[contenteditable="true"]'
|
'[contenteditable="true"]'
|
||||||
];
|
];
|
||||||
|
|
||||||
return Array.from(
|
return Array.from(
|
||||||
modalRef.value.querySelectorAll(focusableSelectors.join(','))
|
modalRef.value.querySelectorAll(focusableSelectors.join(','))
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleTabKey = (event) => {
|
const handleTabKey = event => {
|
||||||
if (!props.modelValue) return;
|
if (!props.modelValue) return;
|
||||||
|
|
||||||
const focusableElements = getFocusableElements();
|
const focusableElements = getFocusableElements();
|
||||||
if (focusableElements.length === 0) return;
|
if (focusableElements.length === 0) return;
|
||||||
|
|
||||||
const firstElement = focusableElements[0];
|
const firstElement = focusableElements[0];
|
||||||
const lastElement = focusableElements[focusableElements.length - 1];
|
const lastElement = focusableElements[focusableElements.length - 1];
|
||||||
|
|
||||||
if (event.shiftKey) {
|
if (event.shiftKey) {
|
||||||
// Shift + Tab: move focus backwards
|
// Shift + Tab: move focus backwards
|
||||||
if (document.activeElement === firstElement) {
|
if (document.activeElement === firstElement) {
|
||||||
@@ -173,7 +173,7 @@ const handleTabKey = (event) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleKeyDown = (event) => {
|
const handleKeyDown = event => {
|
||||||
if (event.key === 'Escape') {
|
if (event.key === 'Escape') {
|
||||||
handleEscapeKey(event);
|
handleEscapeKey(event);
|
||||||
} else if (event.key === 'Tab') {
|
} else if (event.key === 'Tab') {
|
||||||
@@ -182,32 +182,35 @@ const handleKeyDown = (event) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Lifecycle hooks
|
// Lifecycle hooks
|
||||||
watch(() => props.modelValue, async (newValue) => {
|
watch(
|
||||||
if (newValue) {
|
() => props.modelValue,
|
||||||
// Modal opened
|
async newValue => {
|
||||||
previousActiveElement.value = document.activeElement;
|
if (newValue) {
|
||||||
document.body.style.overflow = 'hidden';
|
// Modal opened
|
||||||
emit('open');
|
previousActiveElement.value = document.activeElement;
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
// Focus first focusable element after render
|
emit('open');
|
||||||
await nextTick();
|
|
||||||
const focusableElements = getFocusableElements();
|
// Focus first focusable element after render
|
||||||
if (focusableElements.length > 0) {
|
await nextTick();
|
||||||
focusableElements[0].focus();
|
const focusableElements = getFocusableElements();
|
||||||
} else if (modalRef.value) {
|
if (focusableElements.length > 0) {
|
||||||
modalRef.value.focus();
|
focusableElements[0].focus();
|
||||||
}
|
} else if (modalRef.value) {
|
||||||
} else {
|
modalRef.value.focus();
|
||||||
// Modal closed
|
}
|
||||||
document.body.style.overflow = '';
|
} else {
|
||||||
|
// Modal closed
|
||||||
// Restore focus to previous element
|
document.body.style.overflow = '';
|
||||||
if (previousActiveElement.value) {
|
|
||||||
previousActiveElement.value.focus();
|
// Restore focus to previous element
|
||||||
previousActiveElement.value = null;
|
if (previousActiveElement.value) {
|
||||||
|
previousActiveElement.value.focus();
|
||||||
|
previousActiveElement.value = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
document.addEventListener('keydown', handleKeyDown);
|
document.addEventListener('keydown', handleKeyDown);
|
||||||
@@ -244,7 +247,9 @@ onBeforeUnmount(() => {
|
|||||||
.modal-container {
|
.modal-container {
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
box-shadow:
|
||||||
|
0 20px 25px -5px rgba(0, 0, 0, 0.1),
|
||||||
|
0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||||
max-height: 90vh;
|
max-height: 90vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
Reference in New Issue
Block a user