Skip to content

Commit

Permalink
[Collapsible] Add horizontal variant (#11967)
Browse files Browse the repository at this point in the history
### WHY are these changes introduced?

Part of Shopify/archive-polaris-backlog-2024#1606

While prototyping multiple options for x-axis animations I realized I
was getting into a lot of what collapsible already does.

TIL: `transform` animations don't affect layouts, which is why they're
less expensive but won't work in our use case.

<!--
  Context about the problem that’s being addressed.
-->

### WHAT is this pull request doing?

<!--
  Summary of the changes committed.

Before / after screenshots are appreciated for UI changes. Make sure to
include alt text that describes the screenshot.

  Include a video if your changes include interactive content.

If you include an animated gif showing your change, wrapping it in a
details tag is recommended. Gifs usually autoplay, which can cause
accessibility issues for people reviewing your PR:

  <details>
    <summary>Summary of your gif(s)</summary>
    <img src="..." alt="Description of what the gif shows">
  </details>
-->

### How to 🎩

🖥 [Local development
instructions](https://github.com/Shopify/polaris/blob/main/README.md#install-dependencies-and-build-workspaces)
🗒 [General tophatting
guidelines](https://github.com/Shopify/polaris/blob/main/documentation/Tophatting.md)
📄 [Changelog
guidelines](https://github.com/Shopify/polaris/blob/main/.github/CONTRIBUTING.md#changelog)

### 🎩 checklist

- [ ] Tested a
[snapshot](https://github.com/Shopify/polaris/blob/main/documentation/Releasing.md#-snapshot-releases)
- [ ] Tested on
[mobile](https://github.com/Shopify/polaris/blob/main/documentation/Tophatting.md#cross-browser-testing)
- [ ] Tested on [multiple
browsers](https://help.shopify.com/en/manual/shopify-admin/supported-browsers)
- [ ] Tested for
[accessibility](https://github.com/Shopify/polaris/blob/main/documentation/Accessibility%20testing.md)
- [ ] Updated the component's `README.md` with documentation changes
- [ ] [Tophatted
documentation](https://github.com/Shopify/polaris/blob/main/documentation/Tophatting%20documentation.md)
changes in the style guide
  • Loading branch information
kyledurand committed May 2, 2024
1 parent d1d69e9 commit e50472f
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 13 deletions.
5 changes: 5 additions & 0 deletions .changeset/strong-experts-remember.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/polaris': minor
---

Added `variant` prop to Collapsible
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
padding-bottom: 0;
max-height: 0;
overflow: hidden;
will-change: max-height;
transition-property: max-height;
transition-duration: var(--p-motion-duration-100);
transition-timing-function: var(--p-motion-ease-out);
Expand All @@ -18,7 +17,14 @@
@media print {
/* stylelint-disable-next-line declaration-no-important -- generated by polaris-migrator DO NOT COPY */
max-height: none !important;
/* stylelint-disable-next-line declaration-no-important -- generated by polaris-migrator DO NOT COPY */
max-width: none !important;
overflow: visible;
display: block;
}
}

.inline {
max-height: none;
transition-property: max-width;
}
28 changes: 28 additions & 0 deletions polaris-react/src/components/Collapsible/Collapsible.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,31 @@ export const Default = {
);
},
};
export const Inline = {
render() {
const [open, setOpen] = useState(true);

const handleToggle = useCallback(() => setOpen((open) => !open), []);

return (
<div style={{height: '200px'}}>
<LegacyCard sectioned>
<LegacyStack alignment="center">
<Button
onClick={handleToggle}
ariaExpanded={open}
ariaControls="basic-collapsible"
>
Toggle
</Button>
<Collapsible open={open} id="inline-collapsible" variant="inline">
<p style={{whiteSpace: 'nowrap', backgroundColor: 'red'}}>
Non breaking text
</p>
</Collapsible>
</LegacyStack>
</LegacyCard>
</div>
);
},
};
55 changes: 43 additions & 12 deletions polaris-react/src/components/Collapsible/Collapsible.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ export interface CollapsibleProps {
expandOnPrint?: boolean;
/** Toggle whether the collapsible is expanded or not. */
open: boolean;
/** The direction the collapsible collapses in.
* @default 'block'
*/
variant?: 'block' | 'inline';
/** Override transition properties. When set to false, disables transition completely.
* @default transition={{duration: 'var(--p-motion-duration-150)', timingFunction: 'var(--p-motion-ease-in-out)'}}
*/
Expand All @@ -34,23 +38,26 @@ export function Collapsible({
id,
expandOnPrint,
open,
variant = 'block',
transition = true,
children,
onAnimationEnd,
}: CollapsibleProps) {
const [height, setHeight] = useState(0);
const [size, setSize] = useState(0);
const [isOpen, setIsOpen] = useState(open);
const [animationState, setAnimationState] = useState<AnimationState>('idle');
const collapsibleContainer = useRef<HTMLDivElement>(null);

const isFullyOpen = animationState === 'idle' && open && isOpen;
const isFullyClosed = animationState === 'idle' && !open && !isOpen;
const content = expandOnPrint || !isFullyClosed ? children : null;
const vertical = variant === 'block';

const wrapperClassName = classNames(
styles.Collapsible,
isFullyClosed && styles.isFullyClosed,
expandOnPrint && styles.expandOnPrint,
variant === 'inline' && styles.inline,
);

const transitionDisabled = isTransitionDisabled(transition);
Expand All @@ -62,10 +69,15 @@ export function Collapsible({

const collapsibleStyles = {
...transitionStyles,
...{
maxHeight: isFullyOpen ? 'none' : `${height}px`,
overflow: isFullyOpen ? 'visible' : 'hidden',
},
...(vertical
? {
maxHeight: isFullyOpen ? 'none' : `${size}px`,
overflow: isFullyOpen ? 'visible' : 'hidden',
}
: {
maxWidth: isFullyOpen ? 'auto' : `${size}px`,
overflow: isFullyOpen ? 'visible' : 'hidden',
}),
};

const handleCompleteAnimation = useCallback(
Expand All @@ -85,14 +97,18 @@ export function Collapsible({
setAnimationState('idle');

if (open && collapsibleContainer.current) {
setHeight(collapsibleContainer.current.scrollHeight);
setSize(
vertical
? collapsibleContainer.current.scrollHeight
: collapsibleContainer.current.scrollWidth,
);
} else {
setHeight(0);
setSize(0);
}
} else {
setAnimationState('measuring');
}
}, [open, transitionDisabled]);
}, [open, vertical, transitionDisabled]);

useEffect(() => {
if (open !== isOpen) {
Expand All @@ -105,7 +121,11 @@ export function Collapsible({
useEffect(() => {
if (!open || !collapsibleContainer.current) return;
// If collapsible defaults to open, set an initial height
setHeight(collapsibleContainer.current.scrollHeight);
setSize(
vertical
? collapsibleContainer.current.scrollHeight
: collapsibleContainer.current.scrollWidth,
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

Expand All @@ -116,13 +136,24 @@ export function Collapsible({
case 'idle':
break;
case 'measuring':
setHeight(collapsibleContainer.current.scrollHeight);
setSize(
vertical
? collapsibleContainer.current.scrollHeight
: collapsibleContainer.current.scrollWidth,
);
setAnimationState('animating');
break;
case 'animating':
setHeight(open ? collapsibleContainer.current.scrollHeight : 0);
setSize(
// eslint-disable-next-line no-nested-ternary
open
? vertical
? collapsibleContainer.current.scrollHeight
: collapsibleContainer.current.scrollWidth
: 0,
);
}
}, [animationState, open, isOpen]);
}, [animationState, vertical, open, isOpen]);

return (
<div
Expand Down

0 comments on commit e50472f

Please sign in to comment.