@contentful/field-editor-date 2.0.9 → 2.0.10-canary.3

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,12 +11,6 @@ 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
- }
20
14
  function _getRequireWildcardCache(nodeInterop) {
21
15
  if (typeof WeakMap !== "function") return null;
22
16
  var cacheBabelInterop = new WeakMap();
@@ -75,14 +69,12 @@ const DatepickerInput = (props)=>{
75
69
  toDate
76
70
  ];
77
71
  }, []);
78
- const dateObj = props.value?.toObject();
79
- const selectedDate = dateObj ? new Date(dateObj.years, dateObj.months, dateObj.date) : undefined;
72
+ const selectedDate = props.value;
80
73
  return /*#__PURE__*/ _react.default.createElement(_f36components.Datepicker, {
81
74
  className: styles.root,
82
75
  selected: selectedDate,
83
76
  onSelect: (day)=>{
84
- const momentDay = day ? (0, _moment.default)(day) : undefined;
85
- props.onChange(momentDay);
77
+ props.onChange(day ?? undefined);
86
78
  },
87
79
  inputProps: {
88
80
  isDisabled: props.disabled,
@@ -11,12 +11,7 @@ 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 _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
+ const _datefns = require("date-fns");
20
15
  function _getRequireWildcardCache(nodeInterop) {
21
16
  if (typeof WeakMap !== "function") return null;
22
17
  var cacheBabelInterop = new WeakMap();
@@ -60,41 +55,31 @@ function _interop_require_wildcard(obj, nodeInterop) {
60
55
  }
61
56
  const validInputFormats = [
62
57
  'hh:mm a',
63
- 'hh:mm A',
64
58
  'h:mm a',
65
- 'h:mm A',
66
59
  'hh:mm',
67
- 'k:mm',
68
60
  'kk:mm',
61
+ 'k:mm',
69
62
  'h a',
70
- 'h A',
71
- 'h',
72
- 'hh',
73
- 'HH'
63
+ 'HH',
64
+ 'H:mm',
65
+ 'h'
74
66
  ];
67
+ const REF_DATE = new Date(2000, 0, 1);
75
68
  function parseRawInput(raw) {
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
+ for (const fmt of validInputFormats){
70
+ const parsed = (0, _datefns.parse)(raw, fmt, REF_DATE);
71
+ if ((0, _datefns.isValid)(parsed)) return parsed;
83
72
  }
84
- return time;
73
+ return null;
85
74
  }
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
- };
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');
92
77
  const TimepickerInput = ({ disabled, uses12hClock, time = '12:00', ampm = 'AM', onChange })=>{
93
78
  const [selectedTime, setSelectedTime] = (0, _react.useState)(()=>{
94
79
  return formatToString(uses12hClock, getDefaultTime());
95
80
  });
96
81
  (0, _react.useEffect)(()=>{
97
- setSelectedTime(formatToString(uses12hClock, (0, _moment.default)(`${time} ${ampm}`, 'hh:mm A')));
82
+ setSelectedTime(formatToString(uses12hClock, (0, _datefns.parse)(`${time} ${ampm}`, 'hh:mm a', REF_DATE)));
98
83
  }, [
99
84
  time,
100
85
  ampm,
@@ -103,16 +88,7 @@ const TimepickerInput = ({ disabled, uses12hClock, time = '12:00', ampm = 'AM',
103
88
  const handleChange = (0, _react.useCallback)((e)=>{
104
89
  const raw = e.currentTarget.value;
105
90
  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
92
  const handleFocus = (0, _react.useCallback)((e)=>{
117
93
  e.preventDefault();
118
94
  e.target.select();
@@ -122,8 +98,8 @@ const TimepickerInput = ({ disabled, uses12hClock, time = '12:00', ampm = 'AM',
122
98
  const value = parsedTime ?? getDefaultTime();
123
99
  setSelectedTime(formatToString(uses12hClock, value));
124
100
  onChange({
125
- time: value.format('hh:mm'),
126
- ampm: value.format('A')
101
+ time: (0, _datefns.format)(value, 'hh:mm'),
102
+ ampm: (0, _datefns.format)(value, 'a').toUpperCase()
127
103
  });
128
104
  }, [
129
105
  selectedTime,
@@ -2,19 +2,13 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- const _moment = /*#__PURE__*/ _interop_require_default(require("moment"));
6
5
  const _date = require("./date");
7
- function _interop_require_default(obj) {
8
- return obj && obj.__esModule ? obj : {
9
- default: obj
10
- };
11
- }
12
6
  describe('date utils', ()=>{
13
7
  describe('buildFieldValue', ()=>{
14
8
  it('should work properly', ()=>{
15
9
  expect((0, _date.buildFieldValue)({
16
10
  data: {
17
- date: (0, _moment.default)('2018-02-02'),
11
+ date: new Date('2018-02-02'),
18
12
  time: '05:00',
19
13
  ampm: 'PM',
20
14
  utcOffset: '+03:00'
@@ -27,7 +21,7 @@ describe('date utils', ()=>{
27
21
  });
28
22
  expect((0, _date.buildFieldValue)({
29
23
  data: {
30
- date: (0, _moment.default)('2015-01-14'),
24
+ date: new Date('2015-01-14'),
31
25
  time: '05:00',
32
26
  ampm: 'AM',
33
27
  utcOffset: '-05:00'
@@ -40,7 +34,7 @@ describe('date utils', ()=>{
40
34
  });
41
35
  expect((0, _date.buildFieldValue)({
42
36
  data: {
43
- date: (0, _moment.default)('2015-01-14'),
37
+ date: new Date('2015-01-14'),
44
38
  time: '17:00',
45
39
  ampm: 'PM',
46
40
  utcOffset: '-05:00'
@@ -55,7 +49,7 @@ describe('date utils', ()=>{
55
49
  it('returns date-only format when usesTime and usesTimezone are false', ()=>{
56
50
  expect((0, _date.buildFieldValue)({
57
51
  data: {
58
- date: (0, _moment.default)('2020-06-15'),
52
+ date: new Date('2020-06-15'),
59
53
  time: '10:30',
60
54
  ampm: 'AM',
61
55
  utcOffset: '+00:00'
@@ -70,7 +64,7 @@ describe('date utils', ()=>{
70
64
  it('returns datetime without timezone when usesTime=true, usesTimezone=false', ()=>{
71
65
  expect((0, _date.buildFieldValue)({
72
66
  data: {
73
- date: (0, _moment.default)('2020-06-15'),
67
+ date: new Date('2020-06-15'),
74
68
  time: '14:30',
75
69
  ampm: 'PM',
76
70
  utcOffset: '+00:00'
@@ -99,7 +93,7 @@ describe('date utils', ()=>{
99
93
  it('handles midnight (12:00 AM) correctly', ()=>{
100
94
  expect((0, _date.buildFieldValue)({
101
95
  data: {
102
- date: (0, _moment.default)('2021-03-01'),
96
+ date: new Date('2021-03-01'),
103
97
  time: '12:00',
104
98
  ampm: 'AM',
105
99
  utcOffset: '+00:00'
@@ -114,7 +108,7 @@ describe('date utils', ()=>{
114
108
  it('handles noon (12:00 PM) correctly', ()=>{
115
109
  expect((0, _date.buildFieldValue)({
116
110
  data: {
117
- date: (0, _moment.default)('2021-03-01'),
111
+ date: new Date('2021-03-01'),
118
112
  time: '12:00',
119
113
  ampm: 'PM',
120
114
  utcOffset: '+00:00'
@@ -129,7 +123,7 @@ describe('date utils', ()=>{
129
123
  it('preserves half-hour offset +05:30 (India)', ()=>{
130
124
  expect((0, _date.buildFieldValue)({
131
125
  data: {
132
- date: (0, _moment.default)('2023-08-15'),
126
+ date: new Date('2023-08-15'),
133
127
  time: '10:00',
134
128
  ampm: 'AM',
135
129
  utcOffset: '+05:30'
@@ -144,7 +138,7 @@ describe('date utils', ()=>{
144
138
  it('preserves negative half-hour offset -09:30', ()=>{
145
139
  expect((0, _date.buildFieldValue)({
146
140
  data: {
147
- date: (0, _moment.default)('2023-08-15'),
141
+ date: new Date('2023-08-15'),
148
142
  time: '03:30',
149
143
  ampm: 'AM',
150
144
  utcOffset: '-09:30'
@@ -159,7 +153,7 @@ describe('date utils', ()=>{
159
153
  it('preserves quarter-hour offset +05:45 (Nepal)', ()=>{
160
154
  expect((0, _date.buildFieldValue)({
161
155
  data: {
162
- date: (0, _moment.default)('2023-08-15'),
156
+ date: new Date('2023-08-15'),
163
157
  time: '05:45',
164
158
  ampm: 'AM',
165
159
  utcOffset: '+05:45'
@@ -174,7 +168,7 @@ describe('date utils', ()=>{
174
168
  it('preserves UTC +00:00 offset', ()=>{
175
169
  expect((0, _date.buildFieldValue)({
176
170
  data: {
177
- date: (0, _moment.default)('2023-01-01'),
171
+ date: new Date('2023-01-01'),
178
172
  time: '00:00',
179
173
  ampm: 'AM',
180
174
  utcOffset: '+00:00'
@@ -189,7 +183,7 @@ describe('date utils', ()=>{
189
183
  it('preserves far-west offset -12:00', ()=>{
190
184
  expect((0, _date.buildFieldValue)({
191
185
  data: {
192
- date: (0, _moment.default)('2023-01-01'),
186
+ date: new Date('2023-01-01'),
193
187
  time: '23:59',
194
188
  ampm: 'PM',
195
189
  utcOffset: '-12:00'
@@ -204,7 +198,7 @@ describe('date utils', ()=>{
204
198
  it('preserves far-east offset +14:00', ()=>{
205
199
  expect((0, _date.buildFieldValue)({
206
200
  data: {
207
- date: (0, _moment.default)('2023-01-01'),
201
+ date: new Date('2023-01-01'),
208
202
  time: '01:00',
209
203
  ampm: 'AM',
210
204
  utcOffset: '+14:00'
@@ -219,7 +213,7 @@ describe('date utils', ()=>{
219
213
  it('11:59 PM → 23:59', ()=>{
220
214
  expect((0, _date.buildFieldValue)({
221
215
  data: {
222
- date: (0, _moment.default)('2023-06-01'),
216
+ date: new Date('2023-06-01'),
223
217
  time: '11:59',
224
218
  ampm: 'PM',
225
219
  utcOffset: '+00:00'
@@ -234,7 +228,7 @@ describe('date utils', ()=>{
234
228
  it('01:00 AM → 01:00 (no shift)', ()=>{
235
229
  expect((0, _date.buildFieldValue)({
236
230
  data: {
237
- date: (0, _moment.default)('2023-06-01'),
231
+ date: new Date('2023-06-01'),
238
232
  time: '01:00',
239
233
  ampm: 'AM',
240
234
  utcOffset: '+00:00'
@@ -290,12 +284,12 @@ describe('date utils', ()=>{
290
284
  });
291
285
  expect(result.date).toBeUndefined();
292
286
  });
293
- it('parses a date-only string — utcOffset is the local system offset', ()=>{
287
+ it('parses a date-only string', ()=>{
294
288
  const result = (0, _date.userInputFromDatetime)({
295
289
  value: '2022-09-16',
296
290
  uses12hClock: false
297
291
  });
298
- expect(result.utcOffset).toMatch(/^[+-]\d{2}:\d{2}$/);
292
+ expect(result.utcOffset).toBe('+00:00');
299
293
  });
300
294
  it('preserves raw time and does not shift by system timezone (positive offset)', ()=>{
301
295
  const result = (0, _date.userInputFromDatetime)({
@@ -315,7 +309,7 @@ describe('date utils', ()=>{
315
309
  expect(result.ampm).toBe('AM');
316
310
  expect(result.utcOffset).toBe('-05:30');
317
311
  });
318
- it('handles UTC "Z" suffix — moment normalizes offset to +00:00', ()=>{
312
+ it('handles UTC "Z" suffix — normalizes offset to +00:00', ()=>{
319
313
  const result = (0, _date.userInputFromDatetime)({
320
314
  value: '2021-06-01T12:00Z',
321
315
  uses12hClock: false
@@ -22,32 +22,37 @@ _export(exports, {
22
22
  return userInputFromDatetime;
23
23
  }
24
24
  });
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
- };
30
- }
25
+ const _datefns = require("date-fns");
31
26
  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);
27
+ function startOfTodayOffset() {
28
+ return (0, _datefns.format)(new Date(), 'xxx');
29
+ }
30
+ function parseUtcOffset(datetimeString) {
31
+ const match = datetimeString.match(ZONE_RX);
32
+ if (!match) return '+00:00';
33
+ return match[1] === 'Z' ? '+00:00' : match[1];
37
34
  }
38
- function fieldValueToMoment(datetimeString) {
35
+ function fieldValueToDate(datetimeString) {
39
36
  if (!datetimeString) {
40
37
  return null;
41
38
  }
42
- const datetime = (0, _moment.default)(datetimeString);
43
- if (ZONE_RX.test(datetimeString)) {
44
- datetime.utcOffset(datetimeString);
45
- }
46
- return datetime;
39
+ const date = (0, _datefns.parseISO)(datetimeString);
40
+ return (0, _datefns.isValid)(date) ? date : null;
47
41
  }
48
42
  function timeFromUserInput(input) {
49
43
  const timeInput = input.time || '00:00';
50
- return _moment.default.utc(timeInput + '!' + input.ampm, 'HH:mm!A');
44
+ const parsed = (0, _datefns.parse)(timeInput, 'HH:mm', new Date(0));
45
+ let hours = (0, _datefns.getHours)(parsed);
46
+ const minutes = (0, _datefns.getMinutes)(parsed);
47
+ if (input.ampm === 'PM' && hours < 12) {
48
+ hours += 12;
49
+ } else if (input.ampm === 'AM' && hours === 12) {
50
+ hours = 0;
51
+ }
52
+ return {
53
+ hours,
54
+ minutes
55
+ };
51
56
  }
52
57
  function datetimeFromUserInput(input) {
53
58
  if (!input.date) {
@@ -55,12 +60,14 @@ function datetimeFromUserInput(input) {
55
60
  valid: null
56
61
  };
57
62
  }
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()
63
+ const { hours, minutes } = timeFromUserInput(input);
64
+ const date = (0, _datefns.set)(input.date, {
65
+ hours,
66
+ minutes,
67
+ seconds: 0,
68
+ milliseconds: 0
62
69
  });
63
- if (date.isValid()) {
70
+ if ((0, _datefns.isValid)(date)) {
64
71
  return {
65
72
  valid: date
66
73
  };
@@ -78,34 +85,58 @@ function buildFieldValue({ data, usesTime, usesTimezone }) {
78
85
  invalid: true
79
86
  };
80
87
  }
81
- let format;
88
+ if (!date.valid) {
89
+ return {
90
+ valid: null,
91
+ invalid: false
92
+ };
93
+ }
82
94
  if (usesTimezone) {
83
- format = 'YYYY-MM-DDTHH:mmZ';
95
+ return {
96
+ valid: (0, _datefns.format)(date.valid, "yyyy-MM-dd'T'HH:mm") + data.utcOffset,
97
+ invalid: false
98
+ };
84
99
  } else if (usesTime) {
85
- format = 'YYYY-MM-DDTHH:mm';
100
+ return {
101
+ valid: (0, _datefns.format)(date.valid, "yyyy-MM-dd'T'HH:mm"),
102
+ invalid: false
103
+ };
86
104
  } else {
87
- format = 'YYYY-MM-DD';
105
+ return {
106
+ valid: (0, _datefns.format)(date.valid, 'yyyy-MM-dd'),
107
+ invalid: false
108
+ };
88
109
  }
89
- return {
90
- valid: date?.valid ? date.valid.format(format) : null,
91
- invalid: false
92
- };
93
110
  }
94
111
  function getDefaultAMPM() {
95
112
  return 'AM';
96
113
  }
97
114
  function getDefaultUtcOffset() {
98
- return startOfToday('Z');
115
+ return startOfTodayOffset();
116
+ }
117
+ function extractTimeFromIso(value) {
118
+ const match = value.match(/T(\d{2}:\d{2})/);
119
+ return match ? match[1] : undefined;
99
120
  }
100
121
  function userInputFromDatetime({ value, uses12hClock }) {
101
- const datetime = fieldValueToMoment(value);
102
- if (datetime) {
103
- const timeFormat = uses12hClock ? 'hh:mm' : 'HH:mm';
122
+ const datetime = fieldValueToDate(value);
123
+ if (datetime && value) {
124
+ const rawTime = extractTimeFromIso(value);
125
+ const timeDate = rawTime ? (0, _datefns.parse)(rawTime, 'HH:mm', new Date(0)) : datetime;
126
+ const hours = (0, _datefns.getHours)(timeDate);
127
+ const ampm = hours < 12 ? 'AM' : 'PM';
128
+ let time;
129
+ if (uses12hClock) {
130
+ const h12 = hours % 12 || 12;
131
+ time = `${String(h12).padStart(2, '0')}:${String((0, _datefns.getMinutes)(timeDate)).padStart(2, '0')}`;
132
+ } else {
133
+ time = rawTime ?? (0, _datefns.format)(datetime, 'HH:mm');
134
+ }
104
135
  return {
105
136
  date: datetime,
106
- time: datetime.format(timeFormat),
107
- ampm: datetime.format('A'),
108
- utcOffset: datetime.format('Z')
137
+ time,
138
+ ampm,
139
+ utcOffset: parseUtcOffset(value)
109
140
  };
110
141
  } else {
111
142
  return {
@@ -1,7 +1,6 @@
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';
5
4
  const YEARS_INTO_FUTURE = 100;
6
5
  const MIN_YEAR = '1000';
7
6
  const styles = {
@@ -19,14 +18,12 @@ export const DatepickerInput = (props)=>{
19
18
  toDate
20
19
  ];
21
20
  }, []);
22
- const dateObj = props.value?.toObject();
23
- const selectedDate = dateObj ? new Date(dateObj.years, dateObj.months, dateObj.date) : undefined;
21
+ const selectedDate = props.value;
24
22
  return /*#__PURE__*/ React.createElement(Datepicker, {
25
23
  className: styles.root,
26
24
  selected: selectedDate,
27
25
  onSelect: (day)=>{
28
- const momentDay = day ? moment(day) : undefined;
29
- props.onChange(momentDay);
26
+ props.onChange(day ?? undefined);
30
27
  },
31
28
  inputProps: {
32
29
  isDisabled: props.disabled,
@@ -1,44 +1,34 @@
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 moment from 'moment';
4
+ import { parse, format, isValid } from 'date-fns';
5
5
  const validInputFormats = [
6
6
  'hh:mm a',
7
- 'hh:mm A',
8
7
  'h:mm a',
9
- 'h:mm A',
10
8
  'hh:mm',
11
- 'k:mm',
12
9
  'kk:mm',
10
+ 'k:mm',
13
11
  'h a',
14
- 'h A',
15
- 'h',
16
- 'hh',
17
- 'HH'
12
+ 'HH',
13
+ 'H:mm',
14
+ 'h'
18
15
  ];
16
+ const REF_DATE = new Date(2000, 0, 1);
19
17
  function parseRawInput(raw) {
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
+ for (const fmt of validInputFormats){
19
+ const parsed = parse(raw, fmt, REF_DATE);
20
+ if (isValid(parsed)) return parsed;
27
21
  }
28
- return time;
22
+ return null;
29
23
  }
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
- };
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');
36
26
  export const TimepickerInput = ({ disabled, uses12hClock, time = '12:00', ampm = 'AM', onChange })=>{
37
27
  const [selectedTime, setSelectedTime] = useState(()=>{
38
28
  return formatToString(uses12hClock, getDefaultTime());
39
29
  });
40
30
  useEffect(()=>{
41
- setSelectedTime(formatToString(uses12hClock, moment(`${time} ${ampm}`, 'hh:mm A')));
31
+ setSelectedTime(formatToString(uses12hClock, parse(`${time} ${ampm}`, 'hh:mm a', REF_DATE)));
42
32
  }, [
43
33
  time,
44
34
  ampm,
@@ -47,16 +37,7 @@ export const TimepickerInput = ({ disabled, uses12hClock, time = '12:00', ampm =
47
37
  const handleChange = useCallback((e)=>{
48
38
  const raw = e.currentTarget.value;
49
39
  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
41
  const handleFocus = useCallback((e)=>{
61
42
  e.preventDefault();
62
43
  e.target.select();
@@ -66,8 +47,8 @@ export const TimepickerInput = ({ disabled, uses12hClock, time = '12:00', ampm =
66
47
  const value = parsedTime ?? getDefaultTime();
67
48
  setSelectedTime(formatToString(uses12hClock, value));
68
49
  onChange({
69
- time: value.format('hh:mm'),
70
- ampm: value.format('A')
50
+ time: format(value, 'hh:mm'),
51
+ ampm: format(value, 'a').toUpperCase()
71
52
  });
72
53
  }, [
73
54
  selectedTime,
@@ -1,11 +1,10 @@
1
- import moment from 'moment';
2
1
  import { buildFieldValue, userInputFromDatetime, getDefaultAMPM, getDefaultUtcOffset } from './date';
3
2
  describe('date utils', ()=>{
4
3
  describe('buildFieldValue', ()=>{
5
4
  it('should work properly', ()=>{
6
5
  expect(buildFieldValue({
7
6
  data: {
8
- date: moment('2018-02-02'),
7
+ date: new Date('2018-02-02'),
9
8
  time: '05:00',
10
9
  ampm: 'PM',
11
10
  utcOffset: '+03:00'
@@ -18,7 +17,7 @@ describe('date utils', ()=>{
18
17
  });
19
18
  expect(buildFieldValue({
20
19
  data: {
21
- date: moment('2015-01-14'),
20
+ date: new Date('2015-01-14'),
22
21
  time: '05:00',
23
22
  ampm: 'AM',
24
23
  utcOffset: '-05:00'
@@ -31,7 +30,7 @@ describe('date utils', ()=>{
31
30
  });
32
31
  expect(buildFieldValue({
33
32
  data: {
34
- date: moment('2015-01-14'),
33
+ date: new Date('2015-01-14'),
35
34
  time: '17:00',
36
35
  ampm: 'PM',
37
36
  utcOffset: '-05:00'
@@ -46,7 +45,7 @@ describe('date utils', ()=>{
46
45
  it('returns date-only format when usesTime and usesTimezone are false', ()=>{
47
46
  expect(buildFieldValue({
48
47
  data: {
49
- date: moment('2020-06-15'),
48
+ date: new Date('2020-06-15'),
50
49
  time: '10:30',
51
50
  ampm: 'AM',
52
51
  utcOffset: '+00:00'
@@ -61,7 +60,7 @@ describe('date utils', ()=>{
61
60
  it('returns datetime without timezone when usesTime=true, usesTimezone=false', ()=>{
62
61
  expect(buildFieldValue({
63
62
  data: {
64
- date: moment('2020-06-15'),
63
+ date: new Date('2020-06-15'),
65
64
  time: '14:30',
66
65
  ampm: 'PM',
67
66
  utcOffset: '+00:00'
@@ -90,7 +89,7 @@ describe('date utils', ()=>{
90
89
  it('handles midnight (12:00 AM) correctly', ()=>{
91
90
  expect(buildFieldValue({
92
91
  data: {
93
- date: moment('2021-03-01'),
92
+ date: new Date('2021-03-01'),
94
93
  time: '12:00',
95
94
  ampm: 'AM',
96
95
  utcOffset: '+00:00'
@@ -105,7 +104,7 @@ describe('date utils', ()=>{
105
104
  it('handles noon (12:00 PM) correctly', ()=>{
106
105
  expect(buildFieldValue({
107
106
  data: {
108
- date: moment('2021-03-01'),
107
+ date: new Date('2021-03-01'),
109
108
  time: '12:00',
110
109
  ampm: 'PM',
111
110
  utcOffset: '+00:00'
@@ -120,7 +119,7 @@ describe('date utils', ()=>{
120
119
  it('preserves half-hour offset +05:30 (India)', ()=>{
121
120
  expect(buildFieldValue({
122
121
  data: {
123
- date: moment('2023-08-15'),
122
+ date: new Date('2023-08-15'),
124
123
  time: '10:00',
125
124
  ampm: 'AM',
126
125
  utcOffset: '+05:30'
@@ -135,7 +134,7 @@ describe('date utils', ()=>{
135
134
  it('preserves negative half-hour offset -09:30', ()=>{
136
135
  expect(buildFieldValue({
137
136
  data: {
138
- date: moment('2023-08-15'),
137
+ date: new Date('2023-08-15'),
139
138
  time: '03:30',
140
139
  ampm: 'AM',
141
140
  utcOffset: '-09:30'
@@ -150,7 +149,7 @@ describe('date utils', ()=>{
150
149
  it('preserves quarter-hour offset +05:45 (Nepal)', ()=>{
151
150
  expect(buildFieldValue({
152
151
  data: {
153
- date: moment('2023-08-15'),
152
+ date: new Date('2023-08-15'),
154
153
  time: '05:45',
155
154
  ampm: 'AM',
156
155
  utcOffset: '+05:45'
@@ -165,7 +164,7 @@ describe('date utils', ()=>{
165
164
  it('preserves UTC +00:00 offset', ()=>{
166
165
  expect(buildFieldValue({
167
166
  data: {
168
- date: moment('2023-01-01'),
167
+ date: new Date('2023-01-01'),
169
168
  time: '00:00',
170
169
  ampm: 'AM',
171
170
  utcOffset: '+00:00'
@@ -180,7 +179,7 @@ describe('date utils', ()=>{
180
179
  it('preserves far-west offset -12:00', ()=>{
181
180
  expect(buildFieldValue({
182
181
  data: {
183
- date: moment('2023-01-01'),
182
+ date: new Date('2023-01-01'),
184
183
  time: '23:59',
185
184
  ampm: 'PM',
186
185
  utcOffset: '-12:00'
@@ -195,7 +194,7 @@ describe('date utils', ()=>{
195
194
  it('preserves far-east offset +14:00', ()=>{
196
195
  expect(buildFieldValue({
197
196
  data: {
198
- date: moment('2023-01-01'),
197
+ date: new Date('2023-01-01'),
199
198
  time: '01:00',
200
199
  ampm: 'AM',
201
200
  utcOffset: '+14:00'
@@ -210,7 +209,7 @@ describe('date utils', ()=>{
210
209
  it('11:59 PM → 23:59', ()=>{
211
210
  expect(buildFieldValue({
212
211
  data: {
213
- date: moment('2023-06-01'),
212
+ date: new Date('2023-06-01'),
214
213
  time: '11:59',
215
214
  ampm: 'PM',
216
215
  utcOffset: '+00:00'
@@ -225,7 +224,7 @@ describe('date utils', ()=>{
225
224
  it('01:00 AM → 01:00 (no shift)', ()=>{
226
225
  expect(buildFieldValue({
227
226
  data: {
228
- date: moment('2023-06-01'),
227
+ date: new Date('2023-06-01'),
229
228
  time: '01:00',
230
229
  ampm: 'AM',
231
230
  utcOffset: '+00:00'
@@ -281,12 +280,12 @@ describe('date utils', ()=>{
281
280
  });
282
281
  expect(result.date).toBeUndefined();
283
282
  });
284
- it('parses a date-only string — utcOffset is the local system offset', ()=>{
283
+ it('parses a date-only string', ()=>{
285
284
  const result = userInputFromDatetime({
286
285
  value: '2022-09-16',
287
286
  uses12hClock: false
288
287
  });
289
- expect(result.utcOffset).toMatch(/^[+-]\d{2}:\d{2}$/);
288
+ expect(result.utcOffset).toBe('+00:00');
290
289
  });
291
290
  it('preserves raw time and does not shift by system timezone (positive offset)', ()=>{
292
291
  const result = userInputFromDatetime({
@@ -306,7 +305,7 @@ describe('date utils', ()=>{
306
305
  expect(result.ampm).toBe('AM');
307
306
  expect(result.utcOffset).toBe('-05:30');
308
307
  });
309
- it('handles UTC "Z" suffix — moment normalizes offset to +00:00', ()=>{
308
+ it('handles UTC "Z" suffix — normalizes offset to +00:00', ()=>{
310
309
  const result = userInputFromDatetime({
311
310
  value: '2021-06-01T12:00Z',
312
311
  uses12hClock: false
@@ -1,24 +1,34 @@
1
- import moment from 'moment';
1
+ import { format, getHours, getMinutes, isValid, parse, parseISO, set } from 'date-fns';
2
2
  const ZONE_RX = /(Z|[+-]\d{2}[:+]?\d{2})$/;
3
- function startOfToday(format) {
4
- return moment().set({
5
- hours: 0,
6
- minutes: 0
7
- }).format(format);
3
+ function startOfTodayOffset() {
4
+ return format(new Date(), 'xxx');
8
5
  }
9
- function fieldValueToMoment(datetimeString) {
6
+ function parseUtcOffset(datetimeString) {
7
+ const match = datetimeString.match(ZONE_RX);
8
+ if (!match) return '+00:00';
9
+ return match[1] === 'Z' ? '+00:00' : match[1];
10
+ }
11
+ function fieldValueToDate(datetimeString) {
10
12
  if (!datetimeString) {
11
13
  return null;
12
14
  }
13
- const datetime = moment(datetimeString);
14
- if (ZONE_RX.test(datetimeString)) {
15
- datetime.utcOffset(datetimeString);
16
- }
17
- return datetime;
15
+ const date = parseISO(datetimeString);
16
+ return isValid(date) ? date : null;
18
17
  }
19
18
  function timeFromUserInput(input) {
20
19
  const timeInput = input.time || '00:00';
21
- return moment.utc(timeInput + '!' + input.ampm, 'HH:mm!A');
20
+ const parsed = parse(timeInput, 'HH:mm', new Date(0));
21
+ let hours = getHours(parsed);
22
+ const minutes = getMinutes(parsed);
23
+ if (input.ampm === 'PM' && hours < 12) {
24
+ hours += 12;
25
+ } else if (input.ampm === 'AM' && hours === 12) {
26
+ hours = 0;
27
+ }
28
+ return {
29
+ hours,
30
+ minutes
31
+ };
22
32
  }
23
33
  function datetimeFromUserInput(input) {
24
34
  if (!input.date) {
@@ -26,12 +36,14 @@ function datetimeFromUserInput(input) {
26
36
  valid: null
27
37
  };
28
38
  }
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()
39
+ const { hours, minutes } = timeFromUserInput(input);
40
+ const date = set(input.date, {
41
+ hours,
42
+ minutes,
43
+ seconds: 0,
44
+ milliseconds: 0
33
45
  });
34
- if (date.isValid()) {
46
+ if (isValid(date)) {
35
47
  return {
36
48
  valid: date
37
49
  };
@@ -49,34 +61,58 @@ export function buildFieldValue({ data, usesTime, usesTimezone }) {
49
61
  invalid: true
50
62
  };
51
63
  }
52
- let format;
64
+ if (!date.valid) {
65
+ return {
66
+ valid: null,
67
+ invalid: false
68
+ };
69
+ }
53
70
  if (usesTimezone) {
54
- format = 'YYYY-MM-DDTHH:mmZ';
71
+ return {
72
+ valid: format(date.valid, "yyyy-MM-dd'T'HH:mm") + data.utcOffset,
73
+ invalid: false
74
+ };
55
75
  } else if (usesTime) {
56
- format = 'YYYY-MM-DDTHH:mm';
76
+ return {
77
+ valid: format(date.valid, "yyyy-MM-dd'T'HH:mm"),
78
+ invalid: false
79
+ };
57
80
  } else {
58
- format = 'YYYY-MM-DD';
81
+ return {
82
+ valid: format(date.valid, 'yyyy-MM-dd'),
83
+ invalid: false
84
+ };
59
85
  }
60
- return {
61
- valid: date?.valid ? date.valid.format(format) : null,
62
- invalid: false
63
- };
64
86
  }
65
87
  export function getDefaultAMPM() {
66
88
  return 'AM';
67
89
  }
68
90
  export function getDefaultUtcOffset() {
69
- return startOfToday('Z');
91
+ return startOfTodayOffset();
92
+ }
93
+ function extractTimeFromIso(value) {
94
+ const match = value.match(/T(\d{2}:\d{2})/);
95
+ return match ? match[1] : undefined;
70
96
  }
71
97
  export function userInputFromDatetime({ value, uses12hClock }) {
72
- const datetime = fieldValueToMoment(value);
73
- if (datetime) {
74
- const timeFormat = uses12hClock ? 'hh:mm' : 'HH:mm';
98
+ const datetime = fieldValueToDate(value);
99
+ if (datetime && value) {
100
+ const rawTime = extractTimeFromIso(value);
101
+ const timeDate = rawTime ? parse(rawTime, 'HH:mm', new Date(0)) : datetime;
102
+ const hours = getHours(timeDate);
103
+ const ampm = hours < 12 ? 'AM' : 'PM';
104
+ let time;
105
+ if (uses12hClock) {
106
+ const h12 = hours % 12 || 12;
107
+ time = `${String(h12).padStart(2, '0')}:${String(getMinutes(timeDate)).padStart(2, '0')}`;
108
+ } else {
109
+ time = rawTime ?? format(datetime, 'HH:mm');
110
+ }
75
111
  return {
76
112
  date: datetime,
77
- time: datetime.format(timeFormat),
78
- ampm: datetime.format('A'),
79
- utcOffset: datetime.format('Z')
113
+ time,
114
+ ampm,
115
+ utcOffset: parseUtcOffset(value)
80
116
  };
81
117
  } else {
82
118
  return {
@@ -1,8 +1,7 @@
1
1
  import React from 'react';
2
- import moment from 'moment';
3
2
  export type DatePickerProps = {
4
- value?: moment.Moment;
5
- onChange: (val: moment.Moment | undefined) => void;
3
+ value?: Date;
4
+ onChange: (val: Date | undefined) => void;
6
5
  disabled?: boolean;
7
6
  };
8
7
  export declare const DatepickerInput: (props: DatePickerProps) => React.JSX.Element;
@@ -1,8 +1,7 @@
1
- import moment from 'moment';
2
1
  export type DateTimeFormat = 'dateonly' | 'time' | 'timeZ';
3
2
  export type TimeFormat = '12' | '24';
4
3
  export type TimeResult = {
5
- date?: moment.Moment;
4
+ date?: Date;
6
5
  time?: string;
7
6
  ampm: string;
8
7
  utcOffset: string;
@@ -13,7 +13,10 @@ export declare function buildFieldValue({ data, usesTime, usesTimezone, }: {
13
13
  invalid: boolean;
14
14
  valid?: undefined;
15
15
  } | {
16
- valid: string | null;
16
+ valid: null;
17
+ invalid: boolean;
18
+ } | {
19
+ valid: string;
17
20
  invalid: boolean;
18
21
  };
19
22
  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.9",
3
+ "version": "2.0.10-canary.3+a0957a88",
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": "^4.0.0",
43
43
  "@emotion/css": "^11.13.5",
44
- "moment": "^2.20.0"
44
+ "date-fns": "^2.30.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": "267c2c3194103479b3fa0ba2c61001ef993f4cfd"
60
+ "gitHead": "a0957a88508271646e8134b212192ddb6e3605bb"
61
61
  }