Skip to content

Commit 59b1fce

Browse files
authored
feat(Feedback): Add support for tooltips (react-bootstrap#5189)
* feat(Feedback): Add support for tooltips * Renamed tooltip to feedbackTooltip in FormCheck and FormFile
1 parent f846dfb commit 59b1fce

File tree

12 files changed

+296
-4
lines changed

12 files changed

+296
-4
lines changed

src/Feedback.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,28 @@ const propTypes = {
99
* @type {('valid'|'invalid')}
1010
*/
1111
type: PropTypes.string.isRequired,
12+
13+
/** Display feedback as a tooltip. */
14+
tooltip: PropTypes.bool,
15+
1216
as: PropTypes.elementType,
1317
};
1418

1519
const defaultProps = {
1620
type: 'valid',
21+
tooltip: false,
1722
};
1823

1924
const Feedback = React.forwardRef(
2025
// Need to define the default "as" during prop destructuring to be compatible with styled-components github.com/react-bootstrap/react-bootstrap/issues/3595
21-
({ as: Component = 'div', className, type, ...props }, ref) => (
26+
({ as: Component = 'div', className, type, tooltip, ...props }, ref) => (
2227
<Component
2328
{...props}
2429
ref={ref}
25-
className={classNames(className, type && `${type}-feedback`)}
30+
className={classNames(
31+
className,
32+
`${type}-${tooltip ? 'tooltip' : 'feedback'}`,
33+
)}
2634
/>
2735
),
2836
);

src/FormCheck.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ const propTypes = {
7979
/** Manually style the input as invalid */
8080
isInvalid: PropTypes.bool.isRequired,
8181

82+
/** Display feedback as a tooltip. */
83+
feedbackTooltip: PropTypes.bool,
84+
8285
/** A message to display when the input is in a validation state */
8386
feedback: PropTypes.node,
8487
};
@@ -89,6 +92,7 @@ const defaultProps = {
8992
disabled: false,
9093
isValid: false,
9194
isInvalid: false,
95+
feedbackTooltip: false,
9296
title: '',
9397
};
9498

@@ -102,6 +106,7 @@ const FormCheck = React.forwardRef(
102106
disabled,
103107
isValid,
104108
isInvalid,
109+
feedbackTooltip,
105110
feedback,
106111
className,
107112
style,
@@ -165,7 +170,10 @@ const FormCheck = React.forwardRef(
165170
<FormCheckLabel title={title}>{label}</FormCheckLabel>
166171
)}
167172
{(isValid || isInvalid) && (
168-
<Feedback type={isValid ? 'valid' : 'invalid'}>
173+
<Feedback
174+
type={isValid ? 'valid' : 'invalid'}
175+
tooltip={feedbackTooltip}
176+
>
169177
{feedback}
170178
</Feedback>
171179
)}

src/FormFile.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ const propTypes = {
7373
/** Manually style the input as invalid */
7474
isInvalid: PropTypes.bool.isRequired,
7575

76+
/** Display feedback as a tooltip. */
77+
feedbackTooltip: PropTypes.bool,
78+
7679
/** A message to display when the input is in a validation state */
7780
feedback: PropTypes.node,
7881

@@ -103,6 +106,7 @@ const defaultProps = {
103106
disabled: false,
104107
isValid: false,
105108
isInvalid: false,
109+
feedbackTooltip: false,
106110
};
107111

108112
const FormFile = React.forwardRef(
@@ -114,6 +118,7 @@ const FormFile = React.forwardRef(
114118
disabled,
115119
isValid,
116120
isInvalid,
121+
feedbackTooltip,
117122
feedback,
118123
className,
119124
style,
@@ -187,7 +192,10 @@ const FormFile = React.forwardRef(
187192
</>
188193
)}
189194
{(isValid || isInvalid) && (
190-
<Feedback type={isValid ? 'valid' : 'invalid'}>
195+
<Feedback
196+
type={isValid ? 'valid' : 'invalid'}
197+
tooltip={feedbackTooltip}
198+
>
191199
{feedback}
192200
</Feedback>
193201
)}

test/FeedbackSpec.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,20 @@ describe('<Feedback>', () => {
77
it('Should have div as default component', () => {
88
mount(<Feedback />).assertSingle('div');
99
});
10+
11+
it('Should render valid feedback', () => {
12+
mount(<Feedback type="valid" />).assertSingle('.valid-feedback');
13+
});
14+
15+
it('Should render invalid feedback', () => {
16+
mount(<Feedback type="invalid" />).assertSingle('.invalid-feedback');
17+
});
18+
19+
it('Should render valid feedback tooltip', () => {
20+
mount(<Feedback type="valid" tooltip />).assertSingle('.valid-tooltip');
21+
});
22+
23+
it('Should render invalid feedback tooltip', () => {
24+
mount(<Feedback type="invalid" tooltip />).assertSingle('.invalid-tooltip');
25+
});
1026
});

test/FormCheckSpec.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,42 @@ describe('<FormCheck>', () => {
125125
const wrapper = mount(<FormCheck as={Surrogate} />);
126126
wrapper.assertSingle('input.extraClass[type="checkbox"]');
127127
});
128+
129+
it('Should render valid feedback properly', () => {
130+
const wrapper = mount(<FormCheck label="My label" isValid />);
131+
const feedback = wrapper.find('Feedback');
132+
133+
expect(feedback.prop('type')).to.equal('valid');
134+
expect(feedback.prop('tooltip')).to.be.false;
135+
});
136+
137+
it('Should render invalid feedback properly', () => {
138+
const wrapper = mount(
139+
<FormCheck label="My label" isValid={false} isInvalid />,
140+
);
141+
const feedback = wrapper.find('Feedback');
142+
143+
expect(feedback.prop('type')).to.equal('invalid');
144+
expect(feedback.prop('tooltip')).to.be.false;
145+
});
146+
147+
it('Should render valid feedback tooltip properly', () => {
148+
const wrapper = mount(
149+
<FormCheck label="My label" isValid feedbackTooltip />,
150+
);
151+
const feedback = wrapper.find('Feedback');
152+
153+
expect(feedback.prop('type')).to.equal('valid');
154+
expect(feedback.prop('tooltip')).to.be.true;
155+
});
156+
157+
it('Should render invalid feedback tooltip properly', () => {
158+
const wrapper = mount(
159+
<FormCheck label="My label" isValid={false} isInvalid feedbackTooltip />,
160+
);
161+
const feedback = wrapper.find('Feedback');
162+
163+
expect(feedback.prop('type')).to.equal('invalid');
164+
expect(feedback.prop('tooltip')).to.be.true;
165+
});
128166
});

test/FormFileSpec.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,42 @@ describe('<FormFile>', () => {
9090
const wrapper = mount(<FormFile as={Surrogate} />);
9191
wrapper.assertSingle('wrapper-element.extraClass');
9292
});
93+
94+
it('Should render valid feedback properly', () => {
95+
const wrapper = mount(<FormFile label="My label" isValid />);
96+
const feedback = wrapper.find('Feedback');
97+
98+
expect(feedback.prop('type')).to.equal('valid');
99+
expect(feedback.prop('tooltip')).to.be.false;
100+
});
101+
102+
it('Should render invalid feedback properly', () => {
103+
const wrapper = mount(
104+
<FormFile label="My label" isValid={false} isInvalid />,
105+
);
106+
const feedback = wrapper.find('Feedback');
107+
108+
expect(feedback.prop('type')).to.equal('invalid');
109+
expect(feedback.prop('tooltip')).to.be.false;
110+
});
111+
112+
it('Should render valid feedback tooltip properly', () => {
113+
const wrapper = mount(
114+
<FormFile label="My label" isValid feedbackTooltip />,
115+
);
116+
const feedback = wrapper.find('Feedback');
117+
118+
expect(feedback.prop('type')).to.equal('valid');
119+
expect(feedback.prop('tooltip')).to.be.true;
120+
});
121+
122+
it('Should render invalid feedback tooltip properly', () => {
123+
const wrapper = mount(
124+
<FormFile label="My label" isValid={false} isInvalid feedbackTooltip />,
125+
);
126+
const feedback = wrapper.find('Feedback');
127+
128+
expect(feedback.prop('type')).to.equal('invalid');
129+
expect(feedback.prop('tooltip')).to.be.true;
130+
});
93131
});

types/components/Feedback.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { BsPrefixComponent } from './helpers';
55
export interface FeedbackProps {
66
bsPrefix?: never;
77
type?: 'valid' | 'invalid';
8+
tooltip?: boolean;
89
}
910

1011
declare class Feedback<

types/components/FormCheck.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export interface FormCheckProps {
1414
type?: 'checkbox' | 'radio' | 'switch';
1515
isValid?: boolean;
1616
isInvalid?: boolean;
17+
feedbackTooltip?: boolean;
1718
feedback?: React.ReactNode;
1819
}
1920

types/components/FormFile.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export interface FormFileProps {
1111
custom?: boolean;
1212
isValid?: boolean;
1313
isInvalid?: boolean;
14+
feedbackTooltip?: boolean;
1415
feedback?: React.ReactNode;
1516
lang?: string;
1617
}

types/simple.test.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ import {
234234
</Col>
235235
</Form.Group>
236236
<Form.File id="custom-file" label="Custom file input" custom />
237+
<Form.File id="file-tooltip" label="File tooltip" feedbackTooltip />
237238
<Form.File
238239
ref={React.createRef<HTMLInputElement & FormFile>()}
239240
id="custom-file-ref"
@@ -242,6 +243,8 @@ import {
242243
/>
243244
<Form.File.Input />
244245
<Form.Switch label="Switch" disabled />
246+
<Form.Check id="check-tooltip" feedbackTooltip />
247+
<FormControl.Feedback tooltip />
245248
</Form>;
246249

247250
<div>

0 commit comments

Comments
 (0)