denwa-web-shared
Version:
A shared library for Next.js App Router projects containing reusable components, hooks, schemas, and utilities.
202 lines (201 loc) • 5.35 kB
JavaScript
import { useEffect, useRef, useState } from "react";
import { useIntersection, useMedia, useWindowScroll } from "react-use";
import { useInView } from "motion/react";
import { clsx } from "clsx";
import { twMerge } from "tailwind-merge";
import { jsx, jsxs } from "react/jsx-runtime";
//#region src/client/hooks/use-disable-scroll.ts
var useDisableScroll = (isDisableScroll) => {
useEffect(() => {
if (!isDisableScroll) return;
const scrollPosition = window.scrollY;
return () => {
window.scrollTo(0, scrollPosition);
};
}, []);
};
//#endregion
//#region src/client/hooks/use-is-client.ts
var useIsClient = () => {
const [isClient, setIsClient] = useState(false);
useEffect(() => {
setIsClient(true);
}, []);
return isClient;
};
//#endregion
//#region src/server/constants/index.ts
var THEME = {
VIEW_PORT: {
EXTRA_SMALL: 280,
SMALL: 320,
SMALL_MOBILE: 380,
MOBILE: 450,
MEDIUM: 500,
EXTRA_MEDIUM: 600,
TABLET: 768,
LAPTOP: 1024,
LAPTOP_BIG: 1200,
BIG: 1440,
VERY_BIG: 1920
},
OFFSET: {
1: 8,
2: 16,
3: 24,
4: 32,
5: 40,
6: 48,
7: 56,
8: 64
}
};
//#endregion
//#region src/client/hooks/use-view-port.ts
var useLaptopBigViewPort = () => {
return {
isLaptopBigMinWidth: useMedia(`(min-width: ${THEME.VIEW_PORT.LAPTOP_BIG}px)`),
isLaptopBigMaxWidth: useMedia(`(max-width: ${THEME.VIEW_PORT.LAPTOP_BIG}px)`)
};
};
var useLaptopViewPort = () => {
return {
isLaptopMinWidth: useMedia(`(min-width: ${THEME.VIEW_PORT.LAPTOP}px)`),
isLaptopMaxWidth: useMedia(`(max-width: ${THEME.VIEW_PORT.LAPTOP}px)`)
};
};
var useTabletViewPort = () => {
return {
isTabletMinWidth: useMedia(`(min-width: ${THEME.VIEW_PORT.TABLET}px)`),
isTabletMaxWidth: useMedia(`(max-width: ${THEME.VIEW_PORT.TABLET}px)`)
};
};
var useExtraMediumViewPort = () => {
return {
isExtraMediumMinWidth: useMedia(`(min-width: ${THEME.VIEW_PORT.EXTRA_MEDIUM}px)`),
isExtraMediumMaxWidth: useMedia(`(max-width: ${THEME.VIEW_PORT.EXTRA_MEDIUM}px)`)
};
};
var useMobileViewPort = () => {
return {
isMobileMinWidth: useMedia(`(min-width: ${THEME.VIEW_PORT.MOBILE}px)`),
isMobileMaxWidth: useMedia(`(max-width: ${THEME.VIEW_PORT.MOBILE}px)`)
};
};
var useSmallViewPort = () => {
return {
isSmallMinWidth: useMedia(`(min-width: ${THEME.VIEW_PORT.SMALL}px)`),
isSmallMaxWidth: useMedia(`(max-width: ${THEME.VIEW_PORT.SMALL}px)`)
};
};
//#endregion
//#region src/client/hooks/use-appear-animation.ts
var useAppearAnimation = ({ once = true, margin = "-100px", delay = .1, direction = "up", animationDistance = 50, duration = .8, ease = "easeOut" } = {}) => {
const ref = useRef(null);
const isInView = useInView(ref, {
once,
margin
});
const getInitialState = () => {
switch (direction) {
case "up": return {
opacity: 0,
y: animationDistance
};
case "down": return {
opacity: 0,
y: -animationDistance
};
case "left": return {
opacity: 0,
x: animationDistance
};
case "right": return {
opacity: 0,
x: -animationDistance
};
case "scale": return {
opacity: 0,
scale: .8
};
case "fade": return { opacity: 0 };
default: return {
opacity: 0,
y: animationDistance
};
}
};
const getAnimateState = () => {
switch (direction) {
case "up":
case "down": return {
opacity: 1,
y: 0
};
case "left":
case "right": return {
opacity: 1,
x: 0
};
case "scale": return {
opacity: 1,
scale: 1
};
case "fade": return { opacity: 1 };
default: return {
opacity: 1,
y: 0
};
}
};
return {
ref,
isInView,
motionProps: {
initial: getInitialState(),
animate: isInView ? getAnimateState() : void 0,
transition: {
duration,
ease,
delay
}
}
};
};
//#endregion
//#region src/server/lib/css.ts
function cn(...inputs) {
return twMerge(clsx(inputs));
}
//#endregion
//#region src/client/ui/header-wrapper.tsx
var HeaderWrapper = ({ children, className, hideClassName, scrollPosition = 100, hideBackgroundOnScroll = true }) => {
const { y } = useWindowScroll();
const isClient = useIsClient();
const isHiddenBackground = hideBackgroundOnScroll && y > scrollPosition && isClient;
return /* @__PURE__ */ jsx("header", {
className: cn("fixed z-30 w-full transition bg-background", className, { "bg-transparent": isHiddenBackground }, { hideClassName: isHiddenBackground && hideClassName }),
children
});
};
//#endregion
//#region src/client/ui/infinity-list.tsx
var InfinityList = ({ children, intersectionElementClassName, isNext, intersectionElement, onIntersection }) => {
const intersectionRef = useRef({});
const intersection = useIntersection(intersectionRef, {
root: null,
rootMargin: "0px",
threshold: 1
});
useEffect(() => {
if (!intersection?.isIntersecting) return;
onIntersection();
}, [intersection?.isIntersecting]);
return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", { children }), /* @__PURE__ */ jsx("div", {
className: cn(intersectionElementClassName, { hidden: !isNext }),
ref: intersectionRef,
children: intersectionElement()
})] });
};
//#endregion
export { HeaderWrapper, InfinityList, useAppearAnimation, useDisableScroll, useExtraMediumViewPort, useIsClient, useLaptopBigViewPort, useLaptopViewPort, useMobileViewPort, useSmallViewPort, useTabletViewPort };