@contentful/field-editor-date 1.4.0 → 1.5.1

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.
Files changed (40) hide show
  1. package/dist/cjs/DateEditor.js +186 -0
  2. package/dist/cjs/DatepickerInput.js +92 -0
  3. package/dist/cjs/DatepickerInput.spec.js +110 -0
  4. package/dist/cjs/TimepickerInput.js +132 -0
  5. package/dist/cjs/TimezonePickerInput.js +32 -0
  6. package/dist/cjs/index.js +20 -0
  7. package/dist/cjs/types.js +4 -0
  8. package/dist/cjs/utils/data.spec.js +56 -0
  9. package/dist/cjs/utils/date.js +116 -0
  10. package/dist/cjs/utils/zoneOffsets.js +61 -0
  11. package/dist/esm/DateEditor.js +132 -0
  12. package/dist/esm/DatepickerInput.js +38 -0
  13. package/dist/esm/DatepickerInput.spec.js +62 -0
  14. package/dist/esm/TimepickerInput.js +78 -0
  15. package/dist/esm/TimezonePickerInput.js +17 -0
  16. package/dist/esm/index.js +2 -0
  17. package/dist/esm/types.js +1 -0
  18. package/dist/esm/utils/data.spec.js +47 -0
  19. package/dist/esm/utils/date.js +87 -0
  20. package/dist/esm/utils/zoneOffsets.js +43 -0
  21. package/dist/{DateEditor.d.ts → types/DateEditor.d.ts} +29 -29
  22. package/dist/{DatepickerInput.d.ts → types/DatepickerInput.d.ts} +8 -8
  23. package/dist/types/DatepickerInput.spec.d.ts +1 -0
  24. package/dist/{TimepickerInput.d.ts → types/TimepickerInput.d.ts} +12 -12
  25. package/dist/{TimezonePickerInput.d.ts → types/TimezonePickerInput.d.ts} +7 -7
  26. package/dist/{index.d.ts → types/index.d.ts} +2 -2
  27. package/dist/types/types.d.ts +9 -0
  28. package/dist/types/utils/data.spec.d.ts +1 -0
  29. package/dist/{utils → types/utils}/date.d.ts +27 -27
  30. package/dist/{utils → types/utils}/zoneOffsets.d.ts +2 -2
  31. package/package.json +26 -12
  32. package/CHANGELOG.md +0 -294
  33. package/dist/field-editor-date.cjs.development.js +0 -430
  34. package/dist/field-editor-date.cjs.development.js.map +0 -1
  35. package/dist/field-editor-date.cjs.production.min.js +0 -2
  36. package/dist/field-editor-date.cjs.production.min.js.map +0 -1
  37. package/dist/field-editor-date.esm.js +0 -422
  38. package/dist/field-editor-date.esm.js.map +0 -1
  39. package/dist/index.js +0 -8
  40. package/dist/types.d.ts +0 -9
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: all[name]
9
+ });
10
+ }
11
+ _export(exports, {
12
+ buildFieldValue: function() {
13
+ return buildFieldValue;
14
+ },
15
+ getDefaultAMPM: function() {
16
+ return getDefaultAMPM;
17
+ },
18
+ getDefaultUtcOffset: function() {
19
+ return getDefaultUtcOffset;
20
+ },
21
+ userInputFromDatetime: function() {
22
+ return userInputFromDatetime;
23
+ }
24
+ });
25
+ const _moment = _interop_require_default(require("moment"));
26
+ function _interop_require_default(obj) {
27
+ return obj && obj.__esModule ? obj : {
28
+ default: obj
29
+ };
30
+ }
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);
37
+ }
38
+ function fieldValueToMoment(datetimeString) {
39
+ if (!datetimeString) {
40
+ return null;
41
+ }
42
+ const datetime = (0, _moment.default)(datetimeString);
43
+ if (ZONE_RX.test(datetimeString)) {
44
+ datetime.utcOffset(datetimeString);
45
+ }
46
+ return datetime;
47
+ }
48
+ function timeFromUserInput(input) {
49
+ const timeInput = input.time || '00:00';
50
+ return _moment.default.utc(timeInput + '!' + input.ampm, 'HH:mm!A');
51
+ }
52
+ function datetimeFromUserInput(input) {
53
+ if (!input.date) {
54
+ return {
55
+ valid: null
56
+ };
57
+ }
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()
62
+ });
63
+ if (date.isValid()) {
64
+ return {
65
+ valid: date
66
+ };
67
+ } else {
68
+ return {
69
+ invalid: true,
70
+ valid: null
71
+ };
72
+ }
73
+ }
74
+ function buildFieldValue({ data , usesTime , usesTimezone }) {
75
+ const date = datetimeFromUserInput(data);
76
+ if (date.invalid) {
77
+ return {
78
+ invalid: true
79
+ };
80
+ }
81
+ let format;
82
+ if (usesTimezone) {
83
+ format = 'YYYY-MM-DDTHH:mmZ';
84
+ } else if (usesTime) {
85
+ format = 'YYYY-MM-DDTHH:mm';
86
+ } else {
87
+ format = 'YYYY-MM-DD';
88
+ }
89
+ return {
90
+ valid: date?.valid ? date.valid.format(format) : null,
91
+ invalid: false
92
+ };
93
+ }
94
+ function getDefaultAMPM() {
95
+ return 'AM';
96
+ }
97
+ function getDefaultUtcOffset() {
98
+ return startOfToday('Z');
99
+ }
100
+ function userInputFromDatetime({ value , uses12hClock }) {
101
+ const datetime = fieldValueToMoment(value);
102
+ if (datetime) {
103
+ const timeFormat = uses12hClock ? 'hh:mm' : 'HH:mm';
104
+ return {
105
+ date: datetime,
106
+ time: datetime.format(timeFormat),
107
+ ampm: datetime.format('A'),
108
+ utcOffset: datetime.format('Z')
109
+ };
110
+ } else {
111
+ return {
112
+ ampm: getDefaultAMPM(),
113
+ utcOffset: getDefaultUtcOffset()
114
+ };
115
+ }
116
+ }
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: all[name]
9
+ });
10
+ }
11
+ _export(exports, {
12
+ defaultZoneOffset: function() {
13
+ return defaultZoneOffset;
14
+ },
15
+ zoneOffsets: function() {
16
+ return zoneOffsets;
17
+ }
18
+ });
19
+ const defaultZoneOffset = '+00:00';
20
+ const zoneOffsets = [
21
+ '-12:00',
22
+ '-11:00',
23
+ '-10:00',
24
+ '-09:30',
25
+ '-09:00',
26
+ '-08:00',
27
+ '-07:00',
28
+ '-06:00',
29
+ '-05:00',
30
+ '-04:30',
31
+ '-04:00',
32
+ '-03:30',
33
+ '-03:00',
34
+ '-02:00',
35
+ '-01:00',
36
+ '+00:00',
37
+ '+01:00',
38
+ '+02:00',
39
+ '+03:00',
40
+ '+03:30',
41
+ '+04:00',
42
+ '+04:30',
43
+ '+05:00',
44
+ '+05:30',
45
+ '+05:45',
46
+ '+06:00',
47
+ '+06:30',
48
+ '+07:00',
49
+ '+08:00',
50
+ '+08:45',
51
+ '+09:00',
52
+ '+09:30',
53
+ '+10:00',
54
+ '+10:30',
55
+ '+11:00',
56
+ '+11:30',
57
+ '+12:00',
58
+ '+12:45',
59
+ '+13:00',
60
+ '+14:00'
61
+ ];
@@ -0,0 +1,132 @@
1
+ import * as React from 'react';
2
+ import { TextLink } from '@contentful/f36-components';
3
+ import tokens from '@contentful/f36-tokens';
4
+ import { FieldConnector } from '@contentful/field-editor-shared';
5
+ import { css } from 'emotion';
6
+ import { DatepickerInput } from './DatepickerInput';
7
+ import { TimepickerInput } from './TimepickerInput';
8
+ import { TimezonepickerInput } from './TimezonePickerInput';
9
+ import { userInputFromDatetime, buildFieldValue, getDefaultAMPM, getDefaultUtcOffset } from './utils/date';
10
+ const styles = {
11
+ root: css({
12
+ display: 'flex',
13
+ alignItems: 'center'
14
+ }),
15
+ separator: css({
16
+ marginLeft: tokens.spacingM
17
+ })
18
+ };
19
+ function useEffectWithoutFirstRender(callback, deps) {
20
+ const isFirstRun = React.useRef(true);
21
+ React.useEffect(()=>{
22
+ if (isFirstRun.current) {
23
+ isFirstRun.current = false;
24
+ return;
25
+ }
26
+ callback();
27
+ }, deps);
28
+ }
29
+ function DateEditorContainer({ initialValue , usesTime , usesTimezone , uses12hClock , disabled , hasClear , onChange }) {
30
+ const [value, setValue] = React.useState(()=>initialValue);
31
+ useEffectWithoutFirstRender(()=>{
32
+ onChange(value);
33
+ }, [
34
+ value
35
+ ]);
36
+ return React.createElement("div", {
37
+ "data-test-id": "date-editor",
38
+ className: styles.root
39
+ }, React.createElement(DatepickerInput, {
40
+ disabled: disabled,
41
+ value: value.date,
42
+ onChange: (date)=>{
43
+ setValue((value)=>({
44
+ ...value,
45
+ date
46
+ }));
47
+ }
48
+ }), usesTime && React.createElement(React.Fragment, null, React.createElement("div", {
49
+ className: styles.separator
50
+ }), React.createElement(TimepickerInput, {
51
+ disabled: disabled,
52
+ time: value.time,
53
+ ampm: value.ampm,
54
+ onChange: ({ time , ampm })=>{
55
+ setValue((value)=>({
56
+ ...value,
57
+ time,
58
+ ampm
59
+ }));
60
+ },
61
+ uses12hClock: uses12hClock
62
+ })), usesTimezone && React.createElement(React.Fragment, null, React.createElement("div", {
63
+ className: styles.separator
64
+ }), React.createElement(TimezonepickerInput, {
65
+ disabled: disabled,
66
+ value: value.utcOffset,
67
+ onChange: (utcOffset)=>{
68
+ setValue((value)=>({
69
+ ...value,
70
+ utcOffset
71
+ }));
72
+ }
73
+ })), hasClear && React.createElement(React.Fragment, null, React.createElement("div", {
74
+ className: styles.separator
75
+ }), React.createElement(TextLink, {
76
+ as: "button",
77
+ isDisabled: disabled,
78
+ testId: "date-clear",
79
+ onClick: ()=>{
80
+ setValue({
81
+ date: undefined,
82
+ time: undefined,
83
+ ampm: getDefaultAMPM(),
84
+ utcOffset: getDefaultUtcOffset()
85
+ });
86
+ }
87
+ }, "Clear")));
88
+ }
89
+ export function DateEditor(props) {
90
+ const { field , parameters } = props;
91
+ const formatParam = parameters?.instance?.format ?? 'timeZ';
92
+ const ampmParam = parameters?.instance?.ampm ?? '24';
93
+ const usesTime = formatParam !== 'dateonly';
94
+ const usesTimezone = formatParam === 'timeZ';
95
+ const uses12hClock = ampmParam === '12';
96
+ return React.createElement(FieldConnector, {
97
+ field: field,
98
+ isInitiallyDisabled: props.isInitiallyDisabled,
99
+ isDisabled: props.isDisabled,
100
+ throttle: 0
101
+ }, ({ value , disabled , setValue , externalReset })=>{
102
+ const datetimeValue = userInputFromDatetime({
103
+ value,
104
+ uses12hClock
105
+ });
106
+ return React.createElement(DateEditorContainer, {
107
+ initialValue: datetimeValue,
108
+ uses12hClock: uses12hClock,
109
+ usesTimezone: usesTimezone,
110
+ usesTime: usesTime,
111
+ disabled: disabled,
112
+ hasClear: Boolean(value),
113
+ onChange: (data)=>{
114
+ const fieldValue = buildFieldValue({
115
+ data,
116
+ usesTime,
117
+ usesTimezone
118
+ });
119
+ if (fieldValue.invalid) {
120
+ return;
121
+ }
122
+ if (Boolean(value) || !value && Boolean(fieldValue.valid)) {
123
+ setValue(fieldValue.valid);
124
+ }
125
+ },
126
+ key: `date-container-${externalReset}`
127
+ });
128
+ });
129
+ }
130
+ DateEditor.defaultProps = {
131
+ isInitiallyDisabled: true
132
+ };
@@ -0,0 +1,38 @@
1
+ import React, { useMemo } from 'react';
2
+ import { Datepicker } from '@contentful/f36-components';
3
+ import { css } from 'emotion';
4
+ import moment from 'moment';
5
+ const YEAR_RANGE = 100;
6
+ const styles = {
7
+ root: css({
8
+ maxWidth: '270px'
9
+ })
10
+ };
11
+ export const DatepickerInput = (props)=>{
12
+ const [fromDate, toDate] = useMemo(()=>{
13
+ const fromDate = new Date();
14
+ fromDate.setFullYear(fromDate.getFullYear() - YEAR_RANGE);
15
+ const toDate = new Date();
16
+ toDate.setFullYear(toDate.getFullYear() + YEAR_RANGE);
17
+ return [
18
+ fromDate,
19
+ toDate
20
+ ];
21
+ }, []);
22
+ const dateObj = props.value?.toObject();
23
+ const selectedDate = dateObj ? new Date(dateObj.years, dateObj.months, dateObj.date) : undefined;
24
+ return React.createElement(Datepicker, {
25
+ className: styles.root,
26
+ selected: selectedDate,
27
+ onSelect: (day)=>{
28
+ const momentDay = day ? moment(day) : undefined;
29
+ props.onChange(momentDay);
30
+ },
31
+ inputProps: {
32
+ isDisabled: props.disabled,
33
+ placeholder: ''
34
+ },
35
+ fromDate: fromDate,
36
+ toDate: toDate
37
+ });
38
+ };
@@ -0,0 +1,62 @@
1
+ import * as React from 'react';
2
+ import '@testing-library/jest-dom/extend-expect';
3
+ import { configure, render, screen } from '@testing-library/react';
4
+ import timezonedDate from 'timezoned-date';
5
+ import { DatepickerInput } from './DatepickerInput';
6
+ import { userInputFromDatetime } from './utils/date';
7
+ configure({
8
+ testIdAttribute: 'data-test-id'
9
+ });
10
+ let originalDate;
11
+ beforeEach(()=>{
12
+ originalDate = global.Date;
13
+ });
14
+ afterEach(()=>{
15
+ global.Date = originalDate;
16
+ });
17
+ const renderDatepicker = (dateString)=>{
18
+ const { date } = userInputFromDatetime({
19
+ value: dateString,
20
+ uses12hClock: false
21
+ });
22
+ return render(React.createElement(DatepickerInput, {
23
+ value: date,
24
+ onChange: jest.fn()
25
+ }));
26
+ };
27
+ describe('Date: DatepickerInput', function() {
28
+ describe('renders correct date, when the system UTC offset is +02:00 and the one in the props.value is', ()=>{
29
+ it('+04:00', async ()=>{
30
+ global.Date = timezonedDate.makeConstructor(120);
31
+ renderDatepicker('2022-09-22T00:00+04:00');
32
+ expect(screen.getByTestId('cf-ui-datepicker-input')).toHaveValue('22 Sep 2022');
33
+ });
34
+ it('+10:00', async ()=>{
35
+ global.Date = timezonedDate.makeConstructor(120);
36
+ renderDatepicker('2022-09-22T00:00+10:00');
37
+ expect(screen.getByTestId('cf-ui-datepicker-input')).toHaveValue('22 Sep 2022');
38
+ });
39
+ it('-08:00', async ()=>{
40
+ global.Date = timezonedDate.makeConstructor(120);
41
+ renderDatepicker('2022-09-22T00:00-08:00');
42
+ expect(screen.getByTestId('cf-ui-datepicker-input')).toHaveValue('22 Sep 2022');
43
+ });
44
+ });
45
+ describe('renders correct date, when the system UTC offset is -06:00 and the one in the props.value is', ()=>{
46
+ it('+02:00', async ()=>{
47
+ global.Date = timezonedDate.makeConstructor(-360);
48
+ renderDatepicker('2022-09-22T00:00+02:00');
49
+ expect(screen.getByTestId('cf-ui-datepicker-input')).toHaveValue('22 Sep 2022');
50
+ });
51
+ it('+10:00', async ()=>{
52
+ global.Date = timezonedDate.makeConstructor(-360);
53
+ renderDatepicker('2022-09-22T00:00+10:00');
54
+ expect(screen.getByTestId('cf-ui-datepicker-input')).toHaveValue('22 Sep 2022');
55
+ });
56
+ it('-08:00', async ()=>{
57
+ global.Date = timezonedDate.makeConstructor(-360);
58
+ renderDatepicker('2022-09-22T00:00-08:00');
59
+ expect(screen.getByTestId('cf-ui-datepicker-input')).toHaveValue('22 Sep 2022');
60
+ });
61
+ });
62
+ });
@@ -0,0 +1,78 @@
1
+ import React, { useState, useCallback, useEffect } from 'react';
2
+ import { TextInput, Flex } from '@contentful/f36-components';
3
+ import { css } from 'emotion';
4
+ import moment from 'moment';
5
+ const validInputFormats = [
6
+ 'hh:mm a',
7
+ 'hh:mm A',
8
+ 'h:mm a',
9
+ 'h:mm A',
10
+ 'hh:mm',
11
+ 'k:mm',
12
+ 'kk:mm',
13
+ 'h a',
14
+ 'h A',
15
+ 'h',
16
+ 'hh',
17
+ 'HH'
18
+ ];
19
+ 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
+ }
27
+ }
28
+ return time;
29
+ }
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
+ };
36
+ export const TimepickerInput = ({ disabled , uses12hClock , time ='12:00' , ampm ='AM' , onChange })=>{
37
+ const [selectedTime, setSelectedTime] = useState(()=>{
38
+ return formatToString(uses12hClock, getDefaultTime());
39
+ });
40
+ useEffect(()=>{
41
+ setSelectedTime(formatToString(uses12hClock, moment(`${time} ${ampm}`, 'hh:mm A')));
42
+ }, [
43
+ time,
44
+ ampm,
45
+ uses12hClock
46
+ ]);
47
+ const handleChange = useCallback((e)=>{
48
+ setSelectedTime(e.currentTarget.value);
49
+ }, []);
50
+ const handleFocus = useCallback((e)=>{
51
+ e.preventDefault();
52
+ e.target.select();
53
+ }, []);
54
+ const handleBlur = ()=>{
55
+ const parsedTime = parseRawInput(selectedTime);
56
+ const value = parsedTime ?? getDefaultTime();
57
+ setSelectedTime(formatToString(uses12hClock, value));
58
+ onChange({
59
+ time: value.format('hh:mm'),
60
+ ampm: value.format('A')
61
+ });
62
+ };
63
+ return React.createElement(Flex, {
64
+ className: css({
65
+ width: '145px'
66
+ })
67
+ }, React.createElement(TextInput, {
68
+ "aria-label": "Select time",
69
+ placeholder: uses12hClock ? '12:00 AM' : '00:00',
70
+ "date-time-type": uses12hClock ? '12' : '24',
71
+ testId: "time-input",
72
+ value: selectedTime,
73
+ isDisabled: disabled,
74
+ onFocus: handleFocus,
75
+ onBlur: handleBlur,
76
+ onChange: handleChange
77
+ }));
78
+ };
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { Select } from '@contentful/f36-components';
3
+ import { zoneOffsets, defaultZoneOffset } from './utils/zoneOffsets';
4
+ export const TimezonepickerInput = ({ disabled , onChange , value =defaultZoneOffset })=>{
5
+ return React.createElement(Select, {
6
+ "aria-label": "Select timezone",
7
+ testId: "timezone-input",
8
+ value: value,
9
+ isDisabled: disabled,
10
+ onChange: (e)=>{
11
+ onChange(e.currentTarget.value);
12
+ }
13
+ }, zoneOffsets.map((offset)=>React.createElement(Select.Option, {
14
+ key: offset,
15
+ value: offset
16
+ }, "UTC", offset)));
17
+ };
@@ -0,0 +1,2 @@
1
+ export { DateEditor } from './DateEditor';
2
+ export { zoneOffsets } from './utils/zoneOffsets';
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,47 @@
1
+ import moment from 'moment';
2
+ import { buildFieldValue } from './date';
3
+ describe('date utils', ()=>{
4
+ describe('buildFieldValue', ()=>{
5
+ it('should work properly', ()=>{
6
+ expect(buildFieldValue({
7
+ data: {
8
+ date: moment('2018-02-02'),
9
+ time: '05:00',
10
+ ampm: 'PM',
11
+ utcOffset: '+03:00'
12
+ },
13
+ usesTimezone: true,
14
+ usesTime: true
15
+ })).toEqual({
16
+ invalid: false,
17
+ valid: '2018-02-02T17:00+03:00'
18
+ });
19
+ expect(buildFieldValue({
20
+ data: {
21
+ date: moment('2015-01-14'),
22
+ time: '05:00',
23
+ ampm: 'AM',
24
+ utcOffset: '-05:00'
25
+ },
26
+ usesTimezone: true,
27
+ usesTime: true
28
+ })).toEqual({
29
+ invalid: false,
30
+ valid: '2015-01-14T05:00-05:00'
31
+ });
32
+ expect(buildFieldValue({
33
+ data: {
34
+ date: moment('2015-01-14'),
35
+ time: '17:00',
36
+ ampm: 'PM',
37
+ utcOffset: '-05:00'
38
+ },
39
+ usesTimezone: true,
40
+ usesTime: true
41
+ })).toEqual({
42
+ invalid: false,
43
+ valid: '2015-01-14T17:00-05:00'
44
+ });
45
+ });
46
+ });
47
+ });
@@ -0,0 +1,87 @@
1
+ import moment from 'moment';
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);
8
+ }
9
+ function fieldValueToMoment(datetimeString) {
10
+ if (!datetimeString) {
11
+ return null;
12
+ }
13
+ const datetime = moment(datetimeString);
14
+ if (ZONE_RX.test(datetimeString)) {
15
+ datetime.utcOffset(datetimeString);
16
+ }
17
+ return datetime;
18
+ }
19
+ function timeFromUserInput(input) {
20
+ const timeInput = input.time || '00:00';
21
+ return moment.utc(timeInput + '!' + input.ampm, 'HH:mm!A');
22
+ }
23
+ function datetimeFromUserInput(input) {
24
+ if (!input.date) {
25
+ return {
26
+ valid: null
27
+ };
28
+ }
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()
33
+ });
34
+ if (date.isValid()) {
35
+ return {
36
+ valid: date
37
+ };
38
+ } else {
39
+ return {
40
+ invalid: true,
41
+ valid: null
42
+ };
43
+ }
44
+ }
45
+ export function buildFieldValue({ data , usesTime , usesTimezone }) {
46
+ const date = datetimeFromUserInput(data);
47
+ if (date.invalid) {
48
+ return {
49
+ invalid: true
50
+ };
51
+ }
52
+ let format;
53
+ if (usesTimezone) {
54
+ format = 'YYYY-MM-DDTHH:mmZ';
55
+ } else if (usesTime) {
56
+ format = 'YYYY-MM-DDTHH:mm';
57
+ } else {
58
+ format = 'YYYY-MM-DD';
59
+ }
60
+ return {
61
+ valid: date?.valid ? date.valid.format(format) : null,
62
+ invalid: false
63
+ };
64
+ }
65
+ export function getDefaultAMPM() {
66
+ return 'AM';
67
+ }
68
+ export function getDefaultUtcOffset() {
69
+ return startOfToday('Z');
70
+ }
71
+ export function userInputFromDatetime({ value , uses12hClock }) {
72
+ const datetime = fieldValueToMoment(value);
73
+ if (datetime) {
74
+ const timeFormat = uses12hClock ? 'hh:mm' : 'HH:mm';
75
+ return {
76
+ date: datetime,
77
+ time: datetime.format(timeFormat),
78
+ ampm: datetime.format('A'),
79
+ utcOffset: datetime.format('Z')
80
+ };
81
+ } else {
82
+ return {
83
+ ampm: getDefaultAMPM(),
84
+ utcOffset: getDefaultUtcOffset()
85
+ };
86
+ }
87
+ }
@@ -0,0 +1,43 @@
1
+ export const defaultZoneOffset = '+00:00';
2
+ export const zoneOffsets = [
3
+ '-12:00',
4
+ '-11:00',
5
+ '-10:00',
6
+ '-09:30',
7
+ '-09:00',
8
+ '-08:00',
9
+ '-07:00',
10
+ '-06:00',
11
+ '-05:00',
12
+ '-04:30',
13
+ '-04:00',
14
+ '-03:30',
15
+ '-03:00',
16
+ '-02:00',
17
+ '-01:00',
18
+ '+00:00',
19
+ '+01:00',
20
+ '+02:00',
21
+ '+03:00',
22
+ '+03:30',
23
+ '+04:00',
24
+ '+04:30',
25
+ '+05:00',
26
+ '+05:30',
27
+ '+05:45',
28
+ '+06:00',
29
+ '+06:30',
30
+ '+07:00',
31
+ '+08:00',
32
+ '+08:45',
33
+ '+09:00',
34
+ '+09:30',
35
+ '+10:00',
36
+ '+10:30',
37
+ '+11:00',
38
+ '+11:30',
39
+ '+12:00',
40
+ '+12:45',
41
+ '+13:00',
42
+ '+14:00'
43
+ ];