@contentful/field-editor-date 2.0.8-canary.2 → 2.0.9

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,52 +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
- 'kk:mm',
61
67
  'k:mm',
68
+ 'kk:mm',
62
69
  'h a',
63
- 'HH',
64
- 'H:mm',
65
- 'h'
70
+ 'h A',
71
+ 'h',
72
+ 'hh',
73
+ 'HH'
66
74
  ];
67
- const REF_DATE = new Date(2000, 0, 1);
68
75
  function parseRawInput(raw) {
69
- for (const fmt of validInputFormats){
70
- const parsed = (0, _datefns.parse)(raw, fmt, REF_DATE);
71
- 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
+ }
72
83
  }
73
- return null;
84
+ return time;
74
85
  }
75
- const getDefaultTime = ()=>(0, _datefns.parse)('12:00 AM', 'hh:mm a', REF_DATE);
76
- 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
+ };
77
92
  const TimepickerInput = ({ disabled, uses12hClock, time = '12:00', ampm = 'AM', onChange })=>{
78
93
  const [selectedTime, setSelectedTime] = (0, _react.useState)(()=>{
79
94
  return formatToString(uses12hClock, getDefaultTime());
80
95
  });
81
96
  (0, _react.useEffect)(()=>{
82
- 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')));
83
98
  }, [
84
99
  time,
85
100
  ampm,
86
101
  uses12hClock
87
102
  ]);
88
103
  const handleChange = (0, _react.useCallback)((e)=>{
89
- setSelectedTime(e.currentTarget.value);
90
- }, []);
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
+ ]);
91
116
  const handleFocus = (0, _react.useCallback)((e)=>{
92
117
  e.preventDefault();
93
118
  e.target.select();
94
119
  }, []);
95
- const handleBlur = ()=>{
120
+ const handleBlur = (0, _react.useCallback)(()=>{
96
121
  const parsedTime = parseRawInput(selectedTime);
97
122
  const value = parsedTime ?? getDefaultTime();
98
123
  setSelectedTime(formatToString(uses12hClock, value));
99
124
  onChange({
100
- time: (0, _datefns.format)(value, 'hh:mm'),
101
- ampm: (0, _datefns.format)(value, 'a').toUpperCase()
125
+ time: value.format('hh:mm'),
126
+ ampm: value.format('A')
102
127
  });
103
- };
128
+ }, [
129
+ selectedTime,
130
+ uses12hClock,
131
+ onChange
132
+ ]);
104
133
  return /*#__PURE__*/ _react.default.createElement(_f36components.Flex, {
105
134
  className: (0, _css.css)({
106
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'
@@ -49,7 +55,7 @@ describe('date utils', ()=>{
49
55
  it('returns date-only format when usesTime and usesTimezone are false', ()=>{
50
56
  expect((0, _date.buildFieldValue)({
51
57
  data: {
52
- date: new Date('2020-06-15'),
58
+ date: (0, _moment.default)('2020-06-15'),
53
59
  time: '10:30',
54
60
  ampm: 'AM',
55
61
  utcOffset: '+00:00'
@@ -64,7 +70,7 @@ describe('date utils', ()=>{
64
70
  it('returns datetime without timezone when usesTime=true, usesTimezone=false', ()=>{
65
71
  expect((0, _date.buildFieldValue)({
66
72
  data: {
67
- date: new Date('2020-06-15'),
73
+ date: (0, _moment.default)('2020-06-15'),
68
74
  time: '14:30',
69
75
  ampm: 'PM',
70
76
  utcOffset: '+00:00'
@@ -93,7 +99,7 @@ describe('date utils', ()=>{
93
99
  it('handles midnight (12:00 AM) correctly', ()=>{
94
100
  expect((0, _date.buildFieldValue)({
95
101
  data: {
96
- date: new Date('2021-03-01'),
102
+ date: (0, _moment.default)('2021-03-01'),
97
103
  time: '12:00',
98
104
  ampm: 'AM',
99
105
  utcOffset: '+00:00'
@@ -108,7 +114,7 @@ describe('date utils', ()=>{
108
114
  it('handles noon (12:00 PM) correctly', ()=>{
109
115
  expect((0, _date.buildFieldValue)({
110
116
  data: {
111
- date: new Date('2021-03-01'),
117
+ date: (0, _moment.default)('2021-03-01'),
112
118
  time: '12:00',
113
119
  ampm: 'PM',
114
120
  utcOffset: '+00:00'
@@ -123,7 +129,7 @@ describe('date utils', ()=>{
123
129
  it('preserves half-hour offset +05:30 (India)', ()=>{
124
130
  expect((0, _date.buildFieldValue)({
125
131
  data: {
126
- date: new Date('2023-08-15'),
132
+ date: (0, _moment.default)('2023-08-15'),
127
133
  time: '10:00',
128
134
  ampm: 'AM',
129
135
  utcOffset: '+05:30'
@@ -138,7 +144,7 @@ describe('date utils', ()=>{
138
144
  it('preserves negative half-hour offset -09:30', ()=>{
139
145
  expect((0, _date.buildFieldValue)({
140
146
  data: {
141
- date: new Date('2023-08-15'),
147
+ date: (0, _moment.default)('2023-08-15'),
142
148
  time: '03:30',
143
149
  ampm: 'AM',
144
150
  utcOffset: '-09:30'
@@ -153,7 +159,7 @@ describe('date utils', ()=>{
153
159
  it('preserves quarter-hour offset +05:45 (Nepal)', ()=>{
154
160
  expect((0, _date.buildFieldValue)({
155
161
  data: {
156
- date: new Date('2023-08-15'),
162
+ date: (0, _moment.default)('2023-08-15'),
157
163
  time: '05:45',
158
164
  ampm: 'AM',
159
165
  utcOffset: '+05:45'
@@ -168,7 +174,7 @@ describe('date utils', ()=>{
168
174
  it('preserves UTC +00:00 offset', ()=>{
169
175
  expect((0, _date.buildFieldValue)({
170
176
  data: {
171
- date: new Date('2023-01-01'),
177
+ date: (0, _moment.default)('2023-01-01'),
172
178
  time: '00:00',
173
179
  ampm: 'AM',
174
180
  utcOffset: '+00:00'
@@ -183,7 +189,7 @@ describe('date utils', ()=>{
183
189
  it('preserves far-west offset -12:00', ()=>{
184
190
  expect((0, _date.buildFieldValue)({
185
191
  data: {
186
- date: new Date('2023-01-01'),
192
+ date: (0, _moment.default)('2023-01-01'),
187
193
  time: '23:59',
188
194
  ampm: 'PM',
189
195
  utcOffset: '-12:00'
@@ -198,7 +204,7 @@ describe('date utils', ()=>{
198
204
  it('preserves far-east offset +14:00', ()=>{
199
205
  expect((0, _date.buildFieldValue)({
200
206
  data: {
201
- date: new Date('2023-01-01'),
207
+ date: (0, _moment.default)('2023-01-01'),
202
208
  time: '01:00',
203
209
  ampm: 'AM',
204
210
  utcOffset: '+14:00'
@@ -213,7 +219,7 @@ describe('date utils', ()=>{
213
219
  it('11:59 PM → 23:59', ()=>{
214
220
  expect((0, _date.buildFieldValue)({
215
221
  data: {
216
- date: new Date('2023-06-01'),
222
+ date: (0, _moment.default)('2023-06-01'),
217
223
  time: '11:59',
218
224
  ampm: 'PM',
219
225
  utcOffset: '+00:00'
@@ -228,7 +234,7 @@ describe('date utils', ()=>{
228
234
  it('01:00 AM → 01:00 (no shift)', ()=>{
229
235
  expect((0, _date.buildFieldValue)({
230
236
  data: {
231
- date: new Date('2023-06-01'),
237
+ date: (0, _moment.default)('2023-06-01'),
232
238
  time: '01:00',
233
239
  ampm: 'AM',
234
240
  utcOffset: '+00:00'
@@ -284,12 +290,12 @@ describe('date utils', ()=>{
284
290
  });
285
291
  expect(result.date).toBeUndefined();
286
292
  });
287
- it('parses a date-only string', ()=>{
293
+ it('parses a date-only string — utcOffset is the local system offset', ()=>{
288
294
  const result = (0, _date.userInputFromDatetime)({
289
295
  value: '2022-09-16',
290
296
  uses12hClock: false
291
297
  });
292
- expect(result.utcOffset).toBe('+00:00');
298
+ expect(result.utcOffset).toMatch(/^[+-]\d{2}:\d{2}$/);
293
299
  });
294
300
  it('preserves raw time and does not shift by system timezone (positive offset)', ()=>{
295
301
  const result = (0, _date.userInputFromDatetime)({
@@ -309,14 +315,14 @@ describe('date utils', ()=>{
309
315
  expect(result.ampm).toBe('AM');
310
316
  expect(result.utcOffset).toBe('-05:30');
311
317
  });
312
- it('handles UTC "Z" suffix — offset is +00:00, time is not shifted', ()=>{
318
+ it('handles UTC "Z" suffix — moment normalizes offset to +00:00', ()=>{
313
319
  const result = (0, _date.userInputFromDatetime)({
314
320
  value: '2021-06-01T12:00Z',
315
321
  uses12hClock: false
316
322
  });
317
323
  expect(result.time).toBe('12:00');
318
324
  expect(result.ampm).toBe('PM');
319
- expect(result.utcOffset).toBe('Z');
325
+ expect(result.utcOffset).toBe('+00:00');
320
326
  });
321
327
  it('handles midnight UTC correctly', ()=>{
322
328
  const result = (0, _date.userInputFromDatetime)({
@@ -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,55 +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
- 'kk:mm',
10
11
  'k:mm',
12
+ 'kk:mm',
11
13
  'h a',
12
- 'HH',
13
- 'H:mm',
14
- 'h'
14
+ 'h A',
15
+ 'h',
16
+ 'hh',
17
+ 'HH'
15
18
  ];
16
- const REF_DATE = new Date(2000, 0, 1);
17
19
  function parseRawInput(raw) {
18
- for (const fmt of validInputFormats){
19
- const parsed = parse(raw, fmt, REF_DATE);
20
- 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
+ }
21
27
  }
22
- return null;
28
+ return time;
23
29
  }
24
- const getDefaultTime = ()=>parse('12:00 AM', 'hh:mm a', REF_DATE);
25
- 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
+ };
26
36
  export const TimepickerInput = ({ disabled, uses12hClock, time = '12:00', ampm = 'AM', onChange })=>{
27
37
  const [selectedTime, setSelectedTime] = useState(()=>{
28
38
  return formatToString(uses12hClock, getDefaultTime());
29
39
  });
30
40
  useEffect(()=>{
31
- setSelectedTime(formatToString(uses12hClock, parse(`${time} ${ampm}`, 'hh:mm a', REF_DATE)));
41
+ setSelectedTime(formatToString(uses12hClock, moment(`${time} ${ampm}`, 'hh:mm A')));
32
42
  }, [
33
43
  time,
34
44
  ampm,
35
45
  uses12hClock
36
46
  ]);
37
47
  const handleChange = useCallback((e)=>{
38
- setSelectedTime(e.currentTarget.value);
39
- }, []);
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
+ ]);
40
60
  const handleFocus = useCallback((e)=>{
41
61
  e.preventDefault();
42
62
  e.target.select();
43
63
  }, []);
44
- const handleBlur = ()=>{
64
+ const handleBlur = useCallback(()=>{
45
65
  const parsedTime = parseRawInput(selectedTime);
46
66
  const value = parsedTime ?? getDefaultTime();
47
67
  setSelectedTime(formatToString(uses12hClock, value));
48
68
  onChange({
49
- time: format(value, 'hh:mm'),
50
- ampm: format(value, 'a').toUpperCase()
69
+ time: value.format('hh:mm'),
70
+ ampm: value.format('A')
51
71
  });
52
- };
72
+ }, [
73
+ selectedTime,
74
+ uses12hClock,
75
+ onChange
76
+ ]);
53
77
  return /*#__PURE__*/ React.createElement(Flex, {
54
78
  className: css({
55
79
  width: '145px'
@@ -1,10 +1,11 @@
1
+ import moment from 'moment';
1
2
  import { buildFieldValue, userInputFromDatetime, getDefaultAMPM, getDefaultUtcOffset } 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'
@@ -45,7 +46,7 @@ describe('date utils', ()=>{
45
46
  it('returns date-only format when usesTime and usesTimezone are false', ()=>{
46
47
  expect(buildFieldValue({
47
48
  data: {
48
- date: new Date('2020-06-15'),
49
+ date: moment('2020-06-15'),
49
50
  time: '10:30',
50
51
  ampm: 'AM',
51
52
  utcOffset: '+00:00'
@@ -60,7 +61,7 @@ describe('date utils', ()=>{
60
61
  it('returns datetime without timezone when usesTime=true, usesTimezone=false', ()=>{
61
62
  expect(buildFieldValue({
62
63
  data: {
63
- date: new Date('2020-06-15'),
64
+ date: moment('2020-06-15'),
64
65
  time: '14:30',
65
66
  ampm: 'PM',
66
67
  utcOffset: '+00:00'
@@ -89,7 +90,7 @@ describe('date utils', ()=>{
89
90
  it('handles midnight (12:00 AM) correctly', ()=>{
90
91
  expect(buildFieldValue({
91
92
  data: {
92
- date: new Date('2021-03-01'),
93
+ date: moment('2021-03-01'),
93
94
  time: '12:00',
94
95
  ampm: 'AM',
95
96
  utcOffset: '+00:00'
@@ -104,7 +105,7 @@ describe('date utils', ()=>{
104
105
  it('handles noon (12:00 PM) correctly', ()=>{
105
106
  expect(buildFieldValue({
106
107
  data: {
107
- date: new Date('2021-03-01'),
108
+ date: moment('2021-03-01'),
108
109
  time: '12:00',
109
110
  ampm: 'PM',
110
111
  utcOffset: '+00:00'
@@ -119,7 +120,7 @@ describe('date utils', ()=>{
119
120
  it('preserves half-hour offset +05:30 (India)', ()=>{
120
121
  expect(buildFieldValue({
121
122
  data: {
122
- date: new Date('2023-08-15'),
123
+ date: moment('2023-08-15'),
123
124
  time: '10:00',
124
125
  ampm: 'AM',
125
126
  utcOffset: '+05:30'
@@ -134,7 +135,7 @@ describe('date utils', ()=>{
134
135
  it('preserves negative half-hour offset -09:30', ()=>{
135
136
  expect(buildFieldValue({
136
137
  data: {
137
- date: new Date('2023-08-15'),
138
+ date: moment('2023-08-15'),
138
139
  time: '03:30',
139
140
  ampm: 'AM',
140
141
  utcOffset: '-09:30'
@@ -149,7 +150,7 @@ describe('date utils', ()=>{
149
150
  it('preserves quarter-hour offset +05:45 (Nepal)', ()=>{
150
151
  expect(buildFieldValue({
151
152
  data: {
152
- date: new Date('2023-08-15'),
153
+ date: moment('2023-08-15'),
153
154
  time: '05:45',
154
155
  ampm: 'AM',
155
156
  utcOffset: '+05:45'
@@ -164,7 +165,7 @@ describe('date utils', ()=>{
164
165
  it('preserves UTC +00:00 offset', ()=>{
165
166
  expect(buildFieldValue({
166
167
  data: {
167
- date: new Date('2023-01-01'),
168
+ date: moment('2023-01-01'),
168
169
  time: '00:00',
169
170
  ampm: 'AM',
170
171
  utcOffset: '+00:00'
@@ -179,7 +180,7 @@ describe('date utils', ()=>{
179
180
  it('preserves far-west offset -12:00', ()=>{
180
181
  expect(buildFieldValue({
181
182
  data: {
182
- date: new Date('2023-01-01'),
183
+ date: moment('2023-01-01'),
183
184
  time: '23:59',
184
185
  ampm: 'PM',
185
186
  utcOffset: '-12:00'
@@ -194,7 +195,7 @@ describe('date utils', ()=>{
194
195
  it('preserves far-east offset +14:00', ()=>{
195
196
  expect(buildFieldValue({
196
197
  data: {
197
- date: new Date('2023-01-01'),
198
+ date: moment('2023-01-01'),
198
199
  time: '01:00',
199
200
  ampm: 'AM',
200
201
  utcOffset: '+14:00'
@@ -209,7 +210,7 @@ describe('date utils', ()=>{
209
210
  it('11:59 PM → 23:59', ()=>{
210
211
  expect(buildFieldValue({
211
212
  data: {
212
- date: new Date('2023-06-01'),
213
+ date: moment('2023-06-01'),
213
214
  time: '11:59',
214
215
  ampm: 'PM',
215
216
  utcOffset: '+00:00'
@@ -224,7 +225,7 @@ describe('date utils', ()=>{
224
225
  it('01:00 AM → 01:00 (no shift)', ()=>{
225
226
  expect(buildFieldValue({
226
227
  data: {
227
- date: new Date('2023-06-01'),
228
+ date: moment('2023-06-01'),
228
229
  time: '01:00',
229
230
  ampm: 'AM',
230
231
  utcOffset: '+00:00'
@@ -280,12 +281,12 @@ describe('date utils', ()=>{
280
281
  });
281
282
  expect(result.date).toBeUndefined();
282
283
  });
283
- it('parses a date-only string', ()=>{
284
+ it('parses a date-only string — utcOffset is the local system offset', ()=>{
284
285
  const result = userInputFromDatetime({
285
286
  value: '2022-09-16',
286
287
  uses12hClock: false
287
288
  });
288
- expect(result.utcOffset).toBe('+00:00');
289
+ expect(result.utcOffset).toMatch(/^[+-]\d{2}:\d{2}$/);
289
290
  });
290
291
  it('preserves raw time and does not shift by system timezone (positive offset)', ()=>{
291
292
  const result = userInputFromDatetime({
@@ -305,14 +306,14 @@ describe('date utils', ()=>{
305
306
  expect(result.ampm).toBe('AM');
306
307
  expect(result.utcOffset).toBe('-05:30');
307
308
  });
308
- it('handles UTC "Z" suffix — offset is +00:00, time is not shifted', ()=>{
309
+ it('handles UTC "Z" suffix — moment normalizes offset to +00:00', ()=>{
309
310
  const result = userInputFromDatetime({
310
311
  value: '2021-06-01T12:00Z',
311
312
  uses12hClock: false
312
313
  });
313
314
  expect(result.time).toBe('12:00');
314
315
  expect(result.ampm).toBe('PM');
315
- expect(result.utcOffset).toBe('Z');
316
+ expect(result.utcOffset).toBe('+00:00');
316
317
  });
317
318
  it('handles midnight UTC correctly', ()=>{
318
319
  const result = userInputFromDatetime({
@@ -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.2+bc54b71b",
3
+ "version": "2.0.9",
4
4
  "main": "dist/cjs/index.js",
5
5
  "module": "dist/esm/index.js",
6
6
  "types": "dist/types/index.d.ts",
@@ -39,13 +39,13 @@
39
39
  "dependencies": {
40
40
  "@contentful/f36-components": "^6.7.1",
41
41
  "@contentful/f36-tokens": "^6.1.2",
42
- "@contentful/field-editor-shared": "^3.1.4",
42
+ "@contentful/field-editor-shared": "^4.0.0",
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",
48
- "@contentful/field-editor-test-utils": "^2.0.1",
48
+ "@contentful/field-editor-test-utils": "^3.0.0",
49
49
  "@lingui/core": "5.3.0",
50
50
  "@types/timezoned-date": "^3.0.0",
51
51
  "timezoned-date": "^3.0.2"
@@ -57,5 +57,5 @@
57
57
  "publishConfig": {
58
58
  "registry": "https://npm.pkg.github.com/"
59
59
  },
60
- "gitHead": "bc54b71bac951f367ecb112f2d869b461edb58c4"
60
+ "gitHead": "267c2c3194103479b3fa0ba2c61001ef993f4cfd"
61
61
  }