bright-components 10.1.0 → 10.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- })), dayPickerOpen && _react.default.createElement(DayRangeContainer, {
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')}`;
@@ -11,6 +11,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
11
11
 
12
12
  const ModalBody = _styledComponents.default.div`
13
13
  padding: ${props => props.noPadding ? '0px' : _spacing.default.s2};
14
+ overflow-y: auto;
14
15
  `;
15
16
  ModalBody.displayName = 'ModalBody';
16
17
  /* @component */
@@ -55,6 +55,8 @@ const Background = _styledComponents.default.div`
55
55
  align-items: center;
56
56
  `;
57
57
  const ModalContainer = _styledComponents.default.div`
58
+ display: flex;
59
+ flex-direction: column;
58
60
  background: white;
59
61
  position: relative;
60
62
  width: ${props => props.width};
@@ -64,7 +66,6 @@ const ModalContainer = _styledComponents.default.div`
64
66
  border-radius: ${_vars.default.borderRadius};
65
67
  max-height: 90%;
66
68
  overflow-x: hidden;
67
- overflow-y: auto;
68
69
  ${props => props.version === '1' && '-webkit-overflow-scrolling: touch'};
69
70
 
70
71
  ${props => props.allowOverflow && (0, _styledComponents.css)`
@@ -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
 
@@ -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.1.0",
3
+ "version": "10.2.1",
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": "^7.0.1",
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
+ ```