Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions UNRELEASED.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Enhancements

- Added optional `onClick` prop to `Tag` ([#2774](https://github.com/Shopify/polaris-react/pull/2774))
- Added transition properties to `Collapsible` ([#2835](https://github.com/Shopify/polaris-react/pull/2835))

### Bug fixes

Expand Down
23 changes: 21 additions & 2 deletions src/components/Collapsible/Collapsible.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,20 @@ import {classNames} from '../../utilities/css';

import styles from './Collapsible.scss';

interface Transition {
/** Assign a transition duration to the collapsible animation. */
duration?: string;
/** Assign a transition timing function to the collapsible animation */
timingFunction?: string;
}

export interface CollapsibleProps {
/** Assign a unique ID to the collapsible. For accessibility, pass this ID as the value of the triggering component’s aria-controls prop. */
id: string;
/** Toggle whether the collapsible is expanded or not. */
open: boolean;
/** Assign transition properties to the collapsible */
transition?: Transition;
/** The content to display inside the collapsible. */
children?: React.ReactNode;
}
Expand Down Expand Up @@ -104,7 +113,7 @@ class CollapsibleInner extends React.Component<CollapsibleProps, State> {
}

render() {
const {id, open, children} = this.props;
const {id, open, children, transition} = this.props;
const {animationState, height} = this.state;
const parentCollapsibleExpanding = this.context;

Expand All @@ -121,6 +130,13 @@ class CollapsibleInner extends React.Component<CollapsibleProps, State> {

const content = animating || open ? children : null;

const transitionProperties = transition
? {
transitionDuration: `${transition.duration}`,
transitionTimingFunction: `${transition.timingFunction}`,
}
: null;

return (
<ParentCollapsibleExpandingContext.Provider
value={
Expand All @@ -130,7 +146,10 @@ class CollapsibleInner extends React.Component<CollapsibleProps, State> {
<div
id={id}
aria-hidden={!open}
style={{maxHeight: displayHeight}}
style={{
maxHeight: `${displayHeight}`,
...transitionProperties,
}}
className={wrapperClassName}
ref={this.node}
onTransitionEnd={this.handleTransitionEnd}
Expand Down
6 changes: 5 additions & 1 deletion src/components/Collapsible/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,11 @@ function CollapsibleExample() {
>
Toggle
</Button>
<Collapsible open={active} id="basic-collapsible">
<Collapsible
open={active}
id="basic-collapsible"
transition={{duration: '150ms', timingFunction: 'ease'}}
>
<TextContainer>
Your mailing list lets you contact customers or visitors who have
shown an interest in your store. Reach out to them with exclusive
Expand Down
25 changes: 25 additions & 0 deletions src/components/Collapsible/tests/Collapsible.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
// eslint-disable-next-line no-restricted-imports
import {mountWithAppProvider} from 'test-utilities/legacy';
import {Tokens} from 'utilities/theme';
import {Collapsible} from '../Collapsible';

describe('<Collapsible />', () => {
Expand Down Expand Up @@ -44,4 +45,28 @@ describe('<Collapsible />', () => {
expect(hidden.exists()).toBe(false);
expect(collapsible.contains('content')).toBe(true);
});

describe('Transition', () => {
it('passes a duration property', () => {
const duration = Tokens.duration150;
const collapsible = mountWithAppProvider(
<Collapsible id="test-collapsible" open transition={{duration}} />,
);

expect(collapsible.props()).toMatchObject({transition: {duration}});
});

it('passes a timingFunction property', () => {
const timingFunction = Tokens.ease;
const collapsible = mountWithAppProvider(
<Collapsible
id="test-collapsible"
open
transition={{timingFunction}}
/>,
);

expect(collapsible.props()).toMatchObject({transition: {timingFunction}});
});
});
});