Skip to content

Commit c8ce7bd

Browse files
committed
'renderStaticRangeLabel' callback prop is added to DefinedRange component to enable custom component rendering for static range labels.
-'react-test-renderer' is added to dev dependencies. -README is updated for 'renderStaticRangeLabel'. -eslintignore file is updated to ignore snapshot files. -Existing demo is updated to display custom 'renderStaticRangeLabel' usage.
1 parent 2ffa7c8 commit c8ce7bd

File tree

9 files changed

+417
-9
lines changed

9 files changed

+417
-9
lines changed

. eslintignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
/node_modules/*
22
/lib/*
33
/dist/*
4+
**/*.snap

CONTRIBUTING.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ Make sure your issue or feature doesn't have any related issue at [react-date-ra
1010

1111
3. Run `yarn` to install the dependencies.
1212

13-
4. Run `yarn dev` to start development server.
13+
4. Run `yarn run dev` to start development server.
1414

1515
## Building
1616

17-
. Run `run test` and `run lint` for make sure tests passes and linter doesn't throw any error.
17+
. Run `yarn test` and `yarn run lint` for make sure tests passes and linter doesn't throw any error.
1818

19-
. Run `yarn build` compile the library and demo source.
19+
. Run `yarn run build` compile the library and demo source.
2020

2121
. Push your changes and create a PR and apply code review decisions.
2222

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ showPreview(DateRange) | bool | true | visibility
129129
dragSelectionEnabled(Calendar) | bool | true | whether dates can be selected via drag n drop
130130
onPreviewChange(DateRange) | Object | | Callback function for preview changes
131131
dateDisplayFormat(DateRange) | String | `MMM D, YYYY` | selected range preview formatter. Check out [date-fns's format option](https://date-fns.org/v2.0.0-alpha.7/docs/format)
132+
renderStaticRangeLabel(`DefinedRange`)| Function | | Callback function to be triggered for the static range configurations that have `hasCustomRendering: true` on them. Instead of rendering `staticRange.label`, return value of this callback will be rendered.
132133
staticRanges(`DefinedRange`, `DateRangePicker`) | Array | [default preDefined ranges](https://github.com/Adphorus/react-date-range/blob/master/src/defaultRanges.js) | -
133134
inputRanges(`DefinedRange`, `DateRangePicker`) | Array | [default input ranges](https://github.com/Adphorus/react-date-range/blob/master/src/defaultRanges.js) | -
134135

demo/src/components/Main.js

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,51 @@ import * as rdrLocales from '../../../src/locale';
44
import { format, addDays } from 'date-fns';
55
import Section from './Section';
66

7+
function renderStaticRangeLabel(staticRange) {
8+
return (
9+
<CustomStaticRangeLabelContent text={'This is a custom label content: '}/>
10+
);
11+
}
12+
13+
class CustomStaticRangeLabelContent extends React.Component {
14+
constructor(props) {
15+
super(props);
16+
17+
this.state = {
18+
currentDateString: Date(),
19+
};
20+
21+
this.intervalId = setInterval(
22+
() => {
23+
this.setState({
24+
currentDateString: Date(),
25+
});
26+
},
27+
1000
28+
);
29+
}
30+
31+
componentWillUnmount() {
32+
if (this.intervalId) {
33+
clearInterval(this.intervalId);
34+
}
35+
}
36+
37+
render() {
38+
const { currentDateString } = this.state;
39+
const { text } = this.props;
40+
41+
return (
42+
<span>
43+
<i>{text}</i>
44+
<span className={'random-date-string'}>
45+
<b>{currentDateString}</b>
46+
</span>
47+
</span>
48+
);
49+
}
50+
}
51+
752
const nameMapper = {
853
ar: 'Arabic (Modern Standard Arabic - Al-fussha)',
954
bg: 'Bulgarian',
@@ -135,6 +180,7 @@ export default class Main extends Component {
135180
[which]: payload,
136181
});
137182
}
183+
138184
handleRangeChange(which, payload) {
139185
console.log(which, payload);
140186
this.setState({
@@ -217,7 +263,7 @@ export default class Main extends Component {
217263
readOnly
218264
value={formatDateDisplay(this.state.multipleRanges.selection1.endDate, 'Continuous')}
219265
/>
220-
<div className={'newLine'} />
266+
<div className={'newLine'}/>
221267

222268
<label className={'label'}>Selection2 Start:</label>
223269
<input
@@ -231,7 +277,7 @@ export default class Main extends Component {
231277
readOnly
232278
value={formatDateDisplay(this.state.multipleRanges.selection2.endDate, 'Continuous')}
233279
/>
234-
<div className={'newLine'} />
280+
<div className={'newLine'}/>
235281

236282
<label className={'label'}>Selection3 Start:</label>
237283
<input
@@ -319,9 +365,24 @@ export default class Main extends Component {
319365

320366
<DefinedRange
321367
ranges={[this.state.definedRange.selection]}
368+
renderStaticRangeLabel={renderStaticRangeLabel}
369+
staticRanges={[{
370+
label: "Hoy",
371+
hasCustomRendering: true,
372+
range: () => ({
373+
startDate: new Date(),
374+
endDate: new Date(),
375+
}),
376+
isSelected() {
377+
return (
378+
true
379+
);
380+
},
381+
}]}
322382
onChange={this.handleRangeChange.bind(this, 'definedRange')}
323383
className={'centered'}
324-
/>
384+
>
385+
</DefinedRange>
325386
</Section>
326387
<Section title="RangePicker with disabled dates">
327388
<div>
@@ -348,6 +409,25 @@ export default class Main extends Component {
348409
disabledDates={[new Date(), addDays(new Date(), 3)]}
349410
minDate={addDays(new Date(), -3)}
350411
/>
412+
413+
<DefinedRange
414+
ranges={[this.state.definedRange.selection]}
415+
renderStaticRangeLabel={renderStaticRangeLabel}
416+
staticRanges={[{
417+
hasCustomRendering: true,
418+
range: () => ({
419+
startDate: new Date(),
420+
endDate: new Date(),
421+
}),
422+
isSelected() {
423+
return (
424+
true
425+
);
426+
},
427+
}]}
428+
onChange={this.handleRangeChange.bind(this, 'definedRange')}
429+
className={'centered'}
430+
/>
351431
</Section>
352432
</main>
353433
);

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
],
2323
"contributors": [
2424
"Burak Can <neoberg@gmail.com> (https://github.com/burakcan)",
25-
"Mehmet Kamil Morcay <mehmetmorcay@gmail.com> (https://github.com/mkg0)"
25+
"Mehmet Kamil Morcay <mehmetmorcay@gmail.com> (https://github.com/mkg0)",
26+
"Engin Semih Basmacı <semih.basmaci@gmail.com> (https://github.com/mortargrind)"
2627
],
2728
"license": "MIT",
2829
"repository": {
@@ -73,6 +74,7 @@
7374
"react": "^16.2.0",
7475
"react-dom": "^16.2.0",
7576
"react-hot-loader": "^3.1.3",
77+
"react-test-renderer": "16.7.0",
7678
"style-loader": "^0.19.1",
7779
"webpack": "^3.10.0",
7880
"webpack-dev-server": "^2.9.7",

src/components/DefinedRange.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class DefinedRanges extends Component {
1414
};
1515
this.handleRangeChange = this.handleRangeChange.bind(this);
1616
}
17+
1718
handleRangeChange(range) {
1819
const { onChange, ranges, focusedRange } = this.props;
1920
const selectedRange = ranges[focusedRange[0]];
@@ -22,6 +23,7 @@ class DefinedRanges extends Component {
2223
[selectedRange.key || `range${focusedRange[0] + 1}`]: { ...selectedRange, ...range },
2324
});
2425
}
26+
2527
getSelectedRange(ranges, staticRange) {
2628
const focusedRangeIndex = ranges.findIndex(range => {
2729
if (!range.startDate || !range.endDate || range.disabled) return false;
@@ -30,14 +32,24 @@ class DefinedRanges extends Component {
3032
const selectedRange = ranges[focusedRangeIndex];
3133
return { selectedRange, focusedRangeIndex };
3234
}
35+
3336
render() {
34-
const { onPreviewChange, ranges, rangeColors, className } = this.props;
37+
const { onPreviewChange, ranges, renderStaticRangeLabel, rangeColors, className } = this.props;
38+
3539
return (
3640
<div className={cx(styles.definedRangesWrapper, className)}>
3741
{this.props.headerContent}
3842
<div className={styles.staticRanges}>
3943
{this.props.staticRanges.map((staticRange, i) => {
4044
const { selectedRange, focusedRangeIndex } = this.getSelectedRange(ranges, staticRange);
45+
let labelContent;
46+
47+
if (staticRange.hasCustomRendering) {
48+
labelContent = renderStaticRangeLabel(staticRange);
49+
} else {
50+
labelContent = staticRange.label;
51+
}
52+
4153
return (
4254
<button
4355
type="button"
@@ -59,7 +71,7 @@ class DefinedRanges extends Component {
5971
this.props.onPreviewChange && this.props.onPreviewChange();
6072
}}>
6173
<span tabIndex={-1} className={styles.staticRangeLabel}>
62-
{staticRange.label}
74+
{labelContent}
6375
</span>
6476
</button>
6577
);
@@ -106,6 +118,7 @@ DefinedRanges.propTypes = {
106118
headerContent: PropTypes.any,
107119
rangeColors: PropTypes.arrayOf(PropTypes.string),
108120
className: PropTypes.string,
121+
renderStaticRangeLabel: PropTypes.func,
109122
};
110123

111124
DefinedRanges.defaultProps = {

src/components/DefinedRange.test.js

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import React from 'react';
2+
import { mount } from 'enzyme';
3+
4+
import DefinedRange from './DefinedRange';
5+
import { isSameDay } from 'date-fns';
6+
import testRenderer from 'react-test-renderer';
7+
8+
describe('DefinedRange tests', () => {
9+
test('Should call "renderStaticRangeLabel" callback correct amount of times according to the "hasCustomRendering" option', () => {
10+
const renderStaticRangeLabel = jest.fn();
11+
12+
mount(
13+
<DefinedRange
14+
staticRanges={[
15+
{
16+
label: 'Dynamic Label',
17+
range: {},
18+
isSelected(range) {
19+
const definedRange = this.range();
20+
return (
21+
isSameDay(range.startDate, definedRange.startDate) &&
22+
isSameDay(range.endDate, definedRange.endDate)
23+
);
24+
},
25+
hasCustomRendering: true,
26+
},
27+
{
28+
label: 'Static Label',
29+
range: {},
30+
isSelected(range) {
31+
const definedRange = this.range();
32+
return (
33+
isSameDay(range.startDate, definedRange.startDate) &&
34+
isSameDay(range.endDate, definedRange.endDate)
35+
);
36+
},
37+
},
38+
{
39+
label: 'Hede',
40+
range: {},
41+
isSelected(range) {
42+
const definedRange = this.range();
43+
return (
44+
isSameDay(range.startDate, definedRange.startDate) &&
45+
isSameDay(range.endDate, definedRange.endDate)
46+
);
47+
},
48+
hasCustomRendering: true,
49+
},
50+
]}
51+
renderStaticRangeLabel={renderStaticRangeLabel}
52+
/>
53+
);
54+
55+
expect(renderStaticRangeLabel).toHaveBeenCalledTimes(2);
56+
});
57+
58+
test('Should render dynamic static label contents correctly', () => {
59+
const renderItalicLabelContent = () => (
60+
<i className={'italic-label-content'}>{'Italic Content'}</i>
61+
);
62+
const renderBoldLabelContent = () => <b className={'bold-label-content'}>{'Bold Content'}</b>;
63+
const renderSomethingElse = () => <img className={'random-image'} />;
64+
65+
const renderStaticRangeLabel = function(staticRange) {
66+
let result;
67+
68+
if (staticRange.id === 'italic') {
69+
result = renderItalicLabelContent();
70+
} else if (staticRange.id === 'bold') {
71+
result = renderBoldLabelContent();
72+
} else {
73+
result = renderSomethingElse();
74+
}
75+
76+
return result;
77+
};
78+
79+
const tree = testRenderer
80+
.create(
81+
<DefinedRange
82+
staticRanges={[
83+
{
84+
id: 'italic',
85+
range: {},
86+
isSelected(range) {
87+
const definedRange = this.range();
88+
return (
89+
isSameDay(range.startDate, definedRange.startDate) &&
90+
isSameDay(range.endDate, definedRange.endDate)
91+
);
92+
},
93+
hasCustomRendering: true,
94+
},
95+
{
96+
label: 'Static Label',
97+
range: {},
98+
isSelected(range) {
99+
const definedRange = this.range();
100+
return (
101+
isSameDay(range.startDate, definedRange.startDate) &&
102+
isSameDay(range.endDate, definedRange.endDate)
103+
);
104+
},
105+
},
106+
{
107+
id: 'whatever',
108+
range: {},
109+
isSelected(range) {
110+
const definedRange = this.range();
111+
return (
112+
isSameDay(range.startDate, definedRange.startDate) &&
113+
isSameDay(range.endDate, definedRange.endDate)
114+
);
115+
},
116+
hasCustomRendering: true,
117+
},
118+
{
119+
id: 'bold',
120+
range: {},
121+
isSelected(range) {
122+
const definedRange = this.range();
123+
return (
124+
isSameDay(range.startDate, definedRange.startDate) &&
125+
isSameDay(range.endDate, definedRange.endDate)
126+
);
127+
},
128+
hasCustomRendering: true,
129+
},
130+
]}
131+
renderStaticRangeLabel={renderStaticRangeLabel}
132+
/>
133+
)
134+
.toJSON();
135+
136+
expect(tree).toMatchSnapshot();
137+
});
138+
});

0 commit comments

Comments
 (0)