@reusable-ui/collapse
Version:
A generic element with dynamic visibility (show/hide).
117 lines (116 loc) • 4.79 kB
JavaScript
// react:
import {
// react:
default as React, } from 'react';
// cssfn:
import {
// style sheets:
dynamicStyleSheet, } from '@cssfn/cssfn-react'; // writes css in react hook
// reusable-ui core:
import {
// react helper hooks:
useMergeEvents, useMergeRefs, useMergeClasses, useMergeStyles, useFloatable, useOrientationable, useCollapsible, useCollapsibleEvent, useLastKnownExpandedSize, } from '@reusable-ui/core'; // a set of reusable-ui packages which are responsible for building any component
// reusable-ui components:
import { Generic, } from '@reusable-ui/generic'; // a generic component
// internals:
import {
// defaults:
defaultOrientationableOptions, } from './defaults.js';
// styles:
export const useCollapseStyleSheet = dynamicStyleSheet(() => import(/* webpackPrefetch: true */ './styles/styles.js'), { id: 'gh2oi6zjs0' }); // a unique salt for SSR support, ensures the server-side & client-side have the same generated class names
const Collapse = (props) => {
// styles:
const styleSheet = useCollapseStyleSheet();
// variants:
const orientationableVariant = useOrientationable(props, defaultOrientationableOptions);
// states:
const collapsibleState = useCollapsible(props);
const isVisible = collapsibleState.isVisible; // visible = showing, shown, hidding ; !visible = hidden
useCollapsibleEvent(props, collapsibleState);
const lastKnownExpandedSize = useLastKnownExpandedSize(collapsibleState);
// capabilities:
/*
collapsibleState.state:
Collapsed = 0, => false => not updateFloatingPosition()
Collapsing = 1, => true => do updateFloatingPosition()
Expanding = 2, => true => do updateFloatingPosition()
Expanded = 3, => true => do updateFloatingPosition()
*/
const floatable = useFloatable(props, collapsibleState.state);
// rest props:
const {
// variants:
orientation: _orientation, // remove
// behaviors:
lazy = false,
// states:
expanded: _expanded, // remove
onExpandStart: _onExpandStart, // remove
onCollapseStart: _onCollapseStart, // remove
onExpandEnd: _onExpandEnd, // remove
onCollapseEnd: _onCollapseEnd, // remove
// floatable:
floatingRef: _floatingRef, // remove
floatingOn: _floatingOn, // remove
floatingPlacement: _floatingPlacement, // remove
floatingMiddleware: _floatingMiddleware, // remove
floatingStrategy: _floatingStrategy, // remove
floatingAutoFlip: _floatingAutoFlip, // remove
floatingAutoShift: _floatingAutoShift, // remove
floatingOffset: _floatingOffset, // remove
floatingShift: _floatingShift, // remove
onFloatingUpdate: _onFloatingUpdate, // remove
// children:
children, ...restGenericProps } = props;
// refs:
const mergedOuterRef = useMergeRefs(
// preserves the original `outerRef`:
props.outerRef, floatable.outerRef, lastKnownExpandedSize.setRef);
// classes:
const variantClasses = useMergeClasses(
// preserves the original `variantClasses`:
props.variantClasses,
// variants:
orientationableVariant.class);
const stateClasses = useMergeClasses(
// preserves the original `stateClasses`:
props.stateClasses,
// states:
collapsibleState.class);
const classes = useMergeClasses(
// preserves the original `classes`:
props.classes,
// capabilities:
floatable.classes);
// styles:
const mergedStyle = useMergeStyles(
// styles:
lastKnownExpandedSize.style,
// preserves the original `style` (can overwrite the `lastKnownExpandedSize.style`):
props.style);
// handlers:
const handleAnimationStart = useMergeEvents(
// preserves the original `onAnimationStart`:
props.onAnimationStart,
// states:
collapsibleState.handleAnimationStart);
const handleAnimationEnd = useMergeEvents(
// preserves the original `onAnimationEnd`:
props.onAnimationEnd,
// states:
collapsibleState.handleAnimationEnd);
// jsx:
return (React.createElement(Generic, { ...restGenericProps,
// refs:
outerRef: mergedOuterRef,
// semantics:
// no need to set [aria-orientation], because the expand/collapse is for styling purpose:
// aria-orientation={props['aria-orientation'] ?? orientationableVariant['aria-orientation']}
// classes:
mainClass: props.mainClass ?? styleSheet.main, variantClasses: variantClasses, stateClasses: stateClasses, classes: classes,
// styles:
style: mergedStyle, ...collapsibleState.props,
// handlers:
onAnimationStart: handleAnimationStart, onAnimationEnd: handleAnimationEnd }, (!lazy || isVisible) && children));
};
export { Collapse, Collapse as default, };