mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
feat(components): collapse component styles in progress
This commit is contained in:
parent
462597b822
commit
1a0f81c006
@ -1,8 +1,14 @@
|
||||
import {forwardRef} from "@nextui-org/system";
|
||||
import {clsx, __DEV__} from "@nextui-org/shared-utils";
|
||||
import {clsx, __DEV__, Expand} from "@nextui-org/shared-utils";
|
||||
import {mergeProps} from "@react-aria/utils";
|
||||
|
||||
import {StyledCollapseItem, StyledCollapseItemButton} from "./collapse.styles";
|
||||
import {
|
||||
StyledCollapseItem,
|
||||
StyledCollapseItemHeading,
|
||||
StyledCollapseItemButton,
|
||||
StyledCollapseItemTitle,
|
||||
StyledCollapseItemIndicator,
|
||||
} from "./collapse.styles";
|
||||
import {UseCollapseItemProps, useCollapseItem} from "./use-collapse-item";
|
||||
|
||||
export interface CollapseItemProps<T extends object = {}>
|
||||
@ -32,28 +38,32 @@ const CollapseItem = forwardRef<CollapseItemProps, "div">((props, ref) => {
|
||||
isOpen={isOpen}
|
||||
{...otherProps}
|
||||
>
|
||||
<h2 className="collapse-item-heading">
|
||||
<StyledCollapseItemHeading className="nextui-collapse-item-heading">
|
||||
<StyledCollapseItemButton
|
||||
{...mergeProps(buttonProps, focusProps)}
|
||||
ref={domRef}
|
||||
className="collapse-item-button"
|
||||
className="nextui-collapse-item-button"
|
||||
disabled={isDisabled}
|
||||
isFocusVisible={isFocusVisible}
|
||||
>
|
||||
{item.props.title}
|
||||
<span
|
||||
<StyledCollapseItemTitle className="nextui-collapse-item-title">
|
||||
{item.props.title}
|
||||
</StyledCollapseItemTitle>
|
||||
<StyledCollapseItemIndicator
|
||||
aria-hidden="true"
|
||||
aria-label="collapse item indicator"
|
||||
className="collapse-item-indicator"
|
||||
className="nextui-collapse-item-indicator"
|
||||
role="img"
|
||||
>
|
||||
{isOpen ? "🔽" : "▶️"}️
|
||||
</span>
|
||||
</StyledCollapseItemIndicator>
|
||||
</StyledCollapseItemButton>
|
||||
</h2>
|
||||
<div {...regionProps} className="collapse-item-content">
|
||||
{item.props.children}
|
||||
</div>
|
||||
</StyledCollapseItemHeading>
|
||||
<Expand isExpanded={isOpen}>
|
||||
<div {...regionProps} className="nextui-collapse-item-content">
|
||||
{item.props.children}
|
||||
</div>
|
||||
</Expand>
|
||||
</StyledCollapseItem>
|
||||
);
|
||||
});
|
||||
|
||||
@ -46,11 +46,29 @@ export const StyledCollapseItem = styled("div", {
|
||||
},
|
||||
});
|
||||
|
||||
export const StyledCollapseItemHeading = styled("h2", {});
|
||||
|
||||
export const StyledCollapseItemButton = styled(
|
||||
"button",
|
||||
{
|
||||
textAlign: "start",
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
appearance: "none",
|
||||
alignItems: "center",
|
||||
padding: "$4 $6",
|
||||
background: "transparent",
|
||||
border: "none",
|
||||
outline: "none",
|
||||
cursor: "pointer",
|
||||
},
|
||||
cssFocusVisible,
|
||||
);
|
||||
|
||||
export const StyledCollapseItemTitle = styled("div", {
|
||||
flex: "1 1 0%",
|
||||
textAlign: "left",
|
||||
});
|
||||
|
||||
export const StyledCollapseItemIndicator = styled("span", {
|
||||
flexShrink: 0,
|
||||
});
|
||||
|
||||
@ -34,6 +34,8 @@
|
||||
"postpack": "clean-package restore"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nextui-org/system": "workspace:*",
|
||||
"@nextui-org/use-real-shape": "workspace:*",
|
||||
"deepmerge": "4.2.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
96
packages/utilities/shared-utils/src/expand.tsx
Normal file
96
packages/utilities/shared-utils/src/expand.tsx
Normal file
@ -0,0 +1,96 @@
|
||||
import React, {useEffect, useRef, useState} from "react";
|
||||
import {styled, HTMLNextUIProps} from "@nextui-org/system";
|
||||
import {useRealShape} from "@nextui-org/use-real-shape";
|
||||
|
||||
export interface ExpandProps extends HTMLNextUIProps<"div"> {
|
||||
isExpanded?: boolean;
|
||||
animated?: boolean;
|
||||
delay?: number;
|
||||
}
|
||||
|
||||
const StyledExpand = styled("div", {
|
||||
p: 0,
|
||||
m: 0,
|
||||
h: 0,
|
||||
opacity: 0,
|
||||
overflow: "hidden",
|
||||
variants: {
|
||||
isExpanded: {
|
||||
true: {
|
||||
opacity: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const Expand: React.FC<ExpandProps> = ({
|
||||
css,
|
||||
children,
|
||||
delay = 200,
|
||||
animated = true,
|
||||
isExpanded = false,
|
||||
...otherProps
|
||||
}) => {
|
||||
const [height, setHeight] = useState<string>(isExpanded ? "auto" : "0");
|
||||
const [selfExpanded, setSelfExpanded] = useState<boolean>(isExpanded);
|
||||
const contentRef = useRef<HTMLDivElement>(null);
|
||||
const entryTimer = useRef<number>();
|
||||
const leaveTimer = useRef<number>();
|
||||
const resetTimer = useRef<number>();
|
||||
const [state, updateShape] = useRealShape<HTMLDivElement>(contentRef);
|
||||
|
||||
useEffect(() => setHeight(`${state.height}px`), [state.height]);
|
||||
useEffect(() => {
|
||||
if (isExpanded === selfExpanded) return;
|
||||
// show element or reset height.
|
||||
// force an update once manually, even if the element does not change.
|
||||
// (the height of the element might be "auto")
|
||||
if (!isExpanded) {
|
||||
updateShape();
|
||||
setHeight(`${state.height}px`);
|
||||
}
|
||||
|
||||
// show expand animation
|
||||
entryTimer.current = window.setTimeout(() => {
|
||||
setSelfExpanded(isExpanded);
|
||||
clearTimeout(entryTimer.current);
|
||||
}, 30);
|
||||
|
||||
// Reset height after animation
|
||||
if (isExpanded) {
|
||||
resetTimer.current = window.setTimeout(() => {
|
||||
setHeight("auto");
|
||||
clearTimeout(resetTimer.current);
|
||||
}, delay);
|
||||
} else {
|
||||
leaveTimer.current = window.setTimeout(() => {
|
||||
clearTimeout(leaveTimer.current);
|
||||
}, delay / 2);
|
||||
}
|
||||
|
||||
return () => {
|
||||
clearTimeout(entryTimer.current);
|
||||
clearTimeout(leaveTimer.current);
|
||||
clearTimeout(resetTimer.current);
|
||||
};
|
||||
}, [isExpanded]);
|
||||
|
||||
return (
|
||||
<StyledExpand
|
||||
css={{
|
||||
height: selfExpanded ? height : "0",
|
||||
transition: animated
|
||||
? `height ${delay}ms ease 0ms,
|
||||
opacity ${delay * 1.5}ms ease 0ms;`
|
||||
: "none",
|
||||
...(css as any),
|
||||
}}
|
||||
isExpanded={selfExpanded}
|
||||
{...otherProps}
|
||||
>
|
||||
<div ref={contentRef} className="nextui-expand-content">
|
||||
{children}
|
||||
</div>
|
||||
</StyledExpand>
|
||||
);
|
||||
};
|
||||
@ -13,3 +13,4 @@ export * from "./functions";
|
||||
export * from "./context";
|
||||
export * from "./numbers";
|
||||
export * from "./console";
|
||||
export * from "./expand";
|
||||
|
||||
4
pnpm-lock.yaml
generated
4
pnpm-lock.yaml
generated
@ -998,10 +998,14 @@ importers:
|
||||
|
||||
packages/utilities/shared-utils:
|
||||
specifiers:
|
||||
'@nextui-org/system': workspace:*
|
||||
'@nextui-org/use-real-shape': workspace:*
|
||||
clean-package: 2.1.1
|
||||
deepmerge: 4.2.2
|
||||
react: ^17.0.2
|
||||
dependencies:
|
||||
'@nextui-org/system': link:../../core/system
|
||||
'@nextui-org/use-real-shape': link:../../hooks/use-real-shape
|
||||
deepmerge: 4.2.2
|
||||
devDependencies:
|
||||
clean-package: 2.1.1
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user