@contentful/field-editor-date 2.0.8-canary.0 → 2.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,6 +11,12 @@ Object.defineProperty(exports, "DatepickerInput", {
11
11
  const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
12
12
  const _f36components = require("@contentful/f36-components");
13
13
  const _css = require("@emotion/css");
14
+ const _moment = /*#__PURE__*/ _interop_require_default(require("moment"));
15
+ function _interop_require_default(obj) {
16
+ return obj && obj.__esModule ? obj : {
17
+ default: obj
18
+ };
19
+ }
14
20
  function _getRequireWildcardCache(nodeInterop) {
15
21
  if (typeof WeakMap !== "function") return null;
16
22
  var cacheBabelInterop = new WeakMap();
@@ -69,12 +75,14 @@ const DatepickerInput = (props)=>{
69
75
  toDate
70
76
  ];
71
77
  }, []);
72
- const selectedDate = props.value;
78
+ const dateObj = props.value?.toObject();
79
+ const selectedDate = dateObj ? new Date(dateObj.years, dateObj.months, dateObj.date) : undefined;
73
80
  return /*#__PURE__*/ _react.default.createElement(_f36components.Datepicker, {
74
81
  className: styles.root,
75
82
  selected: selectedDate,
76
83
  onSelect: (day)=>{
77
- props.onChange(day ?? undefined);
84
+ const momentDay = day ? (0, _moment.default)(day) : undefined;
85
+ props.onChange(momentDay);
78
86
  },
79
87
  inputProps: {
80
88
  isDisabled: props.disabled,
@@ -11,7 +11,12 @@ Object.defineProperty(exports, "TimepickerInput", {
11
11
  const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
12
12
  const _f36components = require("@contentful/f36-components");
13
13
  const _css = require("@emotion/css");
14
- const _datefns = require("date-fns");
14
+ const _moment = /*#__PURE__*/ _interop_require_default(require("moment"));
15
+ function _interop_require_default(obj) {
16
+ return obj && obj.__esModule ? obj : {
17
+ default: obj
18
+ };
19
+ }
15
20
  function _getRequireWildcardCache(nodeInterop) {
16
21
  if (typeof WeakMap !== "function") return null;
17
22
  var cacheBabelInterop = new WeakMap();
@@ -55,49 +60,76 @@ function _interop_require_wildcard(obj, nodeInterop) {
55
60
  }
56
61
  const validInputFormats = [
57
62
  'hh:mm a',
63
+ 'hh:mm A',
58
64
  'h:mm a',
65
+ 'h:mm A',
59
66
  'hh:mm',
60
- 'H:mm',
67
+ 'k:mm',
68
+ 'kk:mm',
61
69
  'h a',
62
- 'h'
70
+ 'h A',
71
+ 'h',
72
+ 'hh',
73
+ 'HH'
63
74
  ];
64
- const REF_DATE = new Date(2000, 0, 1);
65
75
  function parseRawInput(raw) {
66
- for (const fmt of validInputFormats){
67
- const parsed = (0, _datefns.parse)(raw, fmt, REF_DATE);
68
- if ((0, _datefns.isValid)(parsed)) return parsed;
76
+ let time = null;
77
+ for(let i = 0; i < validInputFormats.length; i++){
78
+ const date = (0, _moment.default)(raw, validInputFormats[i]);
79
+ if (date.isValid()) {
80
+ time = date;
81
+ break;
82
+ }
69
83
  }
70
- return null;
84
+ return time;
71
85
  }
72
- const getDefaultTime = ()=>(0, _datefns.parse)('12:00 AM', 'hh:mm a', REF_DATE);
73
- const formatToString = (uses12hClock, value)=>(0, _datefns.format)(value, uses12hClock ? 'hh:mm a' : 'HH:mm');
86
+ const getDefaultTime = ()=>{
87
+ return (0, _moment.default)(`12:00 AM`, 'hh:mm A');
88
+ };
89
+ const formatToString = (uses12hClock, value)=>{
90
+ return uses12hClock ? value.format('hh:mm A') : value.format('HH:mm');
91
+ };
74
92
  const TimepickerInput = ({ disabled, uses12hClock, time = '12:00', ampm = 'AM', onChange })=>{
75
93
  const [selectedTime, setSelectedTime] = (0, _react.useState)(()=>{
76
94
  return formatToString(uses12hClock, getDefaultTime());
77
95
  });
78
96
  (0, _react.useEffect)(()=>{
79
- setSelectedTime(formatToString(uses12hClock, (0, _datefns.parse)(`${time} ${ampm}`, 'hh:mm a', REF_DATE)));
97
+ setSelectedTime(formatToString(uses12hClock, (0, _moment.default)(`${time} ${ampm}`, 'hh:mm A')));
80
98
  }, [
81
99
  time,
82
100
  ampm,
83
101
  uses12hClock
84
102
  ]);
85
103
  const handleChange = (0, _react.useCallback)((e)=>{
86
- setSelectedTime(e.currentTarget.value);
87
- }, []);
104
+ const raw = e.currentTarget.value;
105
+ setSelectedTime(raw);
106
+ const parsedTime = parseRawInput(raw);
107
+ if (parsedTime) {
108
+ onChange({
109
+ time: parsedTime.format('hh:mm'),
110
+ ampm: parsedTime.format('A')
111
+ });
112
+ }
113
+ }, [
114
+ onChange
115
+ ]);
88
116
  const handleFocus = (0, _react.useCallback)((e)=>{
89
117
  e.preventDefault();
90
118
  e.target.select();
91
119
  }, []);
92
- const handleBlur = ()=>{
120
+ const handleBlur = (0, _react.useCallback)(()=>{
93
121
  const parsedTime = parseRawInput(selectedTime);
94
122
  const value = parsedTime ?? getDefaultTime();
95
123
  setSelectedTime(formatToString(uses12hClock, value));
96
124
  onChange({
97
- time: (0, _datefns.format)(value, 'hh:mm'),
98
- ampm: (0, _datefns.format)(value, 'a').toUpperCase()
125
+ time: value.format('hh:mm'),
126
+ ampm: value.format('A')
99
127
  });
100
- };
128
+ }, [
129
+ selectedTime,
130
+ uses12hClock,
131
+ onChange
132
+ ]);
101
133
  return /*#__PURE__*/ _react.default.createElement(_f36components.Flex, {
102
134
  className: (0, _css.css)({
103
135
  width: '145px'
@@ -2,13 +2,19 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
+ const _moment = /*#__PURE__*/ _interop_require_default(require("moment"));
5
6
  const _date = require("./date");
7
+ function _interop_require_default(obj) {
8
+ return obj && obj.__esModule ? obj : {
9
+ default: obj
10
+ };
11
+ }
6
12
  describe('date utils', ()=>{
7
13
  describe('buildFieldValue', ()=>{
8
14
  it('should work properly', ()=>{
9
15
  expect((0, _date.buildFieldValue)({
10
16
  data: {
11
- date: new Date('2018-02-02'),
17
+ date: (0, _moment.default)('2018-02-02'),
12
18
  time: '05:00',
13
19
  ampm: 'PM',
14
20
  utcOffset: '+03:00'
@@ -21,7 +27,7 @@ describe('date utils', ()=>{
21
27
  });
22
28
  expect((0, _date.buildFieldValue)({
23
29
  data: {
24
- date: new Date('2015-01-14'),
30
+ date: (0, _moment.default)('2015-01-14'),
25
31
  time: '05:00',
26
32
  ampm: 'AM',
27
33
  utcOffset: '-05:00'
@@ -34,7 +40,7 @@ describe('date utils', ()=>{
34
40
  });
35
41
  expect((0, _date.buildFieldValue)({
36
42
  data: {
37
- date: new Date('2015-01-14'),
43
+ date: (0, _moment.default)('2015-01-14'),
38
44
  time: '17:00',
39
45
  ampm: 'PM',
40
46
  utcOffset: '-05:00'
@@ -46,135 +52,5 @@ describe('date utils', ()=>{
46
52
  valid: '2015-01-14T17:00-05:00'
47
53
  });
48
54
  });
49
- it('returns date-only format when usesTime and usesTimezone are false', ()=>{
50
- expect((0, _date.buildFieldValue)({
51
- data: {
52
- date: new Date('2020-06-15'),
53
- time: '10:30',
54
- ampm: 'AM',
55
- utcOffset: '+00:00'
56
- },
57
- usesTimezone: false,
58
- usesTime: false
59
- })).toEqual({
60
- invalid: false,
61
- valid: '2020-06-15'
62
- });
63
- });
64
- it('returns datetime without timezone when usesTime=true, usesTimezone=false', ()=>{
65
- expect((0, _date.buildFieldValue)({
66
- data: {
67
- date: new Date('2020-06-15'),
68
- time: '14:30',
69
- ampm: 'PM',
70
- utcOffset: '+00:00'
71
- },
72
- usesTimezone: false,
73
- usesTime: true
74
- })).toEqual({
75
- invalid: false,
76
- valid: '2020-06-15T14:30'
77
- });
78
- });
79
- it('returns valid: null when no date is provided', ()=>{
80
- expect((0, _date.buildFieldValue)({
81
- data: {
82
- time: '10:00',
83
- ampm: 'AM',
84
- utcOffset: '+00:00'
85
- },
86
- usesTimezone: true,
87
- usesTime: true
88
- })).toEqual({
89
- invalid: false,
90
- valid: null
91
- });
92
- });
93
- it('handles midnight (12:00 AM) correctly', ()=>{
94
- expect((0, _date.buildFieldValue)({
95
- data: {
96
- date: new Date('2021-03-01'),
97
- time: '12:00',
98
- ampm: 'AM',
99
- utcOffset: '+00:00'
100
- },
101
- usesTimezone: true,
102
- usesTime: true
103
- })).toEqual({
104
- invalid: false,
105
- valid: '2021-03-01T00:00+00:00'
106
- });
107
- });
108
- it('handles noon (12:00 PM) correctly', ()=>{
109
- expect((0, _date.buildFieldValue)({
110
- data: {
111
- date: new Date('2021-03-01'),
112
- time: '12:00',
113
- ampm: 'PM',
114
- utcOffset: '+00:00'
115
- },
116
- usesTimezone: true,
117
- usesTime: true
118
- })).toEqual({
119
- invalid: false,
120
- valid: '2021-03-01T12:00+00:00'
121
- });
122
- });
123
- });
124
- describe('userInputFromDatetime', ()=>{
125
- it('parses a full ISO datetime string with timezone', ()=>{
126
- const result = (0, _date.userInputFromDatetime)({
127
- value: '2018-02-02T17:00+03:00',
128
- uses12hClock: false
129
- });
130
- expect(result.time).toBe('17:00');
131
- expect(result.ampm).toBe('PM');
132
- expect(result.utcOffset).toBe('+03:00');
133
- });
134
- it('parses a full ISO datetime string with 12h clock', ()=>{
135
- const result = (0, _date.userInputFromDatetime)({
136
- value: '2018-02-02T05:00+03:00',
137
- uses12hClock: true
138
- });
139
- expect(result.time).toBe('05:00');
140
- expect(result.ampm).toBe('AM');
141
- expect(result.utcOffset).toBe('+03:00');
142
- });
143
- it('returns defaults when value is null', ()=>{
144
- const result = (0, _date.userInputFromDatetime)({
145
- value: null,
146
- uses12hClock: false
147
- });
148
- expect(result.date).toBeUndefined();
149
- expect(result.ampm).toBe((0, _date.getDefaultAMPM)());
150
- expect(result.utcOffset).toBe((0, _date.getDefaultUtcOffset)());
151
- });
152
- it('returns defaults when value is undefined', ()=>{
153
- const result = (0, _date.userInputFromDatetime)({
154
- value: undefined,
155
- uses12hClock: false
156
- });
157
- expect(result.date).toBeUndefined();
158
- expect(result.ampm).toBe((0, _date.getDefaultAMPM)());
159
- });
160
- it('returns defaults when value is empty string', ()=>{
161
- const result = (0, _date.userInputFromDatetime)({
162
- value: '',
163
- uses12hClock: false
164
- });
165
- expect(result.date).toBeUndefined();
166
- });
167
- it('parses a date-only string', ()=>{
168
- const result = (0, _date.userInputFromDatetime)({
169
- value: '2022-09-16',
170
- uses12hClock: false
171
- });
172
- expect(result.utcOffset).toBe('+00:00');
173
- });
174
- });
175
- describe('getDefaultAMPM', ()=>{
176
- it('returns AM', ()=>{
177
- expect((0, _date.getDefaultAMPM)()).toBe('AM');
178
- });
179
55
  });
180
56
  });
@@ -22,36 +22,32 @@ _export(exports, {
22
22
  return userInputFromDatetime;
23
23
  }
24
24
  });
25
- const _datefns = require("date-fns");
26
- const ZONE_RX = /(Z|[+-]\d{2}[:+]?\d{2})$/;
27
- function startOfTodayOffset() {
28
- return (0, _datefns.format)(new Date(), 'xxx');
25
+ const _moment = /*#__PURE__*/ _interop_require_default(require("moment"));
26
+ function _interop_require_default(obj) {
27
+ return obj && obj.__esModule ? obj : {
28
+ default: obj
29
+ };
29
30
  }
30
- function parseUtcOffset(datetimeString) {
31
- const match = datetimeString.match(ZONE_RX);
32
- return match ? match[1] : '+00:00';
31
+ const ZONE_RX = /(Z|[+-]\d{2}[:+]?\d{2})$/;
32
+ function startOfToday(format) {
33
+ return (0, _moment.default)().set({
34
+ hours: 0,
35
+ minutes: 0
36
+ }).format(format);
33
37
  }
34
- function fieldValueToDate(datetimeString) {
38
+ function fieldValueToMoment(datetimeString) {
35
39
  if (!datetimeString) {
36
40
  return null;
37
41
  }
38
- const date = (0, _datefns.parseISO)(datetimeString);
39
- return (0, _datefns.isValid)(date) ? date : null;
42
+ const datetime = (0, _moment.default)(datetimeString);
43
+ if (ZONE_RX.test(datetimeString)) {
44
+ datetime.utcOffset(datetimeString);
45
+ }
46
+ return datetime;
40
47
  }
41
48
  function timeFromUserInput(input) {
42
49
  const timeInput = input.time || '00:00';
43
- const parsed = (0, _datefns.parse)(timeInput, 'HH:mm', new Date(0));
44
- let hours = (0, _datefns.getHours)(parsed);
45
- const minutes = (0, _datefns.getMinutes)(parsed);
46
- if (input.ampm === 'PM' && hours < 12) {
47
- hours += 12;
48
- } else if (input.ampm === 'AM' && hours === 12) {
49
- hours = 0;
50
- }
51
- return {
52
- hours,
53
- minutes
54
- };
50
+ return _moment.default.utc(timeInput + '!' + input.ampm, 'HH:mm!A');
55
51
  }
56
52
  function datetimeFromUserInput(input) {
57
53
  if (!input.date) {
@@ -59,14 +55,12 @@ function datetimeFromUserInput(input) {
59
55
  valid: null
60
56
  };
61
57
  }
62
- const { hours, minutes } = timeFromUserInput(input);
63
- const date = (0, _datefns.set)(input.date, {
64
- hours,
65
- minutes,
66
- seconds: 0,
67
- milliseconds: 0
58
+ const time = timeFromUserInput(input);
59
+ const date = _moment.default.parseZone(input.utcOffset, 'Z').set(input.date.toObject()).set({
60
+ hours: time.hours(),
61
+ minutes: time.minutes()
68
62
  });
69
- if ((0, _datefns.isValid)(date)) {
63
+ if (date.isValid()) {
70
64
  return {
71
65
  valid: date
72
66
  };
@@ -84,58 +78,34 @@ function buildFieldValue({ data, usesTime, usesTimezone }) {
84
78
  invalid: true
85
79
  };
86
80
  }
87
- if (!date.valid) {
88
- return {
89
- valid: null,
90
- invalid: false
91
- };
92
- }
81
+ let format;
93
82
  if (usesTimezone) {
94
- return {
95
- valid: (0, _datefns.format)(date.valid, "yyyy-MM-dd'T'HH:mm") + data.utcOffset,
96
- invalid: false
97
- };
83
+ format = 'YYYY-MM-DDTHH:mmZ';
98
84
  } else if (usesTime) {
99
- return {
100
- valid: (0, _datefns.format)(date.valid, "yyyy-MM-dd'T'HH:mm"),
101
- invalid: false
102
- };
85
+ format = 'YYYY-MM-DDTHH:mm';
103
86
  } else {
104
- return {
105
- valid: (0, _datefns.format)(date.valid, 'yyyy-MM-dd'),
106
- invalid: false
107
- };
87
+ format = 'YYYY-MM-DD';
108
88
  }
89
+ return {
90
+ valid: date?.valid ? date.valid.format(format) : null,
91
+ invalid: false
92
+ };
109
93
  }
110
94
  function getDefaultAMPM() {
111
95
  return 'AM';
112
96
  }
113
97
  function getDefaultUtcOffset() {
114
- return startOfTodayOffset();
115
- }
116
- function extractTimeFromIso(value) {
117
- const match = value.match(/T(\d{2}:\d{2})/);
118
- return match ? match[1] : undefined;
98
+ return startOfToday('Z');
119
99
  }
120
100
  function userInputFromDatetime({ value, uses12hClock }) {
121
- const datetime = fieldValueToDate(value);
122
- if (datetime && value) {
123
- const rawTime = extractTimeFromIso(value);
124
- const timeDate = rawTime ? (0, _datefns.parse)(rawTime, 'HH:mm', new Date(0)) : datetime;
125
- const hours = (0, _datefns.getHours)(timeDate);
126
- const ampm = hours < 12 ? 'AM' : 'PM';
127
- let time;
128
- if (uses12hClock) {
129
- const h12 = hours % 12 || 12;
130
- time = `${String(h12).padStart(2, '0')}:${String((0, _datefns.getMinutes)(timeDate)).padStart(2, '0')}`;
131
- } else {
132
- time = rawTime ?? (0, _datefns.format)(datetime, 'HH:mm');
133
- }
101
+ const datetime = fieldValueToMoment(value);
102
+ if (datetime) {
103
+ const timeFormat = uses12hClock ? 'hh:mm' : 'HH:mm';
134
104
  return {
135
105
  date: datetime,
136
- time,
137
- ampm,
138
- utcOffset: parseUtcOffset(value)
106
+ time: datetime.format(timeFormat),
107
+ ampm: datetime.format('A'),
108
+ utcOffset: datetime.format('Z')
139
109
  };
140
110
  } else {
141
111
  return {
@@ -1,6 +1,7 @@
1
1
  import React, { useMemo } from 'react';
2
2
  import { Datepicker } from '@contentful/f36-components';
3
3
  import { css } from '@emotion/css';
4
+ import moment from 'moment';
4
5
  const YEARS_INTO_FUTURE = 100;
5
6
  const MIN_YEAR = '1000';
6
7
  const styles = {
@@ -18,12 +19,14 @@ export const DatepickerInput = (props)=>{
18
19
  toDate
19
20
  ];
20
21
  }, []);
21
- const selectedDate = props.value;
22
+ const dateObj = props.value?.toObject();
23
+ const selectedDate = dateObj ? new Date(dateObj.years, dateObj.months, dateObj.date) : undefined;
22
24
  return /*#__PURE__*/ React.createElement(Datepicker, {
23
25
  className: styles.root,
24
26
  selected: selectedDate,
25
27
  onSelect: (day)=>{
26
- props.onChange(day ?? undefined);
28
+ const momentDay = day ? moment(day) : undefined;
29
+ props.onChange(momentDay);
27
30
  },
28
31
  inputProps: {
29
32
  isDisabled: props.disabled,
@@ -1,52 +1,79 @@
1
1
  import React, { useState, useCallback, useEffect } from 'react';
2
2
  import { TextInput, Flex } from '@contentful/f36-components';
3
3
  import { css } from '@emotion/css';
4
- import { parse, format, isValid } from 'date-fns';
4
+ import moment from 'moment';
5
5
  const validInputFormats = [
6
6
  'hh:mm a',
7
+ 'hh:mm A',
7
8
  'h:mm a',
9
+ 'h:mm A',
8
10
  'hh:mm',
9
- 'H:mm',
11
+ 'k:mm',
12
+ 'kk:mm',
10
13
  'h a',
11
- 'h'
14
+ 'h A',
15
+ 'h',
16
+ 'hh',
17
+ 'HH'
12
18
  ];
13
- const REF_DATE = new Date(2000, 0, 1);
14
19
  function parseRawInput(raw) {
15
- for (const fmt of validInputFormats){
16
- const parsed = parse(raw, fmt, REF_DATE);
17
- if (isValid(parsed)) return parsed;
20
+ let time = null;
21
+ for(let i = 0; i < validInputFormats.length; i++){
22
+ const date = moment(raw, validInputFormats[i]);
23
+ if (date.isValid()) {
24
+ time = date;
25
+ break;
26
+ }
18
27
  }
19
- return null;
28
+ return time;
20
29
  }
21
- const getDefaultTime = ()=>parse('12:00 AM', 'hh:mm a', REF_DATE);
22
- const formatToString = (uses12hClock, value)=>format(value, uses12hClock ? 'hh:mm a' : 'HH:mm');
30
+ const getDefaultTime = ()=>{
31
+ return moment(`12:00 AM`, 'hh:mm A');
32
+ };
33
+ const formatToString = (uses12hClock, value)=>{
34
+ return uses12hClock ? value.format('hh:mm A') : value.format('HH:mm');
35
+ };
23
36
  export const TimepickerInput = ({ disabled, uses12hClock, time = '12:00', ampm = 'AM', onChange })=>{
24
37
  const [selectedTime, setSelectedTime] = useState(()=>{
25
38
  return formatToString(uses12hClock, getDefaultTime());
26
39
  });
27
40
  useEffect(()=>{
28
- setSelectedTime(formatToString(uses12hClock, parse(`${time} ${ampm}`, 'hh:mm a', REF_DATE)));
41
+ setSelectedTime(formatToString(uses12hClock, moment(`${time} ${ampm}`, 'hh:mm A')));
29
42
  }, [
30
43
  time,
31
44
  ampm,
32
45
  uses12hClock
33
46
  ]);
34
47
  const handleChange = useCallback((e)=>{
35
- setSelectedTime(e.currentTarget.value);
36
- }, []);
48
+ const raw = e.currentTarget.value;
49
+ setSelectedTime(raw);
50
+ const parsedTime = parseRawInput(raw);
51
+ if (parsedTime) {
52
+ onChange({
53
+ time: parsedTime.format('hh:mm'),
54
+ ampm: parsedTime.format('A')
55
+ });
56
+ }
57
+ }, [
58
+ onChange
59
+ ]);
37
60
  const handleFocus = useCallback((e)=>{
38
61
  e.preventDefault();
39
62
  e.target.select();
40
63
  }, []);
41
- const handleBlur = ()=>{
64
+ const handleBlur = useCallback(()=>{
42
65
  const parsedTime = parseRawInput(selectedTime);
43
66
  const value = parsedTime ?? getDefaultTime();
44
67
  setSelectedTime(formatToString(uses12hClock, value));
45
68
  onChange({
46
- time: format(value, 'hh:mm'),
47
- ampm: format(value, 'a').toUpperCase()
69
+ time: value.format('hh:mm'),
70
+ ampm: value.format('A')
48
71
  });
49
- };
72
+ }, [
73
+ selectedTime,
74
+ uses12hClock,
75
+ onChange
76
+ ]);
50
77
  return /*#__PURE__*/ React.createElement(Flex, {
51
78
  className: css({
52
79
  width: '145px'
@@ -1,10 +1,11 @@
1
- import { buildFieldValue, userInputFromDatetime, getDefaultAMPM, getDefaultUtcOffset } from './date';
1
+ import moment from 'moment';
2
+ import { buildFieldValue } from './date';
2
3
  describe('date utils', ()=>{
3
4
  describe('buildFieldValue', ()=>{
4
5
  it('should work properly', ()=>{
5
6
  expect(buildFieldValue({
6
7
  data: {
7
- date: new Date('2018-02-02'),
8
+ date: moment('2018-02-02'),
8
9
  time: '05:00',
9
10
  ampm: 'PM',
10
11
  utcOffset: '+03:00'
@@ -17,7 +18,7 @@ describe('date utils', ()=>{
17
18
  });
18
19
  expect(buildFieldValue({
19
20
  data: {
20
- date: new Date('2015-01-14'),
21
+ date: moment('2015-01-14'),
21
22
  time: '05:00',
22
23
  ampm: 'AM',
23
24
  utcOffset: '-05:00'
@@ -30,7 +31,7 @@ describe('date utils', ()=>{
30
31
  });
31
32
  expect(buildFieldValue({
32
33
  data: {
33
- date: new Date('2015-01-14'),
34
+ date: moment('2015-01-14'),
34
35
  time: '17:00',
35
36
  ampm: 'PM',
36
37
  utcOffset: '-05:00'
@@ -42,135 +43,5 @@ describe('date utils', ()=>{
42
43
  valid: '2015-01-14T17:00-05:00'
43
44
  });
44
45
  });
45
- it('returns date-only format when usesTime and usesTimezone are false', ()=>{
46
- expect(buildFieldValue({
47
- data: {
48
- date: new Date('2020-06-15'),
49
- time: '10:30',
50
- ampm: 'AM',
51
- utcOffset: '+00:00'
52
- },
53
- usesTimezone: false,
54
- usesTime: false
55
- })).toEqual({
56
- invalid: false,
57
- valid: '2020-06-15'
58
- });
59
- });
60
- it('returns datetime without timezone when usesTime=true, usesTimezone=false', ()=>{
61
- expect(buildFieldValue({
62
- data: {
63
- date: new Date('2020-06-15'),
64
- time: '14:30',
65
- ampm: 'PM',
66
- utcOffset: '+00:00'
67
- },
68
- usesTimezone: false,
69
- usesTime: true
70
- })).toEqual({
71
- invalid: false,
72
- valid: '2020-06-15T14:30'
73
- });
74
- });
75
- it('returns valid: null when no date is provided', ()=>{
76
- expect(buildFieldValue({
77
- data: {
78
- time: '10:00',
79
- ampm: 'AM',
80
- utcOffset: '+00:00'
81
- },
82
- usesTimezone: true,
83
- usesTime: true
84
- })).toEqual({
85
- invalid: false,
86
- valid: null
87
- });
88
- });
89
- it('handles midnight (12:00 AM) correctly', ()=>{
90
- expect(buildFieldValue({
91
- data: {
92
- date: new Date('2021-03-01'),
93
- time: '12:00',
94
- ampm: 'AM',
95
- utcOffset: '+00:00'
96
- },
97
- usesTimezone: true,
98
- usesTime: true
99
- })).toEqual({
100
- invalid: false,
101
- valid: '2021-03-01T00:00+00:00'
102
- });
103
- });
104
- it('handles noon (12:00 PM) correctly', ()=>{
105
- expect(buildFieldValue({
106
- data: {
107
- date: new Date('2021-03-01'),
108
- time: '12:00',
109
- ampm: 'PM',
110
- utcOffset: '+00:00'
111
- },
112
- usesTimezone: true,
113
- usesTime: true
114
- })).toEqual({
115
- invalid: false,
116
- valid: '2021-03-01T12:00+00:00'
117
- });
118
- });
119
- });
120
- describe('userInputFromDatetime', ()=>{
121
- it('parses a full ISO datetime string with timezone', ()=>{
122
- const result = userInputFromDatetime({
123
- value: '2018-02-02T17:00+03:00',
124
- uses12hClock: false
125
- });
126
- expect(result.time).toBe('17:00');
127
- expect(result.ampm).toBe('PM');
128
- expect(result.utcOffset).toBe('+03:00');
129
- });
130
- it('parses a full ISO datetime string with 12h clock', ()=>{
131
- const result = userInputFromDatetime({
132
- value: '2018-02-02T05:00+03:00',
133
- uses12hClock: true
134
- });
135
- expect(result.time).toBe('05:00');
136
- expect(result.ampm).toBe('AM');
137
- expect(result.utcOffset).toBe('+03:00');
138
- });
139
- it('returns defaults when value is null', ()=>{
140
- const result = userInputFromDatetime({
141
- value: null,
142
- uses12hClock: false
143
- });
144
- expect(result.date).toBeUndefined();
145
- expect(result.ampm).toBe(getDefaultAMPM());
146
- expect(result.utcOffset).toBe(getDefaultUtcOffset());
147
- });
148
- it('returns defaults when value is undefined', ()=>{
149
- const result = userInputFromDatetime({
150
- value: undefined,
151
- uses12hClock: false
152
- });
153
- expect(result.date).toBeUndefined();
154
- expect(result.ampm).toBe(getDefaultAMPM());
155
- });
156
- it('returns defaults when value is empty string', ()=>{
157
- const result = userInputFromDatetime({
158
- value: '',
159
- uses12hClock: false
160
- });
161
- expect(result.date).toBeUndefined();
162
- });
163
- it('parses a date-only string', ()=>{
164
- const result = userInputFromDatetime({
165
- value: '2022-09-16',
166
- uses12hClock: false
167
- });
168
- expect(result.utcOffset).toBe('+00:00');
169
- });
170
- });
171
- describe('getDefaultAMPM', ()=>{
172
- it('returns AM', ()=>{
173
- expect(getDefaultAMPM()).toBe('AM');
174
- });
175
46
  });
176
47
  });
@@ -1,33 +1,24 @@
1
- import { format, getHours, getMinutes, isValid, parse, parseISO, set } from 'date-fns';
1
+ import moment from 'moment';
2
2
  const ZONE_RX = /(Z|[+-]\d{2}[:+]?\d{2})$/;
3
- function startOfTodayOffset() {
4
- return format(new Date(), 'xxx');
3
+ function startOfToday(format) {
4
+ return moment().set({
5
+ hours: 0,
6
+ minutes: 0
7
+ }).format(format);
5
8
  }
6
- function parseUtcOffset(datetimeString) {
7
- const match = datetimeString.match(ZONE_RX);
8
- return match ? match[1] : '+00:00';
9
- }
10
- function fieldValueToDate(datetimeString) {
9
+ function fieldValueToMoment(datetimeString) {
11
10
  if (!datetimeString) {
12
11
  return null;
13
12
  }
14
- const date = parseISO(datetimeString);
15
- return isValid(date) ? date : null;
13
+ const datetime = moment(datetimeString);
14
+ if (ZONE_RX.test(datetimeString)) {
15
+ datetime.utcOffset(datetimeString);
16
+ }
17
+ return datetime;
16
18
  }
17
19
  function timeFromUserInput(input) {
18
20
  const timeInput = input.time || '00:00';
19
- const parsed = parse(timeInput, 'HH:mm', new Date(0));
20
- let hours = getHours(parsed);
21
- const minutes = getMinutes(parsed);
22
- if (input.ampm === 'PM' && hours < 12) {
23
- hours += 12;
24
- } else if (input.ampm === 'AM' && hours === 12) {
25
- hours = 0;
26
- }
27
- return {
28
- hours,
29
- minutes
30
- };
21
+ return moment.utc(timeInput + '!' + input.ampm, 'HH:mm!A');
31
22
  }
32
23
  function datetimeFromUserInput(input) {
33
24
  if (!input.date) {
@@ -35,14 +26,12 @@ function datetimeFromUserInput(input) {
35
26
  valid: null
36
27
  };
37
28
  }
38
- const { hours, minutes } = timeFromUserInput(input);
39
- const date = set(input.date, {
40
- hours,
41
- minutes,
42
- seconds: 0,
43
- milliseconds: 0
29
+ const time = timeFromUserInput(input);
30
+ const date = moment.parseZone(input.utcOffset, 'Z').set(input.date.toObject()).set({
31
+ hours: time.hours(),
32
+ minutes: time.minutes()
44
33
  });
45
- if (isValid(date)) {
34
+ if (date.isValid()) {
46
35
  return {
47
36
  valid: date
48
37
  };
@@ -60,58 +49,34 @@ export function buildFieldValue({ data, usesTime, usesTimezone }) {
60
49
  invalid: true
61
50
  };
62
51
  }
63
- if (!date.valid) {
64
- return {
65
- valid: null,
66
- invalid: false
67
- };
68
- }
52
+ let format;
69
53
  if (usesTimezone) {
70
- return {
71
- valid: format(date.valid, "yyyy-MM-dd'T'HH:mm") + data.utcOffset,
72
- invalid: false
73
- };
54
+ format = 'YYYY-MM-DDTHH:mmZ';
74
55
  } else if (usesTime) {
75
- return {
76
- valid: format(date.valid, "yyyy-MM-dd'T'HH:mm"),
77
- invalid: false
78
- };
56
+ format = 'YYYY-MM-DDTHH:mm';
79
57
  } else {
80
- return {
81
- valid: format(date.valid, 'yyyy-MM-dd'),
82
- invalid: false
83
- };
58
+ format = 'YYYY-MM-DD';
84
59
  }
60
+ return {
61
+ valid: date?.valid ? date.valid.format(format) : null,
62
+ invalid: false
63
+ };
85
64
  }
86
65
  export function getDefaultAMPM() {
87
66
  return 'AM';
88
67
  }
89
68
  export function getDefaultUtcOffset() {
90
- return startOfTodayOffset();
91
- }
92
- function extractTimeFromIso(value) {
93
- const match = value.match(/T(\d{2}:\d{2})/);
94
- return match ? match[1] : undefined;
69
+ return startOfToday('Z');
95
70
  }
96
71
  export function userInputFromDatetime({ value, uses12hClock }) {
97
- const datetime = fieldValueToDate(value);
98
- if (datetime && value) {
99
- const rawTime = extractTimeFromIso(value);
100
- const timeDate = rawTime ? parse(rawTime, 'HH:mm', new Date(0)) : datetime;
101
- const hours = getHours(timeDate);
102
- const ampm = hours < 12 ? 'AM' : 'PM';
103
- let time;
104
- if (uses12hClock) {
105
- const h12 = hours % 12 || 12;
106
- time = `${String(h12).padStart(2, '0')}:${String(getMinutes(timeDate)).padStart(2, '0')}`;
107
- } else {
108
- time = rawTime ?? format(datetime, 'HH:mm');
109
- }
72
+ const datetime = fieldValueToMoment(value);
73
+ if (datetime) {
74
+ const timeFormat = uses12hClock ? 'hh:mm' : 'HH:mm';
110
75
  return {
111
76
  date: datetime,
112
- time,
113
- ampm,
114
- utcOffset: parseUtcOffset(value)
77
+ time: datetime.format(timeFormat),
78
+ ampm: datetime.format('A'),
79
+ utcOffset: datetime.format('Z')
115
80
  };
116
81
  } else {
117
82
  return {
@@ -1,7 +1,8 @@
1
1
  import React from 'react';
2
+ import moment from 'moment';
2
3
  export type DatePickerProps = {
3
- value?: Date;
4
- onChange: (val: Date | undefined) => void;
4
+ value?: moment.Moment;
5
+ onChange: (val: moment.Moment | undefined) => void;
5
6
  disabled?: boolean;
6
7
  };
7
8
  export declare const DatepickerInput: (props: DatePickerProps) => React.JSX.Element;
@@ -1,7 +1,8 @@
1
+ import moment from 'moment';
1
2
  export type DateTimeFormat = 'dateonly' | 'time' | 'timeZ';
2
3
  export type TimeFormat = '12' | '24';
3
4
  export type TimeResult = {
4
- date?: Date;
5
+ date?: moment.Moment;
5
6
  time?: string;
6
7
  ampm: string;
7
8
  utcOffset: string;
@@ -13,10 +13,7 @@ export declare function buildFieldValue({ data, usesTime, usesTimezone, }: {
13
13
  invalid: boolean;
14
14
  valid?: undefined;
15
15
  } | {
16
- valid: null;
17
- invalid: boolean;
18
- } | {
19
- valid: string;
16
+ valid: string | null;
20
17
  invalid: boolean;
21
18
  };
22
19
  export declare function getDefaultAMPM(): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/field-editor-date",
3
- "version": "2.0.8-canary.0+d0604e80",
3
+ "version": "2.0.8",
4
4
  "main": "dist/cjs/index.js",
5
5
  "module": "dist/esm/index.js",
6
6
  "types": "dist/types/index.d.ts",
@@ -41,7 +41,7 @@
41
41
  "@contentful/f36-tokens": "^6.1.2",
42
42
  "@contentful/field-editor-shared": "^3.1.4",
43
43
  "@emotion/css": "^11.13.5",
44
- "date-fns": "^2.30.0"
44
+ "moment": "^2.20.0"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@babel/core": "^7.7.4",
@@ -57,5 +57,5 @@
57
57
  "publishConfig": {
58
58
  "registry": "https://npm.pkg.github.com/"
59
59
  },
60
- "gitHead": "d0604e80ea65d12805975ad34c70c5fd499457c5"
60
+ "gitHead": "d4f28439b71dc035df4efd4fde6284e46961e4fd"
61
61
  }