@atlaskit/datetime-picker 15.4.3 → 15.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 (46) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/cjs/components/date-picker-class.js +11 -3
  3. package/dist/cjs/components/date-picker-fc.js +11 -3
  4. package/dist/cjs/components/date-time-picker-class.js +439 -0
  5. package/dist/cjs/components/date-time-picker-fc.js +398 -0
  6. package/dist/cjs/components/date-time-picker.js +7 -430
  7. package/dist/cjs/components/time-picker.js +9 -3
  8. package/dist/cjs/internal/date-time-picker-container.js +21 -20
  9. package/dist/cjs/internal/indicators-container.js +31 -0
  10. package/dist/es2019/components/date-picker-class.js +9 -1
  11. package/dist/es2019/components/date-picker-fc.js +9 -1
  12. package/dist/es2019/components/date-time-picker-class.js +400 -0
  13. package/dist/es2019/components/date-time-picker-fc.js +363 -0
  14. package/dist/es2019/components/date-time-picker.js +4 -397
  15. package/dist/es2019/components/time-picker.js +8 -3
  16. package/dist/es2019/internal/date-time-picker-container.js +8 -7
  17. package/dist/es2019/internal/indicators-container.js +22 -0
  18. package/dist/esm/components/date-picker-class.js +11 -3
  19. package/dist/esm/components/date-picker-fc.js +11 -3
  20. package/dist/esm/components/date-time-picker-class.js +437 -0
  21. package/dist/esm/components/date-time-picker-fc.js +391 -0
  22. package/dist/esm/components/date-time-picker.js +6 -434
  23. package/dist/esm/components/time-picker.js +9 -3
  24. package/dist/esm/internal/date-time-picker-container.js +8 -7
  25. package/dist/esm/internal/indicators-container.js +25 -0
  26. package/dist/types/components/date-picker-class.d.ts +2 -2
  27. package/dist/types/components/date-picker-fc.d.ts +1 -1
  28. package/dist/types/components/date-picker.d.ts +3 -3
  29. package/dist/types/components/date-time-picker-class.d.ts +56 -0
  30. package/dist/types/components/date-time-picker-fc.d.ts +19 -0
  31. package/dist/types/components/date-time-picker.d.ts +2 -55
  32. package/dist/types/components/time-picker.d.ts +1 -1
  33. package/dist/types/internal/date-time-picker-container.d.ts +10 -12
  34. package/dist/types/internal/indicators-container.d.ts +9 -0
  35. package/dist/types/types.d.ts +4 -0
  36. package/dist/types-ts4.5/components/date-picker-class.d.ts +2 -2
  37. package/dist/types-ts4.5/components/date-picker-fc.d.ts +1 -1
  38. package/dist/types-ts4.5/components/date-picker.d.ts +3 -3
  39. package/dist/types-ts4.5/components/date-time-picker-class.d.ts +56 -0
  40. package/dist/types-ts4.5/components/date-time-picker-fc.d.ts +19 -0
  41. package/dist/types-ts4.5/components/date-time-picker.d.ts +2 -55
  42. package/dist/types-ts4.5/components/time-picker.d.ts +1 -1
  43. package/dist/types-ts4.5/internal/date-time-picker-container.d.ts +10 -12
  44. package/dist/types-ts4.5/internal/indicators-container.d.ts +9 -0
  45. package/dist/types-ts4.5/types.d.ts +4 -0
  46. package/package.json +8 -5
@@ -0,0 +1,363 @@
1
+ /**
2
+ * @jsxRuntime classic
3
+ * @jsx jsx
4
+ */
5
+ import React, { forwardRef, useCallback, useEffect, useState } from 'react';
6
+
7
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
8
+ import { css, jsx } from '@emotion/react';
9
+ import { format, isValid, parseISO } from 'date-fns';
10
+ import { usePlatformLeafEventHandler } from '@atlaskit/analytics-next';
11
+ import SelectClearIcon from '@atlaskit/icon/glyph/select-clear';
12
+ import { fg } from '@atlaskit/platform-feature-flags';
13
+ import { mergeStyles } from '@atlaskit/select';
14
+ import { N500, N70 } from '@atlaskit/theme/colors';
15
+ import { formatDateTimeZoneIntoIso } from '../internal';
16
+ import { DateTimePickerContainer } from '../internal/date-time-picker-container';
17
+ import { componentWithCondition } from '../internal/ff-component';
18
+ import { convertTokens } from '../internal/parse-tokens';
19
+ import DatePickerOld from './date-picker-class';
20
+ import DatePickerNew from './date-picker-fc';
21
+ import TimePicker from './time-picker';
22
+ const DatePicker = componentWithCondition(() => fg('dst-date-picker-use-functional-component'), DatePickerNew, DatePickerOld);
23
+ const packageName = "@atlaskit/datetime-picker";
24
+ const packageVersion = "15.5.1";
25
+ const analyticsAttributes = {
26
+ componentName: 'dateTimePicker',
27
+ packageName,
28
+ packageVersion
29
+ };
30
+
31
+ // Make DatePicker 50% the width of DateTimePicker
32
+ // If rendering an icon container, shrink the TimePicker
33
+ const datePickerContainerStyles = css({
34
+ flexBasis: '50%',
35
+ flexGrow: 1,
36
+ flexShrink: 0
37
+ });
38
+ const timePickerContainerStyles = css({
39
+ flexBasis: '50%',
40
+ flexGrow: 1
41
+ });
42
+ const iconContainerStyles = css({
43
+ display: 'flex',
44
+ margin: "var(--ds-border-width, 1px)",
45
+ alignItems: 'center',
46
+ flexBasis: 'inherit',
47
+ backgroundColor: 'inherit',
48
+ border: 'none',
49
+ color: `var(--ds-text-subtlest, ${N70})`,
50
+ paddingBlockEnd: "var(--ds-space-075, 6px)",
51
+ paddingBlockStart: "var(--ds-space-075, 6px)",
52
+ paddingInlineEnd: "var(--ds-space-100, 8px)",
53
+ paddingInlineStart: "var(--ds-space-050, 4px)",
54
+ transition: `color 150ms`,
55
+ '&:hover': {
56
+ color: `var(--ds-text-subtle, ${N500})`
57
+ }
58
+ });
59
+
60
+ // react-select overrides (via @atlaskit/select).
61
+ const styles = {
62
+ control: style => ({
63
+ ...style,
64
+ backgroundColor: 'transparent',
65
+ border: 2,
66
+ borderRadius: 0,
67
+ paddingLeft: 0,
68
+ ':hover': {
69
+ backgroundColor: 'transparent',
70
+ cursor: 'inherit'
71
+ }
72
+ })
73
+ };
74
+ export const datePickerDefaultAriaLabel = 'Date';
75
+ export const timePickerDefaultAriaLabel = 'Time';
76
+
77
+ /**
78
+ * __Date time picker__
79
+ *
80
+ * A date time picker allows the user to select an associated date and time.
81
+ *
82
+ * - [Examples](https://atlassian.design/components/datetime-picker/examples)
83
+ * - [Code](https://atlassian.design/components/datetime-picker/code)
84
+ * - [Usage](https://atlassian.design/components/datetime-picker/usage)
85
+ */
86
+ const DateTimePicker = /*#__PURE__*/forwardRef(({
87
+ 'aria-describedby': ariaDescribedBy,
88
+ appearance = 'default',
89
+ autoFocus = false,
90
+ clearControlLabel = 'clear',
91
+ datePickerProps: datePickerPropsWithSelectProps = {},
92
+ defaultValue = '',
93
+ id = '',
94
+ innerProps = {},
95
+ isDisabled = false,
96
+ isInvalid = false,
97
+ isRequired = false,
98
+ name = '',
99
+ // These disables are here for proper typing when used as defaults. They
100
+ // should *not* use the `noop` function.
101
+ /* eslint-disable @repo/internal/react/use-noop */
102
+ onBlur = _event => {},
103
+ onChange: onChangeProp = _value => {},
104
+ onFocus = _event => {},
105
+ /* eslint-enable @repo/internal/react/use-noop */
106
+ parseValue: providedParseValue,
107
+ spacing = 'default',
108
+ locale = 'en-US',
109
+ testId,
110
+ timePickerProps: timePickerPropsWithSelectProps = {},
111
+ value: providedValue
112
+ }, ref) => {
113
+ const [dateValue, setDateValue] = useState((datePickerPropsWithSelectProps === null || datePickerPropsWithSelectProps === void 0 ? void 0 : datePickerPropsWithSelectProps.defaultValue) || '');
114
+ const [isFocused, setIsFocused] = useState(false);
115
+ const [timeValue, setTimeValue] = useState((timePickerPropsWithSelectProps === null || timePickerPropsWithSelectProps === void 0 ? void 0 : timePickerPropsWithSelectProps.defaultValue) || '');
116
+ const [value, setValue] = useState(defaultValue || '');
117
+ const [zoneValue, setZoneValue] = useState('');
118
+ useEffect(() => {
119
+ if (providedValue) {
120
+ setValue(providedValue);
121
+ }
122
+ }, [providedValue]);
123
+ const parseValue = useCallback((value, providedDateValue, providedTimeValue, providedZoneValue) => {
124
+ if (providedParseValue) {
125
+ const parsedFromFn = providedParseValue(value, providedDateValue, providedTimeValue, providedZoneValue);
126
+ // This handles cases found in Jira where the parse function actually does
127
+ // nothing and returns undefined. The previous `getSafeState` function
128
+ // just spread the values over the state, but if it returned `undefined`,
129
+ // it would just rely on the previous state values. Considering this is
130
+ // what is input to this function anyway, this is a safe way to handle
131
+ // this, colocate the behavior, and not rely on `getSafeState`.
132
+ return parsedFromFn || {
133
+ dateValue: providedDateValue,
134
+ timeValue: providedTimeValue,
135
+ zoneValue: providedZoneValue
136
+ };
137
+ }
138
+ const parsed = parseISO(value);
139
+ return isValid(parsed) ? {
140
+ dateValue: format(parsed, convertTokens('YYYY-MM-DD')),
141
+ timeValue: format(parsed, convertTokens('HH:mm')),
142
+ zoneValue: format(parsed, convertTokens('ZZ'))
143
+ } : {
144
+ dateValue,
145
+ timeValue,
146
+ zoneValue
147
+ };
148
+ }, [providedParseValue, dateValue, timeValue, zoneValue]);
149
+ useEffect(() => {
150
+ const parsedValues = parseValue(value, dateValue, timeValue, zoneValue);
151
+ setDateValue(parsedValues.dateValue);
152
+ setTimeValue(parsedValues.timeValue);
153
+ setZoneValue(parsedValues.zoneValue);
154
+ }, [value, dateValue, timeValue, zoneValue, parseValue]);
155
+ const onDateBlur = event => {
156
+ setIsFocused(false);
157
+ onBlur(event);
158
+ if (datePickerPropsWithSelectProps !== null && datePickerPropsWithSelectProps !== void 0 && datePickerPropsWithSelectProps.onBlur) {
159
+ datePickerPropsWithSelectProps.onBlur(event);
160
+ }
161
+ };
162
+ const onTimeBlur = event => {
163
+ setIsFocused(false);
164
+ onBlur(event);
165
+ if (timePickerPropsWithSelectProps !== null && timePickerPropsWithSelectProps !== void 0 && timePickerPropsWithSelectProps.onBlur) {
166
+ timePickerPropsWithSelectProps.onBlur(event);
167
+ }
168
+ };
169
+ const onDateFocus = event => {
170
+ setIsFocused(false);
171
+ onFocus(event);
172
+ if (datePickerPropsWithSelectProps !== null && datePickerPropsWithSelectProps !== void 0 && datePickerPropsWithSelectProps.onFocus) {
173
+ datePickerPropsWithSelectProps.onFocus(event);
174
+ }
175
+ };
176
+ const onTimeFocus = event => {
177
+ setIsFocused(false);
178
+ onFocus(event);
179
+ if (timePickerPropsWithSelectProps !== null && timePickerPropsWithSelectProps !== void 0 && timePickerPropsWithSelectProps.onFocus) {
180
+ timePickerPropsWithSelectProps.onFocus(event);
181
+ }
182
+ };
183
+ const onDateChange = dateValue => {
184
+ const parsedValues = parseValue(value, dateValue, timeValue, zoneValue);
185
+ onValueChange({
186
+ providedDateValue: dateValue,
187
+ providedTimeValue: parsedValues.timeValue,
188
+ providedZoneValue: parsedValues.zoneValue
189
+ });
190
+ if (datePickerPropsWithSelectProps !== null && datePickerPropsWithSelectProps !== void 0 && datePickerPropsWithSelectProps.onChange) {
191
+ datePickerPropsWithSelectProps.onChange(dateValue);
192
+ }
193
+ };
194
+ const onTimeChange = timeValue => {
195
+ const parsedValues = parseValue(value, dateValue, timeValue, zoneValue);
196
+ onValueChange({
197
+ providedDateValue: parsedValues.dateValue,
198
+ providedTimeValue: timeValue,
199
+ providedZoneValue: parsedValues.zoneValue
200
+ });
201
+ if (timePickerPropsWithSelectProps !== null && timePickerPropsWithSelectProps !== void 0 && timePickerPropsWithSelectProps.onChange) {
202
+ timePickerPropsWithSelectProps.onChange(timeValue);
203
+ }
204
+ };
205
+ const onClear = () => {
206
+ const parsedValues = parseValue(value, dateValue, timeValue, zoneValue);
207
+ onValueChange({
208
+ providedDateValue: '',
209
+ providedTimeValue: '',
210
+ providedZoneValue: parsedValues.zoneValue
211
+ });
212
+ if (datePickerPropsWithSelectProps !== null && datePickerPropsWithSelectProps !== void 0 && datePickerPropsWithSelectProps.onChange) {
213
+ datePickerPropsWithSelectProps.onChange('');
214
+ }
215
+ if (timePickerPropsWithSelectProps !== null && timePickerPropsWithSelectProps !== void 0 && timePickerPropsWithSelectProps.onChange) {
216
+ timePickerPropsWithSelectProps.onChange('');
217
+ }
218
+ };
219
+ const onChangePropWithAnalytics = usePlatformLeafEventHandler({
220
+ fn: onChangeProp,
221
+ action: 'selectedDate',
222
+ actionSubject: 'datePicker',
223
+ ...analyticsAttributes
224
+ });
225
+ const onValueChange = ({
226
+ providedDateValue,
227
+ providedTimeValue,
228
+ providedZoneValue
229
+ }) => {
230
+ setDateValue(providedDateValue);
231
+ setTimeValue(providedTimeValue);
232
+ setZoneValue(providedZoneValue);
233
+ if (providedDateValue && providedTimeValue) {
234
+ const value = formatDateTimeZoneIntoIso(providedDateValue, providedTimeValue, providedZoneValue);
235
+ const {
236
+ zoneValue: parsedZone
237
+ } = parseValue(value, providedDateValue, providedTimeValue, providedZoneValue);
238
+ const valueWithValidZone = formatDateTimeZoneIntoIso(providedDateValue, providedTimeValue, parsedZone);
239
+ setValue(valueWithValidZone);
240
+ onChangePropWithAnalytics(valueWithValidZone);
241
+ // If the date or time value was cleared when there is an existing datetime value, then clear the value.
242
+ } else if (value) {
243
+ setValue('');
244
+ onChangePropWithAnalytics('');
245
+ }
246
+ };
247
+ const {
248
+ selectProps: datePickerSelectProps,
249
+ ...datePickerProps
250
+ } = datePickerPropsWithSelectProps;
251
+ const datePickerAriaDescribedBy = datePickerProps['aria-describedby'] || ariaDescribedBy;
252
+ const datePickerLabel = datePickerProps.label || datePickerDefaultAriaLabel;
253
+ const mergedDatePickerSelectProps = {
254
+ ...datePickerSelectProps,
255
+ styles: mergeStyles(styles, datePickerSelectProps === null || datePickerSelectProps === void 0 ? void 0 : datePickerSelectProps.styles)
256
+ };
257
+ const {
258
+ selectProps: timePickerSelectProps,
259
+ ...timePickerProps
260
+ } = timePickerPropsWithSelectProps;
261
+ const timePickerAriaDescribedBy = timePickerProps['aria-describedby'] || ariaDescribedBy;
262
+ const timePickerLabel = timePickerProps.label || timePickerDefaultAriaLabel;
263
+ const mergedTimePickerSelectProps = {
264
+ ...timePickerSelectProps,
265
+ styles: mergeStyles(styles, timePickerSelectProps === null || timePickerSelectProps === void 0 ? void 0 : timePickerSelectProps.styles)
266
+ };
267
+
268
+ // Render DateTimePicker's IconContainer when a value has been filled
269
+ // Don't use Date or TimePicker's because they can't be customised
270
+ const isClearable = Boolean(dateValue || timeValue);
271
+ return jsx(DateTimePickerContainer, {
272
+ appearance: appearance,
273
+ isDisabled: isDisabled,
274
+ isFocused: isFocused,
275
+ isInvalid: isInvalid,
276
+ testId: testId,
277
+ innerProps: innerProps
278
+ }, jsx("input", {
279
+ name: name,
280
+ type: "hidden",
281
+ value: value,
282
+ "data-testid": testId && `${testId}--input`
283
+ }), jsx("div", {
284
+ css: datePickerContainerStyles
285
+ }, jsx(DatePicker, {
286
+ appearance: appearance,
287
+ "aria-describedby": datePickerAriaDescribedBy,
288
+ autoFocus: datePickerProps.autoFocus || autoFocus,
289
+ dateFormat: datePickerProps.dateFormat,
290
+ defaultIsOpen: datePickerProps.defaultIsOpen,
291
+ defaultValue: datePickerProps.defaultValue,
292
+ disabled: datePickerProps.disabled,
293
+ disabledDateFilter: datePickerProps.disabledDateFilter,
294
+ formatDisplayLabel: datePickerProps.formatDisplayLabel,
295
+ hideIcon: datePickerProps.hideIcon || true,
296
+ icon: datePickerProps.icon,
297
+ id: datePickerProps.id || id,
298
+ innerProps: datePickerProps.innerProps,
299
+ isDisabled: datePickerProps.isDisabled || isDisabled,
300
+ isInvalid: datePickerProps.isInvalid || isInvalid,
301
+ isOpen: datePickerProps.isOpen,
302
+ isRequired: datePickerProps.isRequired || isRequired,
303
+ label: datePickerLabel,
304
+ locale: datePickerProps.locale || locale,
305
+ maxDate: datePickerProps.maxDate,
306
+ minDate: datePickerProps.minDate,
307
+ name: datePickerProps.name,
308
+ nextMonthLabel: datePickerProps.nextMonthLabel,
309
+ onBlur: onDateBlur,
310
+ onChange: onDateChange,
311
+ onFocus: onDateFocus,
312
+ parseInputValue: datePickerProps.parseInputValue,
313
+ placeholder: datePickerProps.placeholder,
314
+ previousMonthLabel: datePickerProps.previousMonthLabel,
315
+ selectProps: mergedDatePickerSelectProps,
316
+ spacing: datePickerProps.spacing || spacing,
317
+ testId: testId && `${testId}--datepicker` || datePickerProps.testId,
318
+ value: dateValue,
319
+ weekStartDay: datePickerProps.weekStartDay
320
+ })), jsx("div", {
321
+ css: timePickerContainerStyles
322
+ }, jsx(TimePicker, {
323
+ appearance: timePickerProps.appearance || appearance,
324
+ "aria-describedby": timePickerAriaDescribedBy,
325
+ autoFocus: timePickerProps.autoFocus,
326
+ defaultIsOpen: timePickerProps.defaultIsOpen,
327
+ defaultValue: timePickerProps.defaultValue,
328
+ formatDisplayLabel: timePickerProps.formatDisplayLabel,
329
+ hideIcon: timePickerProps.hideIcon || true,
330
+ id: timePickerProps.id,
331
+ innerProps: timePickerProps.innerProps,
332
+ isDisabled: timePickerProps.isDisabled || isDisabled,
333
+ isInvalid: timePickerProps.isInvalid || isInvalid,
334
+ isOpen: timePickerProps.isOpen,
335
+ isRequired: timePickerProps.isRequired || isRequired,
336
+ label: timePickerLabel,
337
+ locale: timePickerProps.locale || locale,
338
+ name: timePickerProps.name,
339
+ onBlur: onTimeBlur,
340
+ onChange: onTimeChange,
341
+ onFocus: onTimeFocus,
342
+ parseInputValue: timePickerProps.parseInputValue,
343
+ placeholder: timePickerProps.placeholder,
344
+ selectProps: mergedTimePickerSelectProps,
345
+ spacing: timePickerProps.spacing || spacing,
346
+ testId: timePickerProps.testId || testId && `${testId}--timepicker`,
347
+ timeFormat: timePickerProps.timeFormat,
348
+ timeIsEditable: timePickerProps.timeIsEditable,
349
+ times: timePickerProps.times,
350
+ value: timeValue
351
+ })), isClearable && !isDisabled ? jsx("button", {
352
+ css: iconContainerStyles,
353
+ onClick: onClear,
354
+ "data-testid": testId && `${testId}--icon--container`,
355
+ tabIndex: -1,
356
+ type: "button"
357
+ }, jsx(SelectClearIcon, {
358
+ size: "small",
359
+ primaryColor: "inherit",
360
+ label: clearControlLabel
361
+ })) : null);
362
+ });
363
+ export default DateTimePicker;