diff --git a/src/composables/useAuthenticatedLayoutResizable.js b/src/composables/useAuthenticatedLayoutResizable.js index a96dafd7..19651ca9 100644 --- a/src/composables/useAuthenticatedLayoutResizable.js +++ b/src/composables/useAuthenticatedLayoutResizable.js @@ -1,4 +1,4 @@ -import { computed, nextTick, onMounted, ref, watch } from 'vue'; +import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'; import { storeToRefs } from 'pinia'; import { useAppearanceSettingsStore } from '../stores'; @@ -15,15 +15,18 @@ export function useAuthenticatedLayoutResizable() { const { asideWidth, isNavCollapsed, isSideBarTabShow, navWidth } = storeToRefs(appearanceStore); - const panelGroupRef = ref(null); - const navPanelRef = ref(null); - const navExpandedSize = ref(null); - const fallbackWidth = typeof window !== 'undefined' && window.innerWidth ? window.innerWidth : 1200; + const panelGroupRef = ref(null); + const navPanelRef = ref(null); + const navExpandedSize = ref(null); + const groupWidth = ref(fallbackWidth); + let resizeObserver = null; + let windowResizeHandler = null; + const getGroupWidth = () => { const element = panelGroupRef.value?.$el ?? panelGroupRef.value; const width = element?.getBoundingClientRect?.().width; @@ -42,7 +45,9 @@ export function useAuthenticatedLayoutResizable() { layout.length >= 3 && layout[layout.length - 1] <= 1; - const navCollapsedSize = computed(() => pxToPercent(navCollapsedPx)); + const navCollapsedSize = computed(() => + pxToPercent(navCollapsedPx, groupWidth.value) + ); const navExpandedPx = computed(() => navWidth.value || navDefaultPx); const navDefaultSize = computed(() => @@ -75,15 +80,15 @@ export function useAuthenticatedLayoutResizable() { return; } - const groupWidth = getGroupWidth(); - if (!Number.isFinite(groupWidth) || groupWidth <= 0) { + const width = getGroupWidth(); + if (!Number.isFinite(width) || width <= 0) { return; } const navSize = sizes[0]; if (!isNavCollapsed.value && Number.isFinite(navSize) && navSize > 0) { navExpandedSize.value = navSize; - setNavWidth(Math.round(percentToPx(navSize, groupWidth))); + setNavWidth(Math.round(percentToPx(navSize, width))); } if (!isSideBarTabShow.value || sizes.length < 3) { @@ -100,12 +105,19 @@ export function useAuthenticatedLayoutResizable() { return; } - setAsideWidth(Math.round(percentToPx(asideSize, groupWidth))); + setAsideWidth(Math.round(percentToPx(asideSize, width))); }; const resizeNavPanel = (targetSize) => navPanelRef.value?.resize?.(targetSize); + const updateGroupWidth = () => { + groupWidth.value = getGroupWidth(); + if (isNavCollapsed.value) { + resizeNavPanel(navCollapsedSize.value); + } + }; + watch(isNavCollapsed, async (collapsed) => { await nextTick(); if (collapsed) { @@ -119,6 +131,7 @@ export function useAuthenticatedLayoutResizable() { onMounted(async () => { await nextTick(); + updateGroupWidth(); let panelSize = null; panelSize = navPanelRef.value?.getSize?.() ?? null; @@ -126,6 +139,26 @@ export function useAuthenticatedLayoutResizable() { if (isNavCollapsed.value) { resizeNavPanel(navCollapsedSize.value); } + + const element = panelGroupRef.value?.$el ?? panelGroupRef.value; + if (element && typeof ResizeObserver !== 'undefined') { + resizeObserver = new ResizeObserver(updateGroupWidth); + resizeObserver.observe(element); + } else if (typeof window !== 'undefined') { + windowResizeHandler = updateGroupWidth; + window.addEventListener('resize', windowResizeHandler); + } + }); + + onUnmounted(() => { + if (resizeObserver) { + resizeObserver.disconnect(); + resizeObserver = null; + } + if (windowResizeHandler && typeof window !== 'undefined') { + window.removeEventListener('resize', windowResizeHandler); + windowResizeHandler = null; + } }); return { diff --git a/src/composables/useDataTableScrollHeight.js b/src/composables/useDataTableScrollHeight.js index cf3eb796..ca7733e0 100644 --- a/src/composables/useDataTableScrollHeight.js +++ b/src/composables/useDataTableScrollHeight.js @@ -19,12 +19,17 @@ export function useDataTableScrollHeight(containerRef, options = {}) { return 0; } const style = getComputedStyle(el); - return (Number.parseFloat(style.paddingTop) || 0) + (Number.parseFloat(style.paddingBottom) || 0); + return ( + (Number.parseFloat(style.paddingTop) || 0) + + (Number.parseFloat(style.paddingBottom) || 0) + ); }; const getHeight = (maybeRef) => { const el = maybeRef?.value; - return el && typeof el.getBoundingClientRect === 'function' ? el.getBoundingClientRect().height : 0; + return el && typeof el.getBoundingClientRect === 'function' + ? el.getBoundingClientRect().height + : 0; }; const recalc = () => { @@ -33,7 +38,10 @@ export function useDataTableScrollHeight(containerRef, options = {}) { return; } - const extraOffset = extraOffsetRefs.reduce((sum, ref) => sum + getHeight(ref), 0); + const extraOffset = extraOffsetRefs.reduce( + (sum, ref) => sum + getHeight(ref), + 0 + ); const available = containerEl.clientHeight - @@ -51,10 +59,12 @@ export function useDataTableScrollHeight(containerRef, options = {}) { return; } - const nextObserved = new Set([ - containerRef?.value, - ...extraOffsetRefs.map((ref) => ref?.value) - ].filter(Boolean)); + const nextObserved = new Set( + [ + containerRef?.value, + ...extraOffsetRefs.map((ref) => ref?.value) + ].filter(Boolean) + ); for (const el of observedElements) { if (!nextObserved.has(el)) { @@ -93,7 +103,8 @@ export function useDataTableScrollHeight(containerRef, options = {}) { }); const tableStyle = computed(() => { - if (!Number.isFinite(maxHeight.value) || maxHeight.value <= 0) return undefined; + if (!Number.isFinite(maxHeight.value) || maxHeight.value <= 0) + return undefined; return { maxHeight: `${maxHeight.value}px` }; });