Skip to content

Commit

Permalink
Merge pull request #487 from appfolio/dreamFixAnnoyances
Browse files Browse the repository at this point in the history
Squelch console warnings and add an `onToggle` for `Alert`
  • Loading branch information
gthomas-appfolio authored Oct 26, 2018
2 parents 455f92a + 9bb8ff2 commit 188066c
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 50 deletions.
4 changes: 4 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"singleQuote": true
}

1 change: 1 addition & 0 deletions src/components/Alert.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ interface AlertProps {
dismissible?: boolean;
icon?: boolean;
className?: string;
onToggle?: (boolean) => any
}

declare class Alert extends React.Component<AlertProps, {}> { }
Expand Down
35 changes: 26 additions & 9 deletions src/components/Alert.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,17 @@ export default class Alert extends React.Component {
color: PropTypes.string,
dismissible: PropTypes.bool,
icon: PropTypes.bool,
className: PropTypes.string
}
className: PropTypes.string,
onToggle: PropTypes.func
};

static defaultProps = {
className: '',
color: 'warning',
dismissible: false,
icon: false
}
icon: false,
onToggle: () => {}
};

static displayName = 'Alert';

Expand All @@ -37,15 +39,24 @@ export default class Alert extends React.Component {
}

toggle = () => {
this.setState({ visible: !this.state.visible });
}
const visible = !this.state.visible;
this.setState({ visible });
this.props.onToggle(visible);
};

componentWillReceiveProps() {
this.setState({ visible: true });
}

render() {
const { color, children, className, dismissible, icon, ...props } = this.props;
const {
color,
children,
className,
dismissible,
icon,
...props
} = this.props;

return (
<AlertComponent
Expand All @@ -56,8 +67,14 @@ export default class Alert extends React.Component {
{...props}
>
<div className="d-flex align-items-start">
{icon ? <Icon name={ICON_MAP[color]} size="lg" className="mr-3 mt-1" /> : null}
{icon ? <div style={{ overflow: 'hidden' }}>{children}</div> : <div>{children}</div>}
{icon ? (
<Icon name={ICON_MAP[color]} size="lg" className="mr-3 mt-1" />
) : null}
{icon ? (
<div style={{ overflow: 'hidden' }}>{children}</div>
) : (
<div>{children}</div>
)}
</div>
</AlertComponent>
);
Expand Down
36 changes: 23 additions & 13 deletions src/components/FormRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,22 @@ const typeTranslations = {
};

function determineElement(type) {
return (typeof type === 'string') ?
typeTranslations[type] || Input :
type;
return typeof type === 'string' ? typeTranslations[type] || Input : type;
}

function parseFeedback(feedback) {
return typeof feedback === 'object' ?
[null, { error: feedback }] :
[feedback, {}];
return typeof feedback === 'object'
? [null, { error: feedback }]
: [feedback, {}];
}

function sanitizeProps(component, props) {
if (!component.props) return props;
const saneProps = {};
Object.entries(props).forEach(([k, v]) => {
if (component.props[k]) saneProps[k] = v;
});
return saneProps;
}

const FormRow = (props) => {
Expand All @@ -49,6 +56,11 @@ const FormRow = (props) => {

const [baseFeedback, childFeedback] = parseFeedback(feedback);

const validityThings = sanitizeProps(InputElement, {
valid: !!validFeedback,
invalid: !!feedback
});

return (
<FormLabelGroup
feedback={baseFeedback}
Expand All @@ -68,23 +80,21 @@ const FormRow = (props) => {
id={id}
size={size}
type={typeof type === 'string' ? type : null}
valid={!!validFeedback}
invalid={!!feedback}
{...validityThings}
{...attributes}
{...childFeedback}
>
{React.Children.map(children, child => React.cloneElement(child, { type }))}
{React.Children.map(children, child =>
React.cloneElement(child, { type })
)}
</InputElement>
</FormLabelGroup>
);
};

FormRow.propTypes = {
children: PropTypes.node,
feedback: PropTypes.oneOfType([
PropTypes.node,
PropTypes.object
]),
feedback: PropTypes.oneOfType([PropTypes.node, PropTypes.object]),
hint: PropTypes.string,
id: PropTypes.string,
inline: PropTypes.bool,
Expand Down
3 changes: 1 addition & 2 deletions src/components/LabelBadge.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ interface LabelBadgeProps {
maxWidth?: number;
onRemove?: React.MouseEventHandler<any>;
removable?: boolean;
value: string;
value: (JSX.Element | string) | (JSX.Element | string)[];
}
declare class LabelBadge extends React.Component<LabelBadgeProps, {}> { }
export default LabelBadge;

2 changes: 1 addition & 1 deletion src/components/LabelBadge.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default class LabelBadge extends React.Component {
maxWidth: PropTypes.number,
onRemove: PropTypes.func,
removable: PropTypes.bool,
value: PropTypes.string.isRequired
value: PropTypes.node.isRequired
}

static defaultProps = {
Expand Down
25 changes: 24 additions & 1 deletion test/components/Alert.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ describe('<Alert />', () => {

assert.equal(component.find(Inner).prop('isOpen'), true);

component.find(Inner).find('button').simulate('click');
component
.find(Inner)
.find('button')
.simulate('click');
assert.equal(component.state('visible'), false);
assert.equal(component.find(Inner).prop('isOpen'), false);
});
Expand All @@ -67,5 +70,25 @@ describe('<Alert />', () => {
component.setProps({ color: 'danger' });
assert.equal(component.state('visible'), true);
});

it('should call onToggle if provided', () => {
let called = false;
let calledWith;

const component = mount(
<Alert
dismissible
onToggle={(value) => {
called = true;
calledWith = value;
}}
/>
);
const inner = component.find(Inner);
inner.find('button').simulate('click');

assert.equal(called, true);
assert.equal(calledWith, false);
});
});
});
42 changes: 18 additions & 24 deletions test/components/FormRow.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import assert from 'assert';
import { shallow } from 'enzyme';
import { render, shallow } from 'enzyme';

import {
CheckboxInput,
Expand Down Expand Up @@ -36,9 +36,7 @@ describe('<FormRow />', () => {
});

describe('with static type', () => {
const component = shallow(
<FormRow label="First Name" type="static" />
);
const component = shallow(<FormRow label="First Name" type="static" />);

it('should render a StaticInput', () => {
const input = component.find(StaticInput);
Expand All @@ -47,52 +45,51 @@ describe('<FormRow />', () => {
});

describe('with checkbox type', () => {
const component = shallow(
<FormRow label="First Name" type="checkbox" />
);
const component = shallow(<FormRow label="First Name" type="checkbox" />);

it('should render a CheckboxInput', () => {
assert.equal(component.find(CheckboxInput).length, 1);
});
});

describe('with radio type', () => {
const component = shallow(
<FormRow label="First Name" type="radio" />
);
const component = shallow(<FormRow label="First Name" type="radio" />);

it('should render a RadioInput', () => {
assert.equal(component.find(RadioInput).length, 1);
});
});

describe('with file type', () => {
const wrapper = shallow(
<FormRow type="file" />
);
const wrapper = shallow(<FormRow type="file" />);

it('should render a FileInput', () => {
assert.equal(wrapper.find(FileInput).length, 1);
});
});

describe('with custom type', () => {
const Custom = () => (<div>Hi</div>);
const component = shallow(
<FormRow label="First Name" type={Custom} />
);
const Custom = () => <div>Hi</div>;
const component = shallow(<FormRow label="First Name" type={Custom} />);

it('should render custom input', () => {
const custom = component.find(Custom);
assert.equal(custom.length, 1);
assert.equal(custom.first().prop('type'), null);
});

describe('that does not grok validity', () => {
const Custom2 = ({ props }) => <div {...props}>Hi</div>;
Custom2.propTypes = {};
const component2 = render(
<FormRow label="First Name" type={Custom2} feedback="Na brah" />
);
assert.notEqual(component2.toString().indexOf('<div>Hi</div>'), -1);
});
});

describe('stacked', () => {
const component = shallow(
<FormRow label="First Name" stacked />
);
const component = shallow(<FormRow label="First Name" stacked />);

it('should have a stacked property', () => {
const formLabelGroup = component.find(FormLabelGroup);
Expand All @@ -112,14 +109,11 @@ describe('<FormRow />', () => {
});

describe('with custom labelSize', () => {
const component = shallow(
<FormRow label="First Name" labelSize='sm' />
);
const component = shallow(<FormRow label="First Name" labelSize="sm" />);

it('should set the FormLabelGroup labelSize', () => {
const formLabelGroup = component.find(FormLabelGroup);
assert.equal(formLabelGroup.prop('labelSize'), 'sm');
});
});
});

0 comments on commit 188066c

Please sign in to comment.