/** * @Author: ?? * @Date: ?? */ import React, { useCallback, useEffect, useImperativeHandle, useMemo, useState } from "react"; import { LayoutMapProps } from "./interface"; import { Layouts, Responsive as ResponsiveGridLayout } from "react-grid-layout"; import { breakpoints, cols, LayoutMapConfig, LayoutMedia, layouts, PLACE_ORDER_WIDTH, purePoints } from "@components/LayoutMap/layoutMapConfig"; import { calcNewestNodeAndMedia, throttle } from "./utils"; import { clone, mapObjIndexed, pipe, values, reduce } from "ramda"; import { LocalStore } from "@utils/localStore"; import "./index.css"; import { FullScreenIcon } from "@icons/FullScreen"; import { IconCom } from "@icons/index"; /** * ### 引用方法 * ```tsx * import { LayoutMap } from "@atomintl/exchange-ui"; * ``` */ export const LayoutMap: React.FC = props => { const { views, responsiveGridLayoutProps, layoutsCacheName } = props; const storageLayouts = layoutsCacheName && LocalStore.get(layoutsCacheName) ? JSON.parse(LocalStore.get(layoutsCacheName)) : undefined; const { innerWidth: initInnerWidth, currentMedia: initMedia } = calcNewestNodeAndMedia( purePoints, breakpoints as any ); const [innerWidth, setInnerWidth] = useState(initInnerWidth - PLACE_ORDER_WIDTH); const [currentMedia, setCurrentMedia] = useState(initMedia); const [alternativeLayout, setAlternativeLayout] = useState(); const [virtualViews, setVirtualViews] = useState(views); const [isFull, setIsFull] = useState(false); useEffect(() => { function handleWindowResize() { const { innerWidth, currentMedia } = calcNewestNodeAndMedia(purePoints, breakpoints as any); setInnerWidth(innerWidth - PLACE_ORDER_WIDTH); setCurrentMedia(currentMedia); } handleWindowResize(); const throttledWindowResize = throttle(handleWindowResize, 5); window?.addEventListener("resize", throttledWindowResize); return () => window?.removeEventListener("resize", throttledWindowResize); }, []); let MetaViews = useMemo(() => { return pipe( mapObjIndexed((value, key) => ({ key, value })), values )(virtualViews); }, [virtualViews, alternativeLayout]); const onFullScreenTapped = useCallback( (e: React.MouseEvent, key: string) => { if (isFull) { setVirtualViews(views); setAlternativeLayout(undefined); setIsFull(false); } else { const dataGrid = LayoutMapConfig[currentMedia]?.dataGrid; const fullWidth = LayoutMapConfig[currentMedia]?.col; const fullHeight = reduce( (acc: number, value: any) => (value.i === "T" || value.i === "V" || value.i === "O" ? acc + value.h : acc), 0, dataGrid ); const lastDataGrid = [{ i: key, x: 0, y: 0, w: fullWidth, h: fullHeight }]; const _layouts = clone(layouts); _layouts[currentMedia] = lastDataGrid; setVirtualViews({ [key]: virtualViews[key] }); setAlternativeLayout(_layouts); setIsFull(true); } e.stopPropagation(); }, [isFull, views, currentMedia, virtualViews] ); const onResizeHandle = useCallback(() => { if (isFull) { setVirtualViews(views); setAlternativeLayout(clone(layouts)); setIsFull(false); return; } layoutsCacheName && LocalStore.remove(layoutsCacheName); const _layouts = clone(layouts); _layouts[currentMedia].push({ i: "INVISIBLE", x: 0, y: 0, w: 0, h: 0 }); setAlternativeLayout(alternativeLayout ? undefined : _layouts); }, [isFull, views, layoutsCacheName, alternativeLayout]); useImperativeHandle(props.onRef, () => ({ onResizeHandle })); return ( } onLayoutChange={e => { if (!isFull && layoutsCacheName) { const _layouts = clone(layouts); _layouts[currentMedia] = e; LocalStore.set(layoutsCacheName, JSON.stringify(_layouts)); } }} {...responsiveGridLayoutProps} > {MetaViews.map((_item, _index) => (
{_item.key === "T" ? null : ( onFullScreenTapped(e, _item.key)}> )} {!React.isValidElement(_item.value) ? _item.value : React.cloneElement(_item.value, { ...(_item.value.props as object), onResizeHandle } as any)}
))}
); }; LayoutMap.defaultProps = {}; export type { LayoutMapProps }; export default LayoutMap;