From af358c1e04bc9ab4d0a94a696781ed42935db5ca Mon Sep 17 00:00:00 2001 From: fantasticit Date: Wed, 4 May 2022 12:07:09 +0800 Subject: [PATCH] fix: fix layout drag width --- packages/client/src/helpers/clamp.ts | 9 ++ packages/client/src/helpers/storage.tsx | 4 +- .../client/src/hooks/use-dragable-width.ts | 95 ++++++++++++------- .../src/layouts/double-column/index.tsx | 6 +- .../client/src/tiptap/prose-utils/clamp.ts | 10 +- 5 files changed, 77 insertions(+), 47 deletions(-) create mode 100644 packages/client/src/helpers/clamp.ts diff --git a/packages/client/src/helpers/clamp.ts b/packages/client/src/helpers/clamp.ts new file mode 100644 index 00000000..bc5c2663 --- /dev/null +++ b/packages/client/src/helpers/clamp.ts @@ -0,0 +1,9 @@ +export function clamp(val: number, min: number, max: number): number { + if (val < min) { + return min; + } + if (val > max) { + return max; + } + return val; +} diff --git a/packages/client/src/helpers/storage.tsx b/packages/client/src/helpers/storage.tsx index e625f576..f5127890 100644 --- a/packages/client/src/helpers/storage.tsx +++ b/packages/client/src/helpers/storage.tsx @@ -1,8 +1,8 @@ -export function getStorage(key) { +export function getStorage(key, defaultValue = null) { if (typeof window === 'undefined') throw new Error(); const value = localStorage.getItem(key); - if (!value) return undefined; + if (!value) return defaultValue; try { return JSON.parse(value); } catch (e) { diff --git a/packages/client/src/hooks/use-dragable-width.ts b/packages/client/src/hooks/use-dragable-width.ts index 069552a3..285e6158 100644 --- a/packages/client/src/hooks/use-dragable-width.ts +++ b/packages/client/src/hooks/use-dragable-width.ts @@ -1,56 +1,85 @@ -import { useCallback, useEffect, useRef } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import useSWR from 'swr'; import { useWindowSize } from 'hooks/use-window-size'; import { setStorage, getStorage } from 'helpers/storage'; +import { clamp } from 'helpers/clamp'; const key = 'dragable-menu-width'; -export const MIN_WIDTH = 240; -export const MAX_WIDTH = 600; +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 const COLLAPSED_WIDTH = 24; +const PC_MOBILE_CRITICAL_WIDTH = 765; + export const useDragableWidth = () => { - const runTimeWidthRef = useRef(null); - const { data, mutate } = useSWR(key, getStorage); - const windowSize = useWindowSize(); - const isCollapsed = data <= COLLAPSED_WIDTH; + 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(key, () => { + const nextWidth = getStorage(key, minWidth); - const updateWidth = (size) => { - setStorage(key, size); - mutate(); - runTimeWidthRef.current = size; - }; + if (nextWidth <= COLLAPSED_WIDTH) { + return COLLAPSED_WIDTH; + } - const toggleCollapsed = useCallback( - (collapsed = null) => { - const isBool = typeof collapsed === 'boolean'; - const nextCollapsed = isBool ? collapsed : !isCollapsed; - const nextWidth = nextCollapsed ? COLLAPSED_WIDTH : MIN_WIDTH; - setStorage(key, nextWidth); + return clamp(nextWidth, minWidth, maxWidth); + }); + const prevWidthRef = useRef(maxWidth); + + const updateWidth = useCallback( + (size) => { + const isMobile = windowWidth <= PC_MOBILE_CRITICAL_WIDTH; + + if (isMobile && size < maxWidth) { + size = minWidth; + } + setStorage(key, size); + prevWidthRef.current = size; mutate(); - runTimeWidthRef.current = nextWidth; }, - [isCollapsed, mutate] + [mutate, windowWidth, minWidth, maxWidth] ); - useEffect(() => { - mutate(); + const toggleCollapsed = useCallback(() => { + const isCollapsed = currentWidth <= COLLAPSED_WIDTH; - return () => { - runTimeWidthRef.current = null; - }; - }, [mutate]); + if (!isCollapsed) { + prevWidthRef.current = currentWidth; + setStorage(key, COLLAPSED_WIDTH); + } else { + let nextWidth = prevWidthRef.current; - useEffect(() => { - if (!windowSize.width) return; - if (windowSize.width <= 765) { - toggleCollapsed(true); + if (nextWidth >= maxWidth) { + nextWidth = maxWidth; + } + + if (nextWidth <= minWidth) { + nextWidth = minWidth; + } + + setStorage(key, nextWidth); } - }, [windowSize.width, toggleCollapsed]); + 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]); return { - width: data, - isCollapsed, + minWidth, + maxWidth, + width: currentWidth, + isCollapsed: currentWidth <= COLLAPSED_WIDTH, toggleCollapsed, updateWidth, }; diff --git a/packages/client/src/layouts/double-column/index.tsx b/packages/client/src/layouts/double-column/index.tsx index f5a4fdbe..a7191f1c 100644 --- a/packages/client/src/layouts/double-column/index.tsx +++ b/packages/client/src/layouts/double-column/index.tsx @@ -3,7 +3,7 @@ import cls from 'classnames'; import { Layout as SemiLayout, Button } from '@douyinfe/semi-ui'; import { IconChevronLeft, IconChevronRight } from '@douyinfe/semi-icons'; import SplitPane from 'react-split-pane'; -import { useDragableWidth, MIN_WIDTH, MAX_WIDTH } from 'hooks/use-dragable-width'; +import { useDragableWidth } from 'hooks/use-dragable-width'; import { RouterHeader } from '../router-header'; import styles from './index.module.scss'; @@ -15,13 +15,13 @@ interface IProps { } export const DoubleColumnLayout: React.FC = ({ leftNode, rightNode }) => { - const { width, isCollapsed, updateWidth, toggleCollapsed } = useDragableWidth(); + const { minWidth, maxWidth, width, isCollapsed, updateWidth, toggleCollapsed } = useDragableWidth(); return ( - +