bright-components 10.0.0 → 10.2.0
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/components/Checkbox/index.js +6 -4
- package/dist/components/DayPicker/NewDayPicker/index.js +207 -0
- package/dist/components/DayPicker/index.js +30 -7
- package/dist/components/DayPickerPanel/index.js +1 -1
- package/dist/components/Time/TimePicker/index.js +1 -0
- package/dist/components/Typeahead/Option/index.js +0 -1
- package/dist/setupTests.js +5 -0
- package/package.json +3 -2
- package/src/components/Checkbox/index.js +2 -2
- package/src/components/DayPicker/NewDayPicker/index.js +208 -0
- package/src/components/DayPicker/examples.md +17 -0
- package/src/components/DayPicker/index.js +43 -17
- package/src/components/DayPicker/test.js +297 -1
- package/src/components/DayPickerPanel/index.js +1 -1
- package/src/components/DayPickerPanel/test.js +1 -1
- package/src/components/DurationInput/test.js +5 -3
- package/src/components/EmployeePicker/FilterBar/test.js +1 -1
- package/src/components/ResponsiveTabs/test.js +3 -3
- package/src/components/Time/TimePicker/index.js +1 -0
- package/src/components/Time/TimePicker/test.js +29 -28
- package/src/components/Typeahead/Option/index.js +0 -1
- package/src/setupTests.js +2 -0
@@ -53,15 +53,17 @@ const Checkmark = _styledComponents.default.span`
|
|
53
53
|
position: relative;
|
54
54
|
top: ${_ref3 => {
|
55
55
|
let {
|
56
|
-
outline
|
56
|
+
outline,
|
57
|
+
disabled
|
57
58
|
} = _ref3;
|
58
|
-
return outline ? '-4px' : '-2px';
|
59
|
+
return outline && !disabled ? '-4px' : '-2px';
|
59
60
|
}};
|
60
61
|
left: ${_ref4 => {
|
61
62
|
let {
|
62
|
-
outline
|
63
|
+
outline,
|
64
|
+
disabled
|
63
65
|
} = _ref4;
|
64
|
-
return outline ? '-2px' : '0';
|
66
|
+
return outline && !disabled ? '-2px' : '0';
|
65
67
|
}};
|
66
68
|
display: block;
|
67
69
|
width: 16px;
|
@@ -0,0 +1,207 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
exports.__esModule = true;
|
4
|
+
exports.default = void 0;
|
5
|
+
|
6
|
+
var _react = _interopRequireWildcard(require("react"));
|
7
|
+
|
8
|
+
var _dateFns = require("date-fns");
|
9
|
+
|
10
|
+
var _styledComponents = _interopRequireDefault(require("styled-components"));
|
11
|
+
|
12
|
+
var _Input = _interopRequireDefault(require("../../Input"));
|
13
|
+
|
14
|
+
var _ErrorMessage = _interopRequireDefault(require("../../ErrorMessage"));
|
15
|
+
|
16
|
+
var _propTypes = require("prop-types");
|
17
|
+
|
18
|
+
var _colors = _interopRequireDefault(require("../../../constants/colors"));
|
19
|
+
|
20
|
+
var _spacing = _interopRequireDefault(require("../../../constants/spacing"));
|
21
|
+
|
22
|
+
var _Calendar = _interopRequireDefault(require("../../Icons/Calendar"));
|
23
|
+
|
24
|
+
var _reactGa = require("react-ga");
|
25
|
+
|
26
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
27
|
+
|
28
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
29
|
+
|
30
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
31
|
+
|
32
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
33
|
+
|
34
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
35
|
+
|
36
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
37
|
+
|
38
|
+
const HiddenBox = (0, _styledComponents.default)(_Input.default.withComponent('div'))`
|
39
|
+
display: flex;
|
40
|
+
align-items: center;
|
41
|
+
${props => props.error && `
|
42
|
+
margin-bottom: 0px !important;
|
43
|
+
border-bottom-left-radius: 0px;
|
44
|
+
border-bottom-right-radius: 0px;
|
45
|
+
border-color: ${_colors.default.borderError} !important;
|
46
|
+
`};
|
47
|
+
input {
|
48
|
+
height: 2.5rem !important;
|
49
|
+
min-height: 2.5rem !important;
|
50
|
+
border: 0 !important;
|
51
|
+
margin: 0 !important;
|
52
|
+
padding: 0 !important;
|
53
|
+
box-shadow: none !important;
|
54
|
+
}
|
55
|
+
`;
|
56
|
+
HiddenBox.displayName = 'HiddenBox';
|
57
|
+
const OpenCalendarIcon = (0, _styledComponents.default)(_Calendar.default)`
|
58
|
+
cursor: ${props => props.disabled ? 'not-allowed' : 'pointer'};
|
59
|
+
margin-left: ${_spacing.default.s1};
|
60
|
+
color: ${_colors.default.primary};
|
61
|
+
`;
|
62
|
+
OpenCalendarIcon.displayName = 'OpenCalendarIcon';
|
63
|
+
const formats = {
|
64
|
+
CA: {
|
65
|
+
placeholderDate: 'YY/MM/DD',
|
66
|
+
dateFormat: 'yy/MM/dd'
|
67
|
+
},
|
68
|
+
default: {
|
69
|
+
placeholderDate: 'DD/MM/YY',
|
70
|
+
dateFormat: 'dd/MM/yy'
|
71
|
+
}
|
72
|
+
};
|
73
|
+
|
74
|
+
const makeInnerDate = (date, dateFormat) => {
|
75
|
+
if (date.from) {
|
76
|
+
return (0, _dateFns.format)(date.from, dateFormat);
|
77
|
+
}
|
78
|
+
|
79
|
+
return '';
|
80
|
+
};
|
81
|
+
|
82
|
+
const NewDisplay = _ref => {
|
83
|
+
let {
|
84
|
+
placeholder,
|
85
|
+
datesToDisplay,
|
86
|
+
range,
|
87
|
+
allowClear,
|
88
|
+
yearRange,
|
89
|
+
onSelectedDate,
|
90
|
+
locale,
|
91
|
+
clearValue,
|
92
|
+
disabled,
|
93
|
+
error,
|
94
|
+
toggleDayPicker,
|
95
|
+
GA: {
|
96
|
+
category,
|
97
|
+
actionId
|
98
|
+
},
|
99
|
+
recordValue,
|
100
|
+
dayPickerOpen
|
101
|
+
} = _ref;
|
102
|
+
const {
|
103
|
+
placeholderDate,
|
104
|
+
dateFormat
|
105
|
+
} = formats[locale] || formats.default;
|
106
|
+
const [hasFocus, setHasFocus] = (0, _react.useState)(false);
|
107
|
+
const [hasError, setHasError] = (0, _react.useState)(false);
|
108
|
+
const [innerDate, setInnerDate] = (0, _react.useState)(makeInnerDate(range, dateFormat));
|
109
|
+
return _react.default.createElement(_react.default.Fragment, null, _react.default.createElement(HiddenBox, {
|
110
|
+
error: error,
|
111
|
+
"data-testid": "input-selector"
|
112
|
+
}, _react.default.createElement(_Input.default, {
|
113
|
+
"data-testid": "new input",
|
114
|
+
placeholder: hasFocus ? placeholderDate : placeholder,
|
115
|
+
value: hasFocus ? innerDate : datesToDisplay,
|
116
|
+
fullWidth: true,
|
117
|
+
disabled: disabled,
|
118
|
+
onFocus: () => {
|
119
|
+
setInnerDate(makeInnerDate(range, dateFormat));
|
120
|
+
setHasFocus(true);
|
121
|
+
setHasError(false);
|
122
|
+
},
|
123
|
+
onBlur: _ref2 => {
|
124
|
+
let {
|
125
|
+
target: {
|
126
|
+
value
|
127
|
+
}
|
128
|
+
} = _ref2;
|
129
|
+
setHasFocus(false);
|
130
|
+
if (dayPickerOpen) toggleDayPicker();
|
131
|
+
|
132
|
+
if (!value && (allowClear || !range.from)) {
|
133
|
+
return range.from ? clearValue() : null;
|
134
|
+
}
|
135
|
+
|
136
|
+
const newDate = {
|
137
|
+
from: (0, _dateFns.parse)(value, dateFormat, new Date()),
|
138
|
+
to: (0, _dateFns.parse)(value, dateFormat, new Date())
|
139
|
+
};
|
140
|
+
const fromYear = (0, _dateFns.getYear)(newDate.from);
|
141
|
+
const toYear = (0, _dateFns.getYear)(newDate.to);
|
142
|
+
|
143
|
+
if (!(0, _dateFns.isValid)(newDate.from) || !(0, _dateFns.isValid)(newDate.to) || fromYear < yearRange.min || toYear > yearRange.max) {
|
144
|
+
setHasError(!((0, _dateFns.isValid)(newDate.from) && (0, _dateFns.isValid)(newDate.to)) ? 'invalid' : 'range');
|
145
|
+
return range.from ? onSelectedDate(allowClear ? '' : range) : null;
|
146
|
+
}
|
147
|
+
|
148
|
+
if (category) {
|
149
|
+
const label = `${(0, _dateFns.format)(newDate.from, 'EEE dd MMM')} ${(0, _dateFns.format)(newDate.from, 'yyyy')}`;
|
150
|
+
(0, _reactGa.event)(_objectSpread({
|
151
|
+
category,
|
152
|
+
action: `${actionId} - Set via Typing`
|
153
|
+
}, recordValue ? {
|
154
|
+
label
|
155
|
+
} : {}));
|
156
|
+
}
|
157
|
+
|
158
|
+
return onSelectedDate(newDate);
|
159
|
+
},
|
160
|
+
onChange: _ref3 => {
|
161
|
+
let {
|
162
|
+
target: {
|
163
|
+
value
|
164
|
+
}
|
165
|
+
} = _ref3;
|
166
|
+
setInnerDate(value.replace(/.*\/$/g, text => value.length < innerDate.length ? value.slice(0, -1) : text).replace(/(\d\d)(\d)/g, '$1/$2').replace(/^(\d\/)$/g, '0$1').replace(/\d\d$/g, text => value.length > innerDate.length && value.length < 7 ? `${text}/` : text).replace(/^(\d\d\/)(\d\/)$/g, '$10$2').replace(/[^\d/]/g, '').replace(/^(.{0,8})(.*)$/g, '$1').replace(/\/\/$/g, '/'));
|
167
|
+
}
|
168
|
+
}), _react.default.createElement(OpenCalendarIcon, {
|
169
|
+
"data-testid": "calendarIcon",
|
170
|
+
size: 22,
|
171
|
+
disabled: disabled,
|
172
|
+
onClick: () => {
|
173
|
+
setHasError(false);
|
174
|
+
toggleDayPicker();
|
175
|
+
}
|
176
|
+
})), hasError && _react.default.createElement(_ErrorMessage.default, {
|
177
|
+
showIcon: false
|
178
|
+
}, hasError === 'invalid' ? 'Date is invalid' : `Year is outside of range. Must be between ${yearRange.min} - ${yearRange.max}`));
|
179
|
+
};
|
180
|
+
|
181
|
+
NewDisplay.propTypes = {
|
182
|
+
placeholder: _propTypes.string.isRequired,
|
183
|
+
datesToDisplay: _propTypes.string.isRequired,
|
184
|
+
range: (0, _propTypes.shape)({
|
185
|
+
from: (0, _propTypes.instanceOf)(Date),
|
186
|
+
to: (0, _propTypes.instanceOf)(Date)
|
187
|
+
}).isRequired,
|
188
|
+
allowClear: _propTypes.bool.isRequired,
|
189
|
+
yearRange: (0, _propTypes.shape)({
|
190
|
+
min: _propTypes.number,
|
191
|
+
max: _propTypes.number
|
192
|
+
}).isRequired,
|
193
|
+
onSelectedDate: _propTypes.func.isRequired,
|
194
|
+
locale: _propTypes.string.isRequired,
|
195
|
+
clearValue: _propTypes.func.isRequired,
|
196
|
+
disabled: _propTypes.bool.isRequired,
|
197
|
+
error: _propTypes.bool.isRequired,
|
198
|
+
toggleDayPicker: _propTypes.func.isRequired,
|
199
|
+
GA: (0, _propTypes.shape)({
|
200
|
+
category: _propTypes.string,
|
201
|
+
actionId: _propTypes.string
|
202
|
+
}).isRequired,
|
203
|
+
recordValue: _propTypes.bool.isRequired,
|
204
|
+
dayPickerOpen: _propTypes.bool.isRequired
|
205
|
+
};
|
206
|
+
var _default = NewDisplay;
|
207
|
+
exports.default = _default;
|
@@ -33,6 +33,8 @@ var _breakpoints = _interopRequireDefault(require("../../constants/breakpoints")
|
|
33
33
|
|
34
34
|
var _Calendar = _interopRequireDefault(require("../Icons/Calendar"));
|
35
35
|
|
36
|
+
var _NewDayPicker = _interopRequireDefault(require("./NewDayPicker"));
|
37
|
+
|
36
38
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
37
39
|
|
38
40
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
@@ -271,15 +273,17 @@ class DayPicker extends _react.default.Component {
|
|
271
273
|
closeButton,
|
272
274
|
panelAbsoluteOnDesktop,
|
273
275
|
onSelectedDate,
|
274
|
-
isDateSelect
|
276
|
+
isDateSelect,
|
277
|
+
typeable
|
275
278
|
} = _this$props,
|
276
|
-
rest = _objectWithoutProperties(_this$props, ["allowClear", "placeholder", "dateRange", "yearRange", "yearsToDisplay", "style", "error", "disabled", "shortcuts", "disabledDays", "GA", "recordValue", "legacyInputStyle", "closeButton", "panelAbsoluteOnDesktop", "onSelectedDate", "isDateSelect"]);
|
279
|
+
rest = _objectWithoutProperties(_this$props, ["allowClear", "placeholder", "dateRange", "yearRange", "yearsToDisplay", "style", "error", "disabled", "shortcuts", "disabledDays", "GA", "recordValue", "legacyInputStyle", "closeButton", "panelAbsoluteOnDesktop", "onSelectedDate", "isDateSelect", "typeable"]);
|
277
280
|
|
278
281
|
const {
|
279
282
|
dayPickerOpen
|
280
283
|
} = this.state;
|
281
284
|
const {
|
282
|
-
range
|
285
|
+
range,
|
286
|
+
locale
|
283
287
|
} = this.props;
|
284
288
|
const fromDate = range.from ? (0, _dateFns.format)(range.from, this.getDisplayFormat()) : '';
|
285
289
|
const toDate = range.to ? (0, _dateFns.format)(range.to, friendlyShortWithYear) : '';
|
@@ -290,7 +294,7 @@ class DayPicker extends _react.default.Component {
|
|
290
294
|
} = style,
|
291
295
|
otherStyles = _objectWithoutProperties(style, ["width"]);
|
292
296
|
|
293
|
-
return _react.default.createElement(DayPickerInputContainer, rest, _react.default.createElement(InputBox, {
|
297
|
+
return _react.default.createElement(DayPickerInputContainer, rest, !typeable || dateRange ? _react.default.createElement(InputBox, {
|
294
298
|
onClick: this.toggleDayPicker,
|
295
299
|
error: error,
|
296
300
|
disabled: disabled,
|
@@ -299,7 +303,22 @@ class DayPicker extends _react.default.Component {
|
|
299
303
|
}, datesToDisplay ? _react.default.createElement("span", null, datesToDisplay) : _react.default.createElement(Placeholder, null, placeholder), _react.default.createElement(OpenCalendarIcon, {
|
300
304
|
size: 22,
|
301
305
|
disabled: disabled
|
302
|
-
}))
|
306
|
+
})) : _react.default.createElement(_NewDayPicker.default, {
|
307
|
+
placeholder: placeholder,
|
308
|
+
datesToDisplay: datesToDisplay,
|
309
|
+
range: range,
|
310
|
+
allowClear: allowClear,
|
311
|
+
yearRange: yearRange,
|
312
|
+
onSelectedDate: onSelectedDate,
|
313
|
+
locale: locale,
|
314
|
+
clearValue: this.clearValue,
|
315
|
+
disabled: disabled,
|
316
|
+
error: error,
|
317
|
+
toggleDayPicker: this.toggleDayPicker,
|
318
|
+
GA: GA,
|
319
|
+
recordValue: recordValue,
|
320
|
+
dayPickerOpen: dayPickerOpen
|
321
|
+
}), dayPickerOpen && _react.default.createElement(DayRangeContainer, {
|
303
322
|
panelAbsoluteOnDesktop: panelAbsoluteOnDesktop,
|
304
323
|
style: otherStyles,
|
305
324
|
width: width,
|
@@ -360,7 +379,9 @@ DayPicker.propTypes = {
|
|
360
379
|
legacyInputStyle: _propTypes.bool,
|
361
380
|
closeButton: _propTypes.bool,
|
362
381
|
panelAbsoluteOnDesktop: _propTypes.bool,
|
363
|
-
isDateSelect: _propTypes.bool
|
382
|
+
isDateSelect: _propTypes.bool,
|
383
|
+
typeable: _propTypes.bool,
|
384
|
+
locale: _propTypes.string
|
364
385
|
};
|
365
386
|
DayPicker.defaultProps = {
|
366
387
|
recordValue: false,
|
@@ -385,7 +406,9 @@ DayPicker.defaultProps = {
|
|
385
406
|
legacyInputStyle: false,
|
386
407
|
closeButton: false,
|
387
408
|
panelAbsoluteOnDesktop: true,
|
388
|
-
isDateSelect: false
|
409
|
+
isDateSelect: false,
|
410
|
+
typeable: false,
|
411
|
+
locale: 'GB'
|
389
412
|
};
|
390
413
|
|
391
414
|
var _default = (0, _reactOnclickoutside.default)(DayPicker);
|
@@ -207,7 +207,7 @@ class DayPickerPanel extends _react.default.Component {
|
|
207
207
|
to
|
208
208
|
}
|
209
209
|
} = this.state;
|
210
|
-
const actionEvent = selectedDay ? 'Set' : 'Apply';
|
210
|
+
const actionEvent = selectedDay ? 'Set via Date Picker' : 'Apply';
|
211
211
|
|
212
212
|
if (category) {
|
213
213
|
const label = dateRange ? `${(0, _dateFns.format)(from, friendlyShort)} - ${(0, _dateFns.format)(to || from, friendlyShort)} ${(0, _dateFns.format)(to || from, 'yyyy')}` : `${(0, _dateFns.format)(from, friendlyShort)} ${(0, _dateFns.format)(from, 'yyyy')}`;
|
@@ -133,6 +133,7 @@ const TimePicker = _ref => {
|
|
133
133
|
const valueAsString = (0, _durationToTimeString.default)(value);
|
134
134
|
return _react.default.createElement(_react.default.Fragment, null, _react.default.createElement(MobileTimePicker, {
|
135
135
|
type: "time",
|
136
|
+
"data-testid": "mobileTimePicker",
|
136
137
|
onChange: e => {
|
137
138
|
const timeString = e.target.value;
|
138
139
|
|
package/dist/setupTests.js
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
var _enzyme = require("enzyme");
|
4
4
|
|
5
|
+
var _react = require("@testing-library/react");
|
6
|
+
|
5
7
|
var _enzymeAdapterReact = _interopRequireDefault(require("enzyme-adapter-react-16"));
|
6
8
|
|
7
9
|
var _reactGa = _interopRequireDefault(require("react-ga"));
|
@@ -53,4 +55,7 @@ afterEach(() => {
|
|
53
55
|
});
|
54
56
|
(0, _enzyme.configure)({
|
55
57
|
adapter: new _enzymeAdapterReact.default()
|
58
|
+
});
|
59
|
+
(0, _react.configure)({
|
60
|
+
defaultHidden: true
|
56
61
|
});
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "bright-components",
|
3
|
-
"version": "10.
|
3
|
+
"version": "10.2.0",
|
4
4
|
"private": false,
|
5
5
|
"main": "./dist",
|
6
6
|
"repository": {
|
@@ -73,10 +73,11 @@
|
|
73
73
|
"@babel/preset-env": "^7.16.5",
|
74
74
|
"@babel/preset-react": "^7.7.4",
|
75
75
|
"@svgr/webpack": "4.3.2",
|
76
|
+
"@testing-library/dom": "^8.11.2",
|
76
77
|
"@testing-library/jest-dom": "^4.1.0",
|
77
78
|
"@testing-library/react": "^9.1.4",
|
78
79
|
"@testing-library/react-hooks": "^2.0.1",
|
79
|
-
"@testing-library/user-event": "^
|
80
|
+
"@testing-library/user-event": "^12.8.3",
|
80
81
|
"babel-eslint": "10.0.2",
|
81
82
|
"babel-jest": "^24.9.0",
|
82
83
|
"babel-loader": "8.0.6",
|
@@ -27,8 +27,8 @@ Box.displayName = 'Box';
|
|
27
27
|
|
28
28
|
const Checkmark = styled.span`
|
29
29
|
position: relative;
|
30
|
-
top: ${({ outline }) => (outline ? '-4px' : '-2px')};
|
31
|
-
left: ${({ outline }) => (outline ? '-2px' : '0')};
|
30
|
+
top: ${({ outline, disabled }) => (outline && !disabled ? '-4px' : '-2px')};
|
31
|
+
left: ${({ outline, disabled }) => (outline && !disabled ? '-2px' : '0')};
|
32
32
|
display: block;
|
33
33
|
width: 16px;
|
34
34
|
height: 16px;
|
@@ -0,0 +1,208 @@
|
|
1
|
+
import React, { useState } from 'react';
|
2
|
+
import { format, isValid, parse, getYear } from 'date-fns';
|
3
|
+
import styled from 'styled-components';
|
4
|
+
import Input from 'components/Input';
|
5
|
+
import ErrorMessage from 'components/ErrorMessage';
|
6
|
+
import { string, func, bool, shape, instanceOf, number } from 'prop-types';
|
7
|
+
import colors from 'constants/colors';
|
8
|
+
import spacing from 'constants/spacing';
|
9
|
+
import CalendarIcon from 'components/Icons/Calendar/';
|
10
|
+
import { event } from 'react-ga';
|
11
|
+
|
12
|
+
const HiddenBox = styled(Input.withComponent('div'))`
|
13
|
+
display: flex;
|
14
|
+
align-items: center;
|
15
|
+
${props =>
|
16
|
+
props.error &&
|
17
|
+
`
|
18
|
+
margin-bottom: 0px !important;
|
19
|
+
border-bottom-left-radius: 0px;
|
20
|
+
border-bottom-right-radius: 0px;
|
21
|
+
border-color: ${colors.borderError} !important;
|
22
|
+
`};
|
23
|
+
input {
|
24
|
+
height: 2.5rem !important;
|
25
|
+
min-height: 2.5rem !important;
|
26
|
+
border: 0 !important;
|
27
|
+
margin: 0 !important;
|
28
|
+
padding: 0 !important;
|
29
|
+
box-shadow: none !important;
|
30
|
+
}
|
31
|
+
`;
|
32
|
+
HiddenBox.displayName = 'HiddenBox';
|
33
|
+
|
34
|
+
const OpenCalendarIcon = styled(CalendarIcon)`
|
35
|
+
cursor: ${props => (props.disabled ? 'not-allowed' : 'pointer')};
|
36
|
+
margin-left: ${spacing.s1};
|
37
|
+
color: ${colors.primary};
|
38
|
+
`;
|
39
|
+
OpenCalendarIcon.displayName = 'OpenCalendarIcon';
|
40
|
+
|
41
|
+
const formats = {
|
42
|
+
CA: { placeholderDate: 'YY/MM/DD', dateFormat: 'yy/MM/dd' },
|
43
|
+
default: { placeholderDate: 'DD/MM/YY', dateFormat: 'dd/MM/yy' }
|
44
|
+
};
|
45
|
+
|
46
|
+
const makeInnerDate = (date, dateFormat) => {
|
47
|
+
if (date.from) {
|
48
|
+
return format(date.from, dateFormat);
|
49
|
+
}
|
50
|
+
return '';
|
51
|
+
};
|
52
|
+
|
53
|
+
const NewDisplay = ({
|
54
|
+
placeholder,
|
55
|
+
datesToDisplay,
|
56
|
+
range,
|
57
|
+
allowClear,
|
58
|
+
yearRange,
|
59
|
+
onSelectedDate,
|
60
|
+
locale,
|
61
|
+
clearValue,
|
62
|
+
disabled,
|
63
|
+
error,
|
64
|
+
toggleDayPicker,
|
65
|
+
GA: { category, actionId },
|
66
|
+
recordValue,
|
67
|
+
dayPickerOpen
|
68
|
+
}) => {
|
69
|
+
const { placeholderDate, dateFormat } = formats[locale] || formats.default;
|
70
|
+
|
71
|
+
const [hasFocus, setHasFocus] = useState(false);
|
72
|
+
const [hasError, setHasError] = useState(false);
|
73
|
+
const [innerDate, setInnerDate] = useState(
|
74
|
+
makeInnerDate(range, dateFormat)
|
75
|
+
);
|
76
|
+
|
77
|
+
return (
|
78
|
+
<>
|
79
|
+
<HiddenBox error={error} data-testid="input-selector">
|
80
|
+
<Input
|
81
|
+
data-testid="new input"
|
82
|
+
placeholder={hasFocus ? placeholderDate : placeholder}
|
83
|
+
value={hasFocus ? innerDate : datesToDisplay}
|
84
|
+
fullWidth
|
85
|
+
disabled={disabled}
|
86
|
+
onFocus={() => {
|
87
|
+
setInnerDate(makeInnerDate(range, dateFormat));
|
88
|
+
setHasFocus(true);
|
89
|
+
setHasError(false);
|
90
|
+
}}
|
91
|
+
onBlur={({ target: { value } }) => {
|
92
|
+
setHasFocus(false);
|
93
|
+
if (dayPickerOpen) toggleDayPicker();
|
94
|
+
if (!value && (allowClear || !range.from)) {
|
95
|
+
return range.from ? clearValue() : null;
|
96
|
+
}
|
97
|
+
|
98
|
+
const newDate = {
|
99
|
+
from: parse(value, dateFormat, new Date()),
|
100
|
+
to: parse(value, dateFormat, new Date())
|
101
|
+
};
|
102
|
+
|
103
|
+
const fromYear = getYear(newDate.from);
|
104
|
+
const toYear = getYear(newDate.to);
|
105
|
+
|
106
|
+
if (
|
107
|
+
!isValid(newDate.from) ||
|
108
|
+
!isValid(newDate.to) ||
|
109
|
+
fromYear < yearRange.min ||
|
110
|
+
toYear > yearRange.max
|
111
|
+
) {
|
112
|
+
setHasError(
|
113
|
+
!(isValid(newDate.from) && isValid(newDate.to))
|
114
|
+
? 'invalid'
|
115
|
+
: 'range'
|
116
|
+
);
|
117
|
+
|
118
|
+
return range.from
|
119
|
+
? onSelectedDate(allowClear ? '' : range)
|
120
|
+
: null;
|
121
|
+
}
|
122
|
+
|
123
|
+
if (category) {
|
124
|
+
const label = `${format(
|
125
|
+
newDate.from,
|
126
|
+
'EEE dd MMM'
|
127
|
+
)} ${format(newDate.from, 'yyyy')}`;
|
128
|
+
|
129
|
+
event({
|
130
|
+
category,
|
131
|
+
action: `${actionId} - Set via Typing`,
|
132
|
+
...(recordValue ? { label } : {})
|
133
|
+
});
|
134
|
+
}
|
135
|
+
|
136
|
+
return onSelectedDate(newDate);
|
137
|
+
}}
|
138
|
+
onChange={({ target: { value } }) => {
|
139
|
+
setInnerDate(
|
140
|
+
value
|
141
|
+
.replace(/.*\/$/g, text =>
|
142
|
+
value.length < innerDate.length
|
143
|
+
? value.slice(0, -1)
|
144
|
+
: text
|
145
|
+
)
|
146
|
+
.replace(/(\d\d)(\d)/g, '$1/$2')
|
147
|
+
.replace(/^(\d\/)$/g, '0$1')
|
148
|
+
.replace(/\d\d$/g, text =>
|
149
|
+
value.length > innerDate.length &&
|
150
|
+
value.length < 7
|
151
|
+
? `${text}/`
|
152
|
+
: text
|
153
|
+
)
|
154
|
+
.replace(/^(\d\d\/)(\d\/)$/g, '$10$2')
|
155
|
+
.replace(/[^\d/]/g, '')
|
156
|
+
.replace(/^(.{0,8})(.*)$/g, '$1')
|
157
|
+
.replace(/\/\/$/g, '/')
|
158
|
+
);
|
159
|
+
}}
|
160
|
+
/>
|
161
|
+
<OpenCalendarIcon
|
162
|
+
data-testid="calendarIcon"
|
163
|
+
size={22}
|
164
|
+
disabled={disabled}
|
165
|
+
onClick={() => {
|
166
|
+
setHasError(false);
|
167
|
+
toggleDayPicker();
|
168
|
+
}}
|
169
|
+
/>
|
170
|
+
</HiddenBox>
|
171
|
+
{hasError && (
|
172
|
+
<ErrorMessage showIcon={false}>
|
173
|
+
{hasError === 'invalid'
|
174
|
+
? 'Date is invalid'
|
175
|
+
: `Year is outside of range. Must be between ${yearRange.min} - ${yearRange.max}`}
|
176
|
+
</ErrorMessage>
|
177
|
+
)}
|
178
|
+
</>
|
179
|
+
);
|
180
|
+
};
|
181
|
+
|
182
|
+
NewDisplay.propTypes = {
|
183
|
+
placeholder: string.isRequired,
|
184
|
+
datesToDisplay: string.isRequired,
|
185
|
+
range: shape({
|
186
|
+
from: instanceOf(Date),
|
187
|
+
to: instanceOf(Date)
|
188
|
+
}).isRequired,
|
189
|
+
allowClear: bool.isRequired,
|
190
|
+
yearRange: shape({
|
191
|
+
min: number,
|
192
|
+
max: number
|
193
|
+
}).isRequired,
|
194
|
+
onSelectedDate: func.isRequired,
|
195
|
+
locale: string.isRequired,
|
196
|
+
clearValue: func.isRequired,
|
197
|
+
disabled: bool.isRequired,
|
198
|
+
error: bool.isRequired,
|
199
|
+
toggleDayPicker: func.isRequired,
|
200
|
+
GA: shape({
|
201
|
+
category: string,
|
202
|
+
actionId: string
|
203
|
+
}).isRequired,
|
204
|
+
recordValue: bool.isRequired,
|
205
|
+
dayPickerOpen: bool.isRequired
|
206
|
+
};
|
207
|
+
|
208
|
+
export default NewDisplay;
|
@@ -231,3 +231,20 @@ initialState={dates: {from: new Date(2018, 3, 1), to: undefined}};
|
|
231
231
|
isDateSelect={true}
|
232
232
|
/>
|
233
233
|
```
|
234
|
+
Day Picker - typeable
|
235
|
+
```js
|
236
|
+
initialState={dates: {from: new Date(2018, 3, 1), to: undefined}};
|
237
|
+
<DayPicker
|
238
|
+
range={state.dates}
|
239
|
+
yearRange={{ min: 2000, max: 2030}}
|
240
|
+
style={{
|
241
|
+
width: '70%'
|
242
|
+
}}
|
243
|
+
GA={{
|
244
|
+
category: 'Test',
|
245
|
+
actionId: 'Test'
|
246
|
+
}}
|
247
|
+
onSelectedDate={dates=>setState({dates})}
|
248
|
+
typeable
|
249
|
+
/>
|
250
|
+
```
|