Skip to content
This repository has been archived by the owner on Mar 13, 2024. It is now read-only.

Commit

Permalink
[MM-27305] Card Component Refactor for smoothness (#6172)
Browse files Browse the repository at this point in the history
* Refactor Card component to be more responsive and robust

* Cleanup and a couple other bug fixes
  • Loading branch information
devinbinnie committed Aug 19, 2020
1 parent 200fd7c commit 396ab95
Show file tree
Hide file tree
Showing 13 changed files with 118 additions and 155 deletions.
43 changes: 42 additions & 1 deletion components/card/__snapshots__/card.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ exports[`components/card/card should match snapshot 1`] = `
key=".1"
>
<div
className="Card__body"
className="Card__body expanding"
onTransitionEnd={[Function]}
style={
Object {
"height": "",
Expand All @@ -35,3 +36,43 @@ exports[`components/card/card should match snapshot 1`] = `
</div>
</Card>
`;

exports[`components/card/card should match snapshot when expanded 1`] = `
<Card
expanded={true}
>
<div
className="Card expanded"
>
<CardHeader
expanded={true}
key=".0"
>
<div
className="Card__header expanded"
>
Header Test
<hr
className="Card__hr"
/>
</div>
</CardHeader>
<CardBody
expanded={true}
key=".1"
>
<div
className="Card__body expanded expanding"
onTransitionEnd={[Function]}
style={
Object {
"height": 0,
}
}
>
Body Test
</div>
</CardBody>
</div>
</Card>
`;
20 changes: 14 additions & 6 deletions components/card/card.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,29 @@
}

.Card__header {
hr.Card__hr {
margin: 0 12px;
border-color: rgba(var(--center-channel-color-rgb), 0.08);
}
}

.Card__body {
overflow: hidden;
height: 0;
margin: 0 12px;

transition-duration: 0.3s;
transition-timing-function: ease-in-out;
transition-property: height, margin;
&.expanding {
transition-duration: 0.3s;
transition-timing-function: ease-in-out;
transition-property: height, margin;
}

&.expanded {
margin: 0 12px 12px 12px;
padding-top: 12px;
border-top: 1px solid rgba(var(--center-channel-color-rgb), 0.08);
margin: 12px;
}

&.expanded:not(.expanding) {
height: auto;
}
}

Expand Down
27 changes: 13 additions & 14 deletions components/card/card.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,27 @@ describe('components/card/card', () => {
test('should match snapshot', () => {
const wrapper = mount(
<Card {...baseProps}>
<Card.Header {...baseProps}>{'Header Test'}</Card.Header>
<Card.Body {...baseProps}>{'Body Test'}</Card.Body>
<Card.Header>{'Header Test'}</Card.Header>
<Card.Body>{'Body Test'}</Card.Body>
</Card>
);

expect(wrapper).toMatchSnapshot();
});

test('should have a height based on content when expanded', () => {
test('should match snapshot when expanded', () => {
const props = {
...baseProps,
expanded: true,
};

const wrapper = mount(
<Card.Body {...baseProps}>
{'Body Test'}
{'Slightly Larger Body Text'}
</Card.Body>
<Card {...props}>
<Card.Header>{'Header Test'}</Card.Header>
<Card.Body>{'Body Test'}</Card.Body>
</Card>
);

expect(wrapper.find('.Card__body').prop('style')).toHaveProperty('height', '');

wrapper.setProps({expanded: true});
expect(wrapper.find('.Card__body').prop('style')).not.toHaveProperty('height', '');

wrapper.setProps({expanded: false});
expect(wrapper.find('.Card__body').prop('style')).toHaveProperty('height', '');
expect(wrapper).toMatchSnapshot();
});
});
37 changes: 22 additions & 15 deletions components/card/card_body.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,45 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import React, {useState, useEffect, useRef} from 'react';
import React, {useState, useEffect} from 'react';
import classNames from 'classnames';

import './card.scss';

export default function CardBody(props: {expanded?: boolean; children: React.ReactNode}) {
const card = useRef<HTMLDivElement>(null);
const [height, setHeight] = useState<number | undefined>(0);
const [height, setHeight] = useState(0);
const [expanding, setExpanding] = useState(false);
const [expanded, setExpanded] = useState(false);

let hasListener = false;
const onChange = () => setHeight(card.current?.scrollHeight);
const stopExpanding = () => setExpanding(false);

useEffect(() => {
if (hasListener) {
window.removeEventListener('resize', onChange);
} else {
window.addEventListener('resize', onChange);
hasListener = true;
const card = (node: HTMLDivElement) => {
if (node && node.children) {
setHeight(Array.from(node.children).map((child) => child.scrollHeight).reduce((a, b) => a + b, 0));
}
}, []);
};

useEffect(() => {
onChange();
setExpanding(true);
if (props.expanded) {
setExpanded(true);
}
}, [props.expanded]);

useEffect(() => {
if (!props.expanded) {
setExpanded(false);
}
}, [expanding]);

return (
<div
ref={card}
style={{
height: props.expanded ? height : '',
height: (expanding && expanded) ? height : '',
}}
className={classNames('Card__body', {expanded: props.expanded})}
className={classNames('Card__body', {expanded, expanding})}
onTransitionEnd={stopExpanding}
>
{props.children}
</div>
Expand Down
1 change: 1 addition & 0 deletions components/card/card_header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const CardHeader: React.FC<Props> = (props: Props) => {
return (
<div className={classNames('Card__header', {expanded: props.expanded})}>
{props.children}
{props.expanded && <hr className='Card__hr'/>}
</div>
);
};
Expand Down
11 changes: 6 additions & 5 deletions components/next_steps_view/next_steps_view.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
height: 100%;
width: 100%;
transition: left 0.5s ease-in;
overflow-y: auto;
overflow-x: hidden;
display: flex;
flex-direction: column;
}

.NextStepsView__mainView {
Expand Down Expand Up @@ -65,6 +69,7 @@
.NextStepsView__header {
padding: 32px 40px 24px 40px;
display: flex;
flex-grow: 0;
}

.NextStepsView__header-headerText {
Expand Down Expand Up @@ -92,6 +97,7 @@
.NextStepsView__body {
display: flex;
height: 100%;
flex-grow: 1;
}

.NextStepsView__body-main {
Expand Down Expand Up @@ -505,11 +511,6 @@
.NextStepsView__body {
height: auto;
}

.NextStepsView__viewWrapper {
overflow-y: auto;
overflow-x: hidden;
}
}

@media screen and (max-width: 1020px) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ exports[`components/next_steps_view/steps/complete_profile_step should match sna
/>
</div>
</div>
<span
className="CompleteProfileStep__pictureError"
/>
<div
className="NextStepsView__wizardButtons"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

.PictureSelector {
margin-top: 12px;
min-height: 125px;
}
}

Expand Down Expand Up @@ -50,7 +49,6 @@
line-height: 16px;
color: var(--error-text);
padding: 0 40px;
min-height: 16px;

> span {
margin-left: 4px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,28 +134,17 @@ export default class CompleteProfileStep extends React.PureComponent<Props, Stat
/>
</div>
</div>
<span className='CompleteProfileStep__pictureError'>
{this.state.profilePictureError && (
<>
<i className='icon icon-alert-outline'/>
<FormattedMarkdownMessage
id='next_steps_view.complete_profile_step.pictureError'
defaultMessage='Photos must be in BMP, JPG or PNG format. Maximum file size is {max}.'
values={{max: Utils.fileSizeToString(this.props.maxFileSize)}}
/>
</>
)}
</span>
<div className='NextStepsView__wizardButtons'>
{/* <button
className='NextStepsView__button cancel'
onClick={this.onSkip}
>
<FormattedMessage
id='next_steps_view.skipForNow'
defaultMessage='Skip for now'
{this.state.profilePictureError &&
<span className='CompleteProfileStep__pictureError'>
<i className='icon icon-alert-outline'/>
<FormattedMarkdownMessage
id='next_steps_view.complete_profile_step.pictureError'
defaultMessage='Photos must be in BMP, JPG or PNG format. Maximum file size is {max}.'
values={{max: Utils.fileSizeToString(this.props.maxFileSize)}}
/>
</button> */}
</span>
}
<div className='NextStepsView__wizardButtons'>
<button
className={classNames('NextStepsView__button NextStepsView__finishButton primary', {disabled: this.isFinishDisabled()})}
onClick={this.onFinish}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,53 +62,6 @@
}
}

.InviteMembersStep__profilePicture {
flex-grow: 0;

.PictureSelector {
margin-top: 12px;
min-height: 125px;
}
}

.InviteMembersStep__fullName {
margin-left: 64px;
flex-grow: 0.75;
max-width: 600px;

.Input {
font-size: 14px;
line-height: 38px;
padding: 0 16px;
}

.Input_legend {
margin-left: 12px;
}

.Input_container {
margin-top: 28px;
}
}

.InviteMembersStep__pictureError {
font-size: 12px;
line-height: 16px;
color: var(--error-text);
padding: 0 40px;
min-height: 16px;

> span {
margin-left: 4px;
}

i {
font-size: 14px;
vertical-align: middle;
margin-top: -2px;
}
}

.InviteMembersStep__send {
display: flex;
margin-top: 8px;
Expand Down Expand Up @@ -185,14 +138,4 @@
flex-direction: column;
padding: 4px 12px 24px 12px;
}

.InviteMembersStep__fullName {
margin-left: 0;
margin-top: 32px;
max-width: unset;

.Input_container {
margin-top: 20px;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,6 @@ exports[`components/next_steps_view/steps/team_profile_step should match snapsho
/>
</div>
</div>
<span
className="TeamProfileStep__pictureError"
/>
<div
className="NextStepsView__wizardButtons"
>
Expand Down
Loading

0 comments on commit 396ab95

Please sign in to comment.