Skip to content

Commit

Permalink
Optionally delay entering/starting transition status
Browse files Browse the repository at this point in the history
  • Loading branch information
mj12albert committed Nov 28, 2024
1 parent bfd7f52 commit 0d49af3
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 4 deletions.
77 changes: 77 additions & 0 deletions docs/src/app/experiments/collapsible-transitions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
'use client';
import * as React from 'react';
import { Collapsible } from '@base-ui-components/react/collapsible';
import classes from './collapsible.module.css';

function classNames(...c: Array<string | undefined | null | false>) {
return c.filter(Boolean).join(' ');
}

export default function CollapsibleTransitions() {
return (
<div className={classes.grid}>
<div>
<Collapsible.Root defaultOpen={false}>
<Collapsible.Trigger className={classes.trigger}>
<ExpandMoreIcon className={classes.icon} />
Trigger 1A
</Collapsible.Trigger>
<Collapsible.Panel
className={classNames(classes.panel, classes.transition)}
>
<p>This is the collapsed content</p>
<p>
You can find the Base UI repository{' '}
<a
href="https://github.com/mui/base-ui"
target="_blank"
rel="noreferrer noopener"
>
here
</a>
</p>
</Collapsible.Panel>
</Collapsible.Root>
</div>

<div>
<Collapsible.Root>
<Collapsible.Trigger className={classes.trigger}>
<ExpandMoreIcon className={classes.icon} />
Trigger 1B
</Collapsible.Trigger>
<Collapsible.Panel
className={classNames(classes.panel, classes.transition)}
>
<p>This is the collapsed content</p>
<p>
You can find the Base UI repository{' '}
<a
href="https://github.com/mui/base-ui"
target="_blank"
rel="noreferrer noopener"
>
here
</a>
</p>
</Collapsible.Panel>
</Collapsible.Root>
</div>
</div>
);
}

function ExpandMoreIcon(props: React.SVGProps<SVGSVGElement>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
{...props}
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
>
<path d="M16.59 8.59 12 13.17 7.41 8.59 6 10l6 6 6-6z" fill="currentColor" />
</svg>
);
}
12 changes: 12 additions & 0 deletions docs/src/app/experiments/collapsible.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,15 @@
height: 0;
}
}

.grid {
--width: 320px;
--duration: 2000ms;

font-family: system-ui, sans-serif;
line-height: 1.4;

display: grid;
grid: var(--width) var(--width) / var(--width) var(--width);
grid-gap: 4rem;
}
2 changes: 1 addition & 1 deletion packages/react/src/collapsible/root/useCollapsibleRoot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function useCollapsibleRoot(
state: 'open',
});

const { mounted, setMounted, transitionStatus } = useTransitionStatus(open, animated);
const { mounted, setMounted, transitionStatus } = useTransitionStatus(open, animated, true);

const [panelId, setPanelId] = React.useState<string | undefined>(useId());

Expand Down
13 changes: 10 additions & 3 deletions packages/react/src/utils/useTransitionStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ export type TransitionStatus = 'entering' | 'exiting' | undefined;
* Provides a status string for CSS animations.
* @param open - a boolean that determines if the element is open.
* @param enabled - a boolean that determines if the logic is enabled.
* @param delayStartingStatus - a boolean that set the `entering` status one
* tick later. For edge cases e.g. collapsible needs an extra frame in order
* to measure the panel contents.
* @ignore - internal hook.
*/
export function useTransitionStatus(open: boolean, enabled = true) {
export function useTransitionStatus(open: boolean, enabled = true, delayStartingStatus = false) {
const [transitionStatus, setTransitionStatus] = React.useState<TransitionStatus>();
const [mounted, setMounted] = React.useState(open);

Expand All @@ -19,7 +22,7 @@ export function useTransitionStatus(open: boolean, enabled = true) {
if (enabled) {
if (open && !mounted) {
setMounted(true);
if (transitionStatus !== 'entering') {
if (transitionStatus !== 'entering' && !delayStartingStatus) {
setTransitionStatus('entering');
}
}
Expand All @@ -38,14 +41,18 @@ export function useTransitionStatus(open: boolean, enabled = true) {
return undefined;
}

if (delayStartingStatus) {
setTransitionStatus('entering');
}

const frame = requestAnimationFrame(() => {
setTransitionStatus(undefined);
});

return () => {
cancelAnimationFrame(frame);
};
}, [enabled, open]);
}, [enabled, open, delayStartingStatus]);

return React.useMemo(
() => ({
Expand Down

0 comments on commit 0d49af3

Please sign in to comment.