Skip to content

Commit

Permalink
CSS animation support
Browse files Browse the repository at this point in the history
  • Loading branch information
mj12albert committed Aug 6, 2024
1 parent dff8ec6 commit 5b232a3
Show file tree
Hide file tree
Showing 16 changed files with 759 additions and 39 deletions.
149 changes: 149 additions & 0 deletions docs/data/base/components/collapsible/CssAnimatedCollapsible.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import * as React from 'react';
import { useTheme } from '@mui/system';
import * as Collapsible from '@base_ui/react/Collapsible';

export default function CssAnimatedCollapsible() {
return (
<div className="CssAnimatedCollapsible">
<Collapsible.Root>
<Collapsible.Trigger className="CssAnimatedCollapsible-trigger">
<span className="icon">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 80 80"
focusable="false"
>
<path d="M70.3 13.8L40 66.3 9.7 13.8z" />
</svg>
</span>
Trigger
</Collapsible.Trigger>
<Collapsible.Content className="CssAnimatedCollapsible-content">
<p>This is the collapsed content</p>
<p>This is the second paragraph</p>
<p>This is a longer sentence and also the third paragraph</p>
</Collapsible.Content>
</Collapsible.Root>
<Styles />
</div>
);
}

const grey = {
50: '#F3F6F9',
100: '#E5EAF2',
200: '#DAE2ED',
300: '#C7D0DD',
400: '#B0B8C4',
500: '#9DA8B7',
600: '#6B7A90',
700: '#434D5B',
800: '#303740',
900: '#1C2025',
};

function useIsDarkMode() {
const theme = useTheme();
return theme.palette.mode === 'dark';
}

export function Styles() {
const isDarkMode = useIsDarkMode();
return (
<style suppressHydrationWarning>{`
.CssAnimatedCollapsible {
font-family: system-ui, sans-serif;
line-height: 1.4;
width: 480px;
}
.CssAnimatedCollapsible h3 {
color: ${isDarkMode ? 'cyan' : 'blue'};
}
.CssAnimatedCollapsible-trigger {
border: .1em solid #ccc;
padding: .5em 1em .5em .5em;
font: inherit;
background-color: ${grey[50]};
border-radius: .5em .5em 0 0;
}
.CssAnimatedCollapsible-trigger .icon {
display: inline-block;
font-size: 60%;
color: #000;
background-color: #00f;
padding: 0.3em 0.2em 0 0.2em;
border: 0.2em solid #00f;
border-radius: 50%;
line-height: 1;
text-align: center;
text-indent: 0;
transform: rotate(270deg);
margin-right: 0.6em;
}
.CssAnimatedCollapsible-trigger svg {
width: 1.25em;
height: 1.25em;
fill: #fff;
transition: transform 0.2s ease-in;
transform-origin: center 45%;
}
.CssAnimatedCollapsible-trigger:hover,
.CssAnimatedCollapsible-trigger:focus-visible {
background-color: #666;
color: #fff;
outline: none;
border-color: #666;
}
.CssAnimatedCollapsible-trigger:hover .icon,
.CssAnimatedCollapsible-trigger:focus-visible .icon {
background-color: #fff;
outline: none;
}
.CssAnimatedCollapsible-trigger:hover svg,
.CssAnimatedCollapsible-trigger:focus-visible svg {
fill: #00f;
}
.CssAnimatedCollapsible-trigger[data-state="open"] svg {
transform: rotate(90deg);
}
.CssAnimatedCollapsible-content {
background-color: #eaeaea;
overflow: hidden;
}
.CssAnimatedCollapsible-content[data-state='open'] {
animation: slideDown 600ms ease-out;
}
.CssAnimatedCollapsible-content[data-state='closed'] {
animation: slideUp 600ms ease-out;
}
@keyframes slideDown {
from {
height: 0;
}
to {
height: var(--collapsible-content-height);
}
}
@keyframes slideUp {
from {
height: var(--collapsible-content-height);
}
to {
height: 0;
}
}
`}</style>
);
}
149 changes: 149 additions & 0 deletions docs/data/base/components/collapsible/CssAnimatedCollapsible.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import * as React from 'react';
import { useTheme } from '@mui/system';
import * as Collapsible from '@base_ui/react/Collapsible';

export default function CssAnimatedCollapsible() {
return (
<div className="CssAnimatedCollapsible">
<Collapsible.Root>
<Collapsible.Trigger className="CssAnimatedCollapsible-trigger">
<span className="icon">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 80 80"
focusable="false"
>
<path d="M70.3 13.8L40 66.3 9.7 13.8z" />
</svg>
</span>
Trigger
</Collapsible.Trigger>
<Collapsible.Content className="CssAnimatedCollapsible-content">
<p>This is the collapsed content</p>
<p>This is the second paragraph</p>
<p>This is a longer sentence and also the third paragraph</p>
</Collapsible.Content>
</Collapsible.Root>
<Styles />
</div>
);
}

const grey = {
50: '#F3F6F9',
100: '#E5EAF2',
200: '#DAE2ED',
300: '#C7D0DD',
400: '#B0B8C4',
500: '#9DA8B7',
600: '#6B7A90',
700: '#434D5B',
800: '#303740',
900: '#1C2025',
};

function useIsDarkMode() {
const theme = useTheme();
return theme.palette.mode === 'dark';
}

export function Styles() {
const isDarkMode = useIsDarkMode();
return (
<style suppressHydrationWarning>{`
.CssAnimatedCollapsible {
font-family: system-ui, sans-serif;
line-height: 1.4;
width: 480px;
}
.CssAnimatedCollapsible h3 {
color: ${isDarkMode ? 'cyan' : 'blue'};
}
.CssAnimatedCollapsible-trigger {
border: .1em solid #ccc;
padding: .5em 1em .5em .5em;
font: inherit;
background-color: ${grey[50]};
border-radius: .5em .5em 0 0;
}
.CssAnimatedCollapsible-trigger .icon {
display: inline-block;
font-size: 60%;
color: #000;
background-color: #00f;
padding: 0.3em 0.2em 0 0.2em;
border: 0.2em solid #00f;
border-radius: 50%;
line-height: 1;
text-align: center;
text-indent: 0;
transform: rotate(270deg);
margin-right: 0.6em;
}
.CssAnimatedCollapsible-trigger svg {
width: 1.25em;
height: 1.25em;
fill: #fff;
transition: transform 0.2s ease-in;
transform-origin: center 45%;
}
.CssAnimatedCollapsible-trigger:hover,
.CssAnimatedCollapsible-trigger:focus-visible {
background-color: #666;
color: #fff;
outline: none;
border-color: #666;
}
.CssAnimatedCollapsible-trigger:hover .icon,
.CssAnimatedCollapsible-trigger:focus-visible .icon {
background-color: #fff;
outline: none;
}
.CssAnimatedCollapsible-trigger:hover svg,
.CssAnimatedCollapsible-trigger:focus-visible svg {
fill: #00f;
}
.CssAnimatedCollapsible-trigger[data-state="open"] svg {
transform: rotate(90deg);
}
.CssAnimatedCollapsible-content {
background-color: #eaeaea;
overflow: hidden;
}
.CssAnimatedCollapsible-content[data-state='open'] {
animation: slideDown 600ms ease-out;
}
.CssAnimatedCollapsible-content[data-state='closed'] {
animation: slideUp 600ms ease-out;
}
@keyframes slideDown {
from {
height: 0;
}
to {
height: var(--collapsible-content-height);
}
}
@keyframes slideUp {
from {
height: var(--collapsible-content-height);
}
to {
height: 0;
}
}
`}</style>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import * as React from 'react';
import { styled, useTheme, Box } from '@mui/system';
import * as BaseCollapsible from '@base_ui/react/Collapsible';

const Collapsible = BaseCollapsible.Root;

const CollapsibleTrigger = styled(BaseCollapsible.Trigger)`
display: flex;
flex-flow: row nowrap;
justify-content: center;
gap: 4px;
font-size: 16px;
& svg {
margin-top: 1px;
}
&[data-state='open'] svg {
transform: rotate(180deg);
}
`;

const CollapsibleContent = styled(BaseCollapsible.Content)``;

export default function UnstyledCollapsibleIntroduction() {
// Replace this with your app logic for determining dark mode
const isDarkMode = useIsDarkMode();
const [open, setOpen] = React.useState(true);
return (
<Box
className={isDarkMode ? 'dark' : ''}
sx={{ width: 480, fontFamily: 'IBM Plex Sans, sans-serif' }}
>
<Collapsible open={open} onOpenChange={setOpen}>
<CollapsibleTrigger>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
width="16"
height="16"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="m19.5 8.25-7.5 7.5-7.5-7.5"
/>
</svg>
Show {open ? 'less' : 'more'}
</CollapsibleTrigger>
<CollapsibleContent>
<p>
This is the collapsed content. The element that shows and hides the
content has role button
</p>
<p>
When the content is visible, the element with role `button` has
`aria-expanded` set to `true`
</p>
<p>When the content area is hidden, it is set to `false`</p>
<p>
Optionally, the element with role `button` has a value specified for
`aria-controls` that refers to the element that contains all the content
that is shown or hidden
</p>
</CollapsibleContent>
</Collapsible>
</Box>
);
}

function useIsDarkMode() {
const theme = useTheme();
return theme.palette.mode === 'dark';
}
Loading

0 comments on commit 5b232a3

Please sign in to comment.