Browse Source

chore:backup

代强 3 years ago
parent
commit
5bd4baa3db

+ 0 - 0
packages/semi-foundation/collapsible/animation.scss


+ 3 - 0
packages/semi-foundation/collapsible/collapsible.scss

@@ -0,0 +1,3 @@
+import "./animation.scss";
+import "./variables.scss";
+

+ 37 - 0
packages/semi-foundation/collapsible/foundation.ts

@@ -0,0 +1,37 @@
+import BaseFoundation, {DefaultAdapter} from "../base/foundation";
+import {CollapseAdapter} from "../collapse/foundation";
+import {Motion} from "@douyinfe/semi-ui/_base/base";
+import React from "react";
+
+
+export interface CollapsibleFoundationProps{
+    isOpen?: boolean;
+    duration?: number;
+    keepDOM?: boolean;
+    className?: string;
+    collapseHeight?: number;
+    reCalcKey?: number | string;
+    id?:string,
+}
+
+export interface CollapsibleFoundationState{
+
+}
+
+
+
+export interface CollapsibleAdapter<P = Record<string, any>, S = Record<string, any>>  extends DefaultAdapter<P, S>{
+
+}
+
+class CollapsibleFoundation extends BaseFoundation<CollapsibleAdapter>{
+
+    constructor(adapter: CollapseAdapter) {
+        super({
+            ...adapter
+        });
+    }
+}
+
+
+export default CollapsibleFoundation;

+ 0 - 0
packages/semi-foundation/collapsible/variables.scss


+ 166 - 0
packages/semi-ui/collapsible/index.old.tsx

@@ -0,0 +1,166 @@
+// @ts-ignore  currently no type definition for @douyinfe/semi-animation-react
+import { Transition } from '@douyinfe/semi-animation-react';
+import PropTypes from 'prop-types';
+import cls from 'classnames';
+import React, { useRef, useState, useCallback, useMemo } from 'react';
+import { cssClasses } from '@douyinfe/semi-foundation/collapsible/constants';
+import { Motion } from '../_base/base';
+import getMotionObjFromProps from '@douyinfe/semi-foundation/utils/getMotionObjFromProps';
+
+const ease = 'cubicBezier(.25,.1,.25,1)';
+
+export interface CollapsibleProps {
+    motion?: Motion;
+    children?: React.ReactNode;
+    isOpen?: boolean;
+    duration?: number;
+    keepDOM?: boolean;
+    className?: string;
+    style?: React.CSSProperties;
+    collapseHeight?: number;
+    reCalcKey?: number | string;
+    id?:string,
+}
+
+
+const Collapsible = (props: CollapsibleProps) => {
+    const {
+        motion,
+        children,
+        isOpen,
+        duration,
+        keepDOM,
+        collapseHeight,
+        style,
+        className,
+        reCalcKey,
+        id
+    } = props;
+
+    const ref = useRef(null);
+    const [maxHeight, setMaxHeight] = useState(0);
+    const [open, setOpen] = useState(props.isOpen);
+    const [isFirst, setIsFirst] = useState(true);
+    const [transitionImmediate, setTransitionImmediate] = useState(open && isFirst);
+    const [left, setLeft] = useState(!props.isOpen);
+    if (isOpen !== open) {
+        setOpen(isOpen);
+        if (isFirst) {
+            setIsFirst(false);
+            setTransitionImmediate(false);
+        }
+        isOpen && setLeft(!isOpen);
+    }
+
+    const setHeight = useCallback(node => {
+        const currHeight = node && node.scrollHeight;
+        console.log(currHeight,left,reCalcKey)
+        if (currHeight && maxHeight !== currHeight) {
+            setMaxHeight(currHeight);
+        }
+        // eslint-disable-next-line react-hooks/exhaustive-deps
+    }, [left, reCalcKey, maxHeight]);
+
+    const resetHeight = () => {
+        ref.current.style.maxHeight = 'none';
+    };
+
+    const formatStyle = ({ maxHeight: maxHeightInTransitionStyle }: any) => ({ maxHeight: maxHeightInTransitionStyle });
+
+    const shouldKeepDOM = () => keepDOM || collapseHeight !== 0;
+
+    const defaultMaxHeight = useMemo(() => {
+        return isOpen || !shouldKeepDOM() && !motion ? 'none' : collapseHeight;
+    }, [collapseHeight, motion, isOpen, shouldKeepDOM]);
+
+    const renderChildren = (transitionStyle: Record<string, any> | null) => {
+        const transition =
+            transitionStyle && typeof transitionStyle === 'object' ?
+                formatStyle(transitionStyle) :
+                {};
+
+        const wrapperstyle = {
+            overflow: 'hidden',
+            maxHeight: defaultMaxHeight,
+            ...style,
+            ...transition,
+        };
+
+        if (isFirst) {
+            wrapperstyle.maxHeight = defaultMaxHeight;
+        }
+
+        const wrapperCls = cls(`${cssClasses.PREFIX}-wrapper`, className);
+        return (
+            <div style={wrapperstyle} className={wrapperCls} ref={ref}>
+                <div
+                    ref={setHeight}
+                    style={{ overflow: 'hidden' }}
+                    id={id}
+                    x-semi-prop="children"
+                >
+                    {children}
+                </div>
+            </div>
+        );
+    };
+
+    const didLeave = () => {
+        setLeft(true);
+        !shouldKeepDOM() && setMaxHeight(collapseHeight);
+    };
+
+    const renderContent = () => {
+        if (left && !shouldKeepDOM()) {
+            return null;
+        }
+
+        const mergedMotion = getMotionObjFromProps({
+            didEnter: resetHeight,
+            didLeave,
+            motion,
+        });
+
+        return (
+            <Transition
+                state={isOpen ? 'enter' : 'leave'}
+                immediate={transitionImmediate}
+                from={{ maxHeight: 0 }}
+                enter={{ maxHeight: { val: maxHeight, easing: ease, duration } }}
+                leave={{ maxHeight: { val: collapseHeight, easing: ease, duration } }}
+                {...mergedMotion}
+            >
+                {(transitionStyle: Record<string, any>) =>
+                    renderChildren(motion ? transitionStyle : null)
+                }
+            </Transition>
+        );
+    };
+
+    return renderContent();
+};
+
+Collapsible.propType = {
+    motion: PropTypes.oneOfType([PropTypes.bool, PropTypes.func, PropTypes.object]),
+    children: PropTypes.node,
+    isOpen: PropTypes.bool,
+    duration: PropTypes.number,
+    keepDOM: PropTypes.bool,
+    collapseHeight: PropTypes.number,
+    style: PropTypes.object,
+    className: PropTypes.string,
+    reCalcKey: PropTypes.oneOfType([
+        PropTypes.string,
+        PropTypes.number
+    ]),
+};
+
+Collapsible.defaultProps = {
+    isOpen: false,
+    duration: 250,
+    motion: true,
+    keepDOM: false,
+    collapseHeight: 0
+};
+
+export default Collapsible;

+ 102 - 120
packages/semi-ui/collapsible/index.tsx

@@ -1,15 +1,12 @@
-// @ts-ignore  currently no type definition for @douyinfe/semi-animation-react
-import { Transition } from '@douyinfe/semi-animation-react';
-import PropTypes from 'prop-types';
-import cls from 'classnames';
-import React, { useRef, useState, useCallback, useMemo } from 'react';
-import { cssClasses } from '@douyinfe/semi-foundation/collapsible/constants';
-import { Motion } from '../_base/base';
-import getMotionObjFromProps from '@douyinfe/semi-foundation/utils/getMotionObjFromProps';
-
-const ease = 'cubicBezier(.25,.1,.25,1)';
-
-export interface CollapsibleProps {
+import React from 'react';
+import type {CollapsibleAdapter, CollapsibleFoundationProps, CollapsibleFoundationState} from "@douyinfe/semi-foundation/collapsible/foundation";
+import BaseComponent from "@douyinfe/semi-ui/_base/baseComponent";
+import {Motion} from "@douyinfe/semi-ui/_base/base";
+import PropTypes from "prop-types";
+import cls from "classnames";
+import {cssClasses} from "@douyinfe/semi-foundation/collapsible/constants";
+import CollapsibleOld from "@douyinfe/semi-ui/collapsible/index.old";
+interface CollapsibleProps extends CollapsibleFoundationProps{
     motion?: Motion;
     children?: React.ReactNode;
     isOpen?: boolean;
@@ -22,124 +19,117 @@ export interface CollapsibleProps {
     id?:string,
 }
 
+interface CollapsibleState extends CollapsibleFoundationState{
+    domInRenderTree:boolean
+    domHeight:number
+}
 
-const Collapsible = (props: CollapsibleProps) => {
-    const {
-        motion,
-        children,
-        isOpen,
-        duration,
-        keepDOM,
-        collapseHeight,
-        style,
-        className,
-        reCalcKey,
-        id
-    } = props;
-
-    const ref = useRef(null);
-    const [maxHeight, setMaxHeight] = useState(0);
-    const [open, setOpen] = useState(props.isOpen);
-    const [isFirst, setIsFirst] = useState(true);
-    const [transitionImmediate, setTransitionImmediate] = useState(open && isFirst);
-    const [left, setLeft] = useState(!props.isOpen);
-    if (isOpen !== open) {
-        setOpen(isOpen);
-        if (isFirst) {
-            setIsFirst(false);
-            setTransitionImmediate(false);
-        }
-        isOpen && setLeft(!isOpen);
-    }
+class Collapsible extends BaseComponent<CollapsibleProps, CollapsibleState> {
+    static defaultProps = {
+        isOpen: false,
+        duration: 250,
+        motion: true,
+        keepDOM: false,
+        collapseHeight: 0
+    };
 
-    const setHeight = useCallback(node => {
-        const currHeight = node && node.scrollHeight;
-        if (currHeight && maxHeight !== currHeight) {
-            setMaxHeight(currHeight);
+    private domRef = React.createRef<HTMLDivElement>();
+    private wrapperRef = React.createRef<HTMLDivElement>();
+    private resizeObserver: ResizeObserver | null;
+    constructor(props: CollapsibleProps) {
+        super(props);
+        this.state = {
+            domInRenderTree:false,
+            domHeight: 0,
         }
-        // eslint-disable-next-line react-hooks/exhaustive-deps
-    }, [left, reCalcKey, maxHeight]);
+    }
 
-    const resetHeight = () => {
-        ref.current.style.maxHeight = 'none';
-    };
+    get adapter(): CollapsibleAdapter<CollapsibleProps,CollapsibleState> {
+        return {
+            ...super.adapter,
+        };
+    }
 
-    const formatStyle = ({ maxHeight: maxHeightInTransitionStyle }: any) => ({ maxHeight: maxHeightInTransitionStyle });
+    componentDidMount() {
+        super.componentDidMount();
+        this.resizeObserver = new ResizeObserver(this.handleResize);
+        this.resizeObserver.observe(this.domRef.current);
+        const domInRenderTree = this.isChildrenInRenderTree();
+        this.setState({domInRenderTree})
+        if(domInRenderTree){
+            this.setState({domHeight:this.domRef.current.scrollHeight})
+        }
+    }
 
-    const shouldKeepDOM = () => keepDOM || collapseHeight !== 0;
+    componentDidUpdate(prevProps: Readonly<CollapsibleProps>, prevState: Readonly<CollapsibleState>, snapshot?: any) {
+        if(prevState.domInRenderTree!==this.state.domInRenderTree){
+            if(this.state.domInRenderTree){
+                this.setState({domHeight:this.domRef.current.scrollHeight})
+            }
+        }
+    }
 
-    const defaultMaxHeight = useMemo(() => {
-        return isOpen || !shouldKeepDOM() && !motion ? 'none' : collapseHeight;
-    }, [collapseHeight, motion, isOpen, shouldKeepDOM]);
+    handleResize = (entryList:ResizeObserverEntry[]) => {
+        const entry = entryList[0];
+        if(entry){
+            const entryInfo  = Collapsible.getEntryInfo(entry);
+            this.setState({domInRenderTree:entryInfo.isShown,domHeight:entryInfo.height})
+        }
+    }
 
-    const renderChildren = (transitionStyle: Record<string, any> | null) => {
-        const transition =
-            transitionStyle && typeof transitionStyle === 'object' ?
-                formatStyle(transitionStyle) :
-                {};
+    static getEntryInfo = (entry:ResizeObserverEntry)=>{
+        //judge whether parent or self display none
+        let inRenderTree:boolean;
+        if(entry.borderBoxSize){
+            inRenderTree= !(entry.borderBoxSize[0].blockSize===0 && entry.borderBoxSize[0].inlineSize===0);
+        }else {
+            inRenderTree = !(entry.contentRect.height===0 && entry.contentRect.width===0);
+        }
 
-        const wrapperstyle = {
-            overflow: 'hidden',
-            maxHeight: defaultMaxHeight,
-            ...style,
-            ...transition,
-        };
+        let height = 0;
+        if(entry.borderBoxSize){
+            height = Math.ceil(entry.borderBoxSize[0].blockSize);
+        }else{
+            const target = entry.target as HTMLElement;
+            height = target.clientHeight;
+        }
 
-        if (isFirst) {
-            wrapperstyle.maxHeight = defaultMaxHeight;
+        return {
+            isShown: inRenderTree,height
         }
 
-        const wrapperCls = cls(`${cssClasses.PREFIX}-wrapper`, className);
-        return (
-            <div style={wrapperstyle} className={wrapperCls} ref={ref}>
-                <div
-                    ref={setHeight}
-                    style={{ overflow: 'hidden' }} 
-                    id={id}
-                    x-semi-prop="children"
-                >
-                    {children}
-                </div>
-            </div>
-        );
-    };
 
-    const didLeave = () => {
-        setLeft(true);
-        !shouldKeepDOM() && setMaxHeight(collapseHeight);
-    };
+    }
 
-    const renderContent = () => {
-        if (left && !shouldKeepDOM()) {
-            return null;
+    isChildrenInRenderTree = ()=>{
+        if(this.domRef.current){
+            return this.domRef.current.offsetHeight >0
+        }else{
+            return false
         }
+    }
 
-        const mergedMotion = getMotionObjFromProps({
-            didEnter: resetHeight,
-            didLeave,
-            motion,
-        });
-
-        return (
-            <Transition
-                state={isOpen ? 'enter' : 'leave'}
-                immediate={transitionImmediate}
-                from={{ maxHeight: 0 }}
-                enter={{ maxHeight: { val: maxHeight, easing: ease, duration } }}
-                leave={{ maxHeight: { val: collapseHeight, easing: ease, duration } }}
-                {...mergedMotion}
+    render() {
+        const wrapperStyle:React.CSSProperties = {
+            overflow: 'hidden',
+            height: this.props.isOpen ? this.state.domHeight : 0,
+            transition: `height ${this.props.duration}ms ease-in-out`,
+            ...this.props.style
+        }
+        const wrapperCls = cls(`${cssClasses.PREFIX}-wrapper`, this.props.className);
+        return <div ref={this.wrapperRef} className={wrapperCls} style={wrapperStyle} >
+            <div
+                x-semi-prop="children"
+                ref={this.domRef}
+                style={{ overflow: 'hidden' }}
             >
-                {(transitionStyle: Record<string, any>) =>
-                    renderChildren(motion ? transitionStyle : null)
-                }
-            </Transition>
-        );
-    };
-
-    return renderContent();
-};
+                {this.props.children}
+            </div>
+        </div>
+    }
+}
 
-Collapsible.propType = {
+Collapsible.propTypes = {
     motion: PropTypes.oneOfType([PropTypes.bool, PropTypes.func, PropTypes.object]),
     children: PropTypes.node,
     isOpen: PropTypes.bool,
@@ -154,12 +144,4 @@ Collapsible.propType = {
     ]),
 };
 
-Collapsible.defaultProps = {
-    isOpen: false,
-    duration: 250,
-    motion: true,
-    keepDOM: false,
-    collapseHeight: 0
-};
-
 export default Collapsible;