Files
tools/vue/primitives/src/overlays/drawer/useScaleBackground.ts
T
robonen 85313c6046
Publish to NPM / Check version changes and publish (push) Successful in 11m14s
feat: update useSnapPoints to improve drawer snapping behavior and add new features
2026-08-03 21:12:35 +07:00

62 lines
2.5 KiB
TypeScript

import { onWatcherCleanup, ref, watchEffect } from 'vue';
import { isClient } from '@robonen/platform/multi';
import { assignStyle } from '@robonen/platform/browsers';
import { injectDrawerRootContext } from './context';
import { getDrawerWrapper, getScaleFactor, isVertical } from './helpers';
import { BORDER_RADIUS, TRANSITIONS } from './constants';
/**
* Scales the page background down behind the drawer (the stacked-card effect),
* transforming the element marked `data-drawer-wrapper`. Restores everything,
* including the body background, when the drawer closes. No-op unless
* `shouldScaleBackground` is enabled on the root.
*/
export function useScaleBackground() {
const { direction, isOpen, shouldScaleBackground, setBackgroundColorOnScale, noBodyStyles } = injectDrawerRootContext();
const timeoutIdRef = ref<number | null>(null);
const initialBackgroundColor = ref(typeof document !== 'undefined' ? document.body.style.backgroundColor : '');
watchEffect(() => {
// `flush: 'pre'` watchers run during SSR; this effect touches document/window,
// so it must stay client-only.
if (isClient && isOpen.value && shouldScaleBackground.value) {
if (timeoutIdRef.value)
clearTimeout(timeoutIdRef.value);
const wrapper = getDrawerWrapper();
if (!wrapper)
return;
if (setBackgroundColorOnScale.value && !noBodyStyles.value)
assignStyle(document.body, { background: 'black' });
assignStyle(wrapper, {
transformOrigin: isVertical(direction.value) ? 'top' : 'left',
transitionProperty: 'transform, border-radius',
transitionDuration: `${TRANSITIONS.DURATION}s`,
transitionTimingFunction: `cubic-bezier(${TRANSITIONS.EASE.join(',')})`,
});
const scale = getScaleFactor(window.innerWidth);
const wrapperStylesCleanup = assignStyle(wrapper, {
borderRadius: `${BORDER_RADIUS}px`,
overflow: 'hidden',
...(isVertical(direction.value)
? { transform: `scale(${scale}) translate3d(0, calc(env(safe-area-inset-top) + 14px), 0)` }
: { transform: `scale(${scale}) translate3d(calc(env(safe-area-inset-top) + 14px), 0, 0)` }),
});
onWatcherCleanup(() => {
wrapperStylesCleanup();
timeoutIdRef.value = setTimeout(() => {
if (initialBackgroundColor.value)
document.body.style.background = initialBackgroundColor.value;
else
document.body.style.removeProperty('background');
}, TRANSITIONS.DURATION * 1000);
});
}
}, { flush: 'pre' });
}