think/packages/client/src/hooks/use-dragable-width.ts

87 lines
2.3 KiB
TypeScript
Raw Normal View History

2022-05-04 04:07:09 +00:00
import { useCallback, useEffect, useRef, useState } from 'react';
2022-03-12 02:31:03 +00:00
import useSWR from 'swr';
2022-03-27 07:43:06 +00:00
import { useWindowSize } from 'hooks/use-window-size';
2022-03-12 02:31:03 +00:00
import { setStorage, getStorage } from 'helpers/storage';
2022-05-04 04:07:09 +00:00
import { clamp } from 'helpers/clamp';
2022-02-20 11:51:55 +00:00
2022-03-12 02:31:03 +00:00
const key = 'dragable-menu-width';
2022-02-20 11:51:55 +00:00
2022-05-04 04:07:09 +00:00
const DEFAULT_PC_MIN_WIDTH = 240;
const DEFAULT_PC_MAX_WIDTH = 600;
const DEFAULT_MOBILE_MIN_WIDTH = 24;
const DEFAULT_MOBILE_MAX_WIDTH = 240;
// 收起宽度24
2022-02-20 11:51:55 +00:00
const COLLAPSED_WIDTH = 24;
2022-05-04 04:07:09 +00:00
const PC_MOBILE_CRITICAL_WIDTH = 765;
2022-02-20 11:51:55 +00:00
export const useDragableWidth = () => {
2022-05-04 04:07:09 +00:00
const { width: windowWidth } = useWindowSize();
const [minWidth, setMinWidth] = useState(DEFAULT_MOBILE_MIN_WIDTH);
const [maxWidth, setMaxWidth] = useState(DEFAULT_MOBILE_MAX_WIDTH);
const { data: currentWidth, mutate } = useSWR<number>(key, () => {
const nextWidth = getStorage(key, minWidth);
2022-02-20 11:51:55 +00:00
2022-05-04 04:07:09 +00:00
if (nextWidth <= COLLAPSED_WIDTH) {
return COLLAPSED_WIDTH;
}
2022-02-20 11:51:55 +00:00
2022-05-04 04:07:09 +00:00
return clamp(nextWidth, minWidth, maxWidth);
});
const prevWidthRef = useRef<number>(maxWidth);
const updateWidth = useCallback(
(size) => {
const isMobile = windowWidth <= PC_MOBILE_CRITICAL_WIDTH;
if (isMobile && size < maxWidth) {
size = minWidth;
}
setStorage(key, size);
prevWidthRef.current = size;
2022-05-01 14:07:22 +00:00
mutate();
},
2022-05-04 04:07:09 +00:00
[mutate, windowWidth, minWidth, maxWidth]
2022-05-01 14:07:22 +00:00
);
2022-02-20 11:51:55 +00:00
2022-05-04 04:07:09 +00:00
const toggleCollapsed = useCallback(() => {
const isCollapsed = currentWidth <= COLLAPSED_WIDTH;
2022-02-20 11:51:55 +00:00
2022-05-04 04:07:09 +00:00
if (!isCollapsed) {
prevWidthRef.current = currentWidth;
setStorage(key, COLLAPSED_WIDTH);
} else {
let nextWidth = prevWidthRef.current;
2022-02-20 11:51:55 +00:00
2022-05-04 04:07:09 +00:00
if (nextWidth >= maxWidth) {
nextWidth = maxWidth;
}
if (nextWidth <= minWidth) {
nextWidth = minWidth;
}
setStorage(key, nextWidth);
}
2022-05-04 04:07:09 +00:00
mutate();
}, [mutate, currentWidth, minWidth]);
useEffect(() => {
const min = windowWidth <= PC_MOBILE_CRITICAL_WIDTH ? DEFAULT_MOBILE_MIN_WIDTH : DEFAULT_PC_MIN_WIDTH;
const max = windowWidth <= PC_MOBILE_CRITICAL_WIDTH ? DEFAULT_MOBILE_MAX_WIDTH : DEFAULT_PC_MAX_WIDTH;
setMinWidth(min);
setMaxWidth(max);
}, [windowWidth, mutate, currentWidth]);
2022-02-20 11:51:55 +00:00
return {
2022-05-04 04:07:09 +00:00
minWidth,
maxWidth,
width: currentWidth,
isCollapsed: currentWidth <= COLLAPSED_WIDTH,
2022-02-20 11:51:55 +00:00
toggleCollapsed,
updateWidth,
};
};