@coinbase/cds-mobile 8.53.1 → 8.54.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"Tooltip.d.ts","sourceRoot":"","sources":["../../../src/overlays/tooltip/Tooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4E,MAAM,OAAO,CAAC;AAMjG,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGlE,eAAO,MAAM,OAAO,qSAmBf,YAAY,6CAsJhB,CAAC"}
1
+ {"version":3,"file":"Tooltip.d.ts","sourceRoot":"","sources":["../../../src/overlays/tooltip/Tooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4E,MAAM,OAAO,CAAC;AACjG,OAAO,EAAE,KAAK,kBAAkB,EAA4C,MAAM,cAAc,CAAC;AAKjG,OAAO,KAAK,EAAiB,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGtE,MAAM,MAAM,YAAY,GAAG,gBAAgB,GAAG;IAC5C;;OAEG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;CACzC,CAAC;AAEF,eAAO,MAAM,OAAO,yTAoBf,YAAY,6CA0JhB,CAAC"}
@@ -1,7 +1,7 @@
1
1
  const _excluded = ["name", "active", "variant", "transparent", "compact", "background", "color", "borderColor", "iconSize", "borderWidth", "borderRadius", "feedback", "flush", "loading", "style", "accessibilityHint", "accessibilityLabel"];
2
2
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
3
3
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
4
- import React, { memo, useCallback, useMemo } from 'react';
4
+ import React, { forwardRef, memo, useCallback, useMemo } from 'react';
5
5
  import { ActivityIndicator } from 'react-native';
6
6
  import { transparentVariants, variants } from '@coinbase/cds-common/tokens/button';
7
7
  import { interactableHeight } from '@coinbase/cds-common/tokens/interactableHeight';
@@ -10,7 +10,7 @@ import { useTheme } from '../hooks/useTheme';
10
10
  import { Icon } from '../icons/Icon';
11
11
  import { Pressable } from '../system/Pressable';
12
12
  import { jsx as _jsx } from "react/jsx-runtime";
13
- export const IconButton = /*#__PURE__*/memo(function IconButton(_ref) {
13
+ export const IconButton = /*#__PURE__*/memo(/*#__PURE__*/forwardRef(function IconButton(_ref, ref) {
14
14
  let {
15
15
  name,
16
16
  active,
@@ -54,6 +54,7 @@ export const IconButton = /*#__PURE__*/memo(function IconButton(_ref) {
54
54
  }), [minHeight]);
55
55
  const pressableStyle = useCallback(state => [sizingStyle, typeof style === 'function' ? style(state) : style], [sizingStyle, style]);
56
56
  return /*#__PURE__*/_jsx(Pressable, _extends({
57
+ ref: ref,
57
58
  accessibilityHint: accessibilityHint,
58
59
  accessibilityLabel: loading ? (accessibilityLabel != null ? accessibilityLabel : '') + ", loading" : accessibilityLabel,
59
60
  background: backgroundValue,
@@ -83,5 +84,5 @@ export const IconButton = /*#__PURE__*/memo(function IconButton(_ref) {
83
84
  style: sizingStyle
84
85
  })
85
86
  }));
86
- });
87
+ }));
87
88
  IconButton.displayName = 'IconButton';
@@ -1,7 +1,7 @@
1
1
  const _excluded = ["disableInheritFocusStyle", "testID", "variant", "accessibilityLabel", "accessibilityHint"];
2
2
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
3
3
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
4
- import React, { memo, useContext } from 'react';
4
+ import React, { forwardRef, memo, useContext } from 'react';
5
5
  import { IconButton } from '../buttons/IconButton';
6
6
  import { Box } from '../layout/Box';
7
7
  import { TextInputFocusVariantContext } from './context';
@@ -14,7 +14,7 @@ export const variantTransformMap = {
14
14
  foregroundMuted: 'foregroundMuted',
15
15
  secondary: 'secondary'
16
16
  };
17
- export const InputIconButton = /*#__PURE__*/memo(function InputIconButton(_ref) {
17
+ export const InputIconButton = /*#__PURE__*/memo(/*#__PURE__*/forwardRef(function InputIconButton(_ref, ref) {
18
18
  let {
19
19
  disableInheritFocusStyle = false,
20
20
  testID,
@@ -30,10 +30,11 @@ export const InputIconButton = /*#__PURE__*/memo(function InputIconButton(_ref)
30
30
  paddingStart: 1,
31
31
  testID: testID,
32
32
  children: /*#__PURE__*/_jsx(IconButton, _extends({
33
+ ref: ref,
33
34
  transparent: true,
34
35
  accessibilityHint: accessibilityHint != null ? accessibilityHint : props.name,
35
36
  accessibilityLabel: accessibilityLabel != null ? accessibilityLabel : props.name,
36
37
  variant: disableInheritFocusStyle ? variant : transformedVariant
37
38
  }, props))
38
39
  });
39
- });
40
+ }));
@@ -0,0 +1,346 @@
1
+ const _excluded = ["background", "borderRadius", "children"],
2
+ _excluded2 = ["selectedDate", "seedDate", "onPressDate", "disabled", "hideControls", "disabledDates", "highlightedDates", "minDate", "maxDate", "disabledDateError", "nextArrowAccessibilityLabel", "previousArrowAccessibilityLabel", "todayAccessibilityHint", "highlightedDateAccessibilityHint", "style", "styles"];
3
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
4
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
5
+ import { forwardRef, memo, useCallback, useImperativeHandle, useMemo, useRef, useState } from 'react';
6
+ import { StyleSheet } from 'react-native';
7
+ import { generateCalendarMonth } from '@coinbase/cds-common/dates/generateCalendarMonth';
8
+ import { getMidnightDate } from '@coinbase/cds-common/dates/getMidnightDate';
9
+ import { getTimesFromDatesAndRanges } from '@coinbase/cds-common/dates/getTimesFromDatesAndRanges';
10
+ import { useLocale } from '@coinbase/cds-common/system/LocaleProvider';
11
+ import { accessibleOpacityDisabled } from '@coinbase/cds-common/tokens/interactable';
12
+ import { useA11y } from '../hooks/useA11y';
13
+ import { useScreenReaderStatus } from '../hooks/useScreenReaderStatus';
14
+ import { Icon } from '../icons/Icon';
15
+ import { Box } from '../layout/Box';
16
+ import { HStack } from '../layout/HStack';
17
+ import { VStack } from '../layout/VStack';
18
+ import { Tooltip } from '../overlays/tooltip/Tooltip';
19
+ import { Pressable } from '../system/Pressable';
20
+ import { Text } from '../typography/Text';
21
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
22
+ const CALENDAR_DAY_DIMENSION = 40;
23
+
24
+ // These could be dynamically generated, but our Calendar and DatePicker aren't localized so there's no point
25
+ const DAYS_OF_WEEK = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
26
+ const styles = StyleSheet.create({
27
+ pressable: {
28
+ alignItems: 'center',
29
+ justifyContent: 'center',
30
+ width: '100%',
31
+ height: '100%'
32
+ }
33
+ });
34
+ const CalendarPressable = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) => {
35
+ let {
36
+ background = 'transparent',
37
+ borderRadius = 1000,
38
+ children
39
+ } = _ref,
40
+ props = _objectWithoutPropertiesLoose(_ref, _excluded);
41
+ return /*#__PURE__*/_jsx(Pressable, _extends({
42
+ ref: ref,
43
+ background: background,
44
+ borderRadius: borderRadius,
45
+ contentStyle: styles.pressable,
46
+ height: CALENDAR_DAY_DIMENSION,
47
+ width: CALENDAR_DAY_DIMENSION
48
+ }, props, {
49
+ children: children
50
+ }));
51
+ }));
52
+ CalendarPressable.displayName = 'CalendarPressable';
53
+ const getDayAccessibilityLabel = function (date, locale) {
54
+ if (locale === void 0) {
55
+ locale = 'en-US';
56
+ }
57
+ return date.toLocaleDateString(locale, {
58
+ weekday: 'long',
59
+ day: 'numeric'
60
+ }) + " " + date.toLocaleDateString(locale, {
61
+ month: 'long',
62
+ year: 'numeric'
63
+ });
64
+ };
65
+ const CalendarDay = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2, ref) => {
66
+ let {
67
+ date,
68
+ active,
69
+ disabled,
70
+ highlighted,
71
+ isToday,
72
+ isCurrentMonth,
73
+ onPress,
74
+ disabledError,
75
+ todayAccessibilityHint,
76
+ highlightedDateAccessibilityHint,
77
+ style
78
+ } = _ref2;
79
+ const {
80
+ locale
81
+ } = useLocale();
82
+ const handlePress = useCallback(() => onPress == null ? void 0 : onPress(date), [date, onPress]);
83
+ const accessibilityLabel = useMemo(() => getDayAccessibilityLabel(date, locale), [date, locale]);
84
+ const accessibilityState = useMemo(() => ({
85
+ disabled: !!disabled,
86
+ selected: !!active
87
+ }), [disabled, active]);
88
+
89
+ // Period between phrases gives screen readers a clear pause (e.g. "Today. Date unavailable").
90
+ const accessibilityHint = useMemo(() => {
91
+ const hints = [isToday ? todayAccessibilityHint : undefined, highlighted ? highlightedDateAccessibilityHint : undefined, disabled ? disabledError : undefined].filter(Boolean).join('. ');
92
+ return hints || undefined;
93
+ }, [disabled, highlighted, isToday, todayAccessibilityHint, highlightedDateAccessibilityHint, disabledError]);
94
+ const isScreenReaderEnabled = useScreenReaderStatus();
95
+
96
+ // Expose disabled to the tooltip's accessibilityState so screen readers on both platforms
97
+ // announce the day button as disabled. We only set disabled when a screen reader is active:
98
+ // on some platforms a11y disabled is equivalent to the top-level disabled prop, so always
99
+ // setting it would block tooltip interactivity for users not using SRs.
100
+ const tooltipAccessibilityState = useMemo(() => ({
101
+ disabled: isScreenReaderEnabled
102
+ }), [isScreenReaderEnabled]);
103
+ if (!isCurrentMonth) {
104
+ return /*#__PURE__*/_jsx(Box, {
105
+ "aria-hidden": true,
106
+ height: CALENDAR_DAY_DIMENSION,
107
+ width: CALENDAR_DAY_DIMENSION
108
+ });
109
+ }
110
+ const dayButton = /*#__PURE__*/_jsx(CalendarPressable, {
111
+ ref: ref,
112
+ accessibilityHint: accessibilityHint,
113
+ accessibilityLabel: accessibilityLabel,
114
+ accessibilityRole: "button",
115
+ accessibilityState: accessibilityState,
116
+ background: active && !disabled ? 'bgPrimary' : undefined,
117
+ borderColor: isToday ? 'bgPrimary' : undefined,
118
+ bordered: isToday,
119
+ disabled: disabled,
120
+ feedback: disabled ? 'none' : 'light',
121
+ onPress: handlePress,
122
+ style: style,
123
+ children: /*#__PURE__*/_jsx(Text, {
124
+ accessible: false,
125
+ align: "center",
126
+ color: active && !disabled ? 'fgInverse' : highlighted ? 'fgPrimary' : undefined,
127
+ font: "body",
128
+ children: date.getDate()
129
+ })
130
+ });
131
+ if (disabled) {
132
+ return /*#__PURE__*/_jsx(Tooltip, {
133
+ accessibilityHint: accessibilityHint,
134
+ accessibilityLabel: accessibilityLabel,
135
+ accessibilityState: tooltipAccessibilityState,
136
+ content: disabledError,
137
+ children: dayButton
138
+ });
139
+ }
140
+ return dayButton;
141
+ }));
142
+ CalendarDay.displayName = 'CalendarDay';
143
+ export const Calendar = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref3, ref) => {
144
+ let {
145
+ selectedDate,
146
+ seedDate,
147
+ onPressDate,
148
+ disabled,
149
+ hideControls,
150
+ disabledDates,
151
+ highlightedDates,
152
+ minDate,
153
+ maxDate,
154
+ disabledDateError = 'Date unavailable',
155
+ nextArrowAccessibilityLabel = 'Go to next month',
156
+ previousArrowAccessibilityLabel = 'Go to previous month',
157
+ todayAccessibilityHint = 'Today',
158
+ highlightedDateAccessibilityHint = 'Highlighted',
159
+ style,
160
+ styles
161
+ } = _ref3,
162
+ props = _objectWithoutPropertiesLoose(_ref3, _excluded2);
163
+ const {
164
+ setA11yFocus,
165
+ announceForA11y
166
+ } = useA11y();
167
+ const today = useMemo(() => getMidnightDate(new Date()), []);
168
+ const todayTime = useMemo(() => today.getTime(), [today]);
169
+
170
+ // Determine default calendar seed date: use whichever comes first between maxDate and today
171
+ const defaultSeedDate = useMemo(() => {
172
+ if (selectedDate) {
173
+ return selectedDate;
174
+ }
175
+ if (seedDate) {
176
+ return seedDate;
177
+ }
178
+ if (maxDate) {
179
+ const maxDateTime = getMidnightDate(maxDate).getTime();
180
+ const todayTime = today.getTime();
181
+ return maxDateTime < todayTime ? maxDate : today;
182
+ }
183
+ return today;
184
+ }, [selectedDate, seedDate, maxDate, today]);
185
+ const [calendarSeedDate, setCalendarSeedDate] = useState(defaultSeedDate);
186
+ const initialFocusRef = useRef(null);
187
+ const calendarMonth = useMemo(() => generateCalendarMonth(calendarSeedDate), [calendarSeedDate]);
188
+ const selectedTime = useMemo(() => selectedDate ? getMidnightDate(selectedDate).getTime() : null, [selectedDate]);
189
+ const disabledTimes = useMemo(() => new Set(getTimesFromDatesAndRanges(disabledDates || [])), [disabledDates]);
190
+ const focusTargetTime = useMemo(() => selectedTime || (seedDate ? getMidnightDate(seedDate).getTime() : null) || todayTime, [selectedTime, seedDate, todayTime]);
191
+ useImperativeHandle(ref, () => ({
192
+ focusInitialDate: () => {
193
+ if (disabled || !initialFocusRef.current) {
194
+ return;
195
+ }
196
+ setA11yFocus(initialFocusRef);
197
+ }
198
+ }), [disabled, setA11yFocus]);
199
+ const minTime = useMemo(() => minDate && getMidnightDate(minDate).getTime(), [minDate]);
200
+ const maxTime = useMemo(() => maxDate && getMidnightDate(maxDate).getTime(), [maxDate]);
201
+ const highlightedTimes = useMemo(() => new Set(getTimesFromDatesAndRanges(highlightedDates || [])), [highlightedDates]);
202
+ const handleGoNextMonth = useCallback(() => {
203
+ setCalendarSeedDate(s => {
204
+ const next = new Date(s.getFullYear(), s.getMonth() + 1, 1);
205
+ announceForA11y(next.toLocaleDateString('en-US', {
206
+ month: 'long',
207
+ year: 'numeric'
208
+ }));
209
+ return next;
210
+ });
211
+ }, [setCalendarSeedDate, announceForA11y]);
212
+ const handleGoPreviousMonth = useCallback(() => {
213
+ setCalendarSeedDate(s => {
214
+ const prev = new Date(s.getFullYear(), s.getMonth() - 1, 1);
215
+ announceForA11y(prev.toLocaleDateString('en-US', {
216
+ month: 'long',
217
+ year: 'numeric'
218
+ }));
219
+ return prev;
220
+ });
221
+ }, [setCalendarSeedDate, announceForA11y]);
222
+ const disableGoNextMonth = useMemo(() => {
223
+ if (disabled) {
224
+ return true;
225
+ }
226
+ const firstDateOfNextMonth = new Date(calendarSeedDate.getFullYear(), calendarSeedDate.getMonth() + 1, 1);
227
+ return maxTime ? maxTime < firstDateOfNextMonth.getTime() : false;
228
+ }, [maxTime, calendarSeedDate, disabled]);
229
+ const disableGoPreviousMonth = useMemo(() => {
230
+ if (disabled) {
231
+ return true;
232
+ }
233
+ const lastDateOfPreviousMonth = new Date(calendarSeedDate.getFullYear(), calendarSeedDate.getMonth(), 0);
234
+ return minTime ? minTime > lastDateOfPreviousMonth.getTime() : false;
235
+ }, [minTime, calendarSeedDate, disabled]);
236
+
237
+ // Split calendar month into weeks
238
+ const calendarWeeks = useMemo(() => {
239
+ const weeks = [];
240
+ for (let i = 0; i < calendarMonth.length; i += DAYS_OF_WEEK.length) {
241
+ const weekDates = calendarMonth.slice(i, i + DAYS_OF_WEEK.length);
242
+ weeks.push(["week-" + calendarMonth[i].getTime(), weekDates]);
243
+ }
244
+ return weeks;
245
+ }, [calendarMonth]);
246
+ const monthYearLabel = useMemo(() => calendarSeedDate.toLocaleDateString('en-US', {
247
+ month: 'long',
248
+ year: 'numeric'
249
+ }), [calendarSeedDate]);
250
+ const previousArrowAccessibilityState = useMemo(() => ({
251
+ disabled: !!disableGoPreviousMonth
252
+ }), [disableGoPreviousMonth]);
253
+ const nextArrowAccessibilityState = useMemo(() => ({
254
+ disabled: !!disableGoNextMonth
255
+ }), [disableGoNextMonth]);
256
+ return /*#__PURE__*/_jsxs(VStack, _extends({
257
+ opacity: disabled ? accessibleOpacityDisabled : undefined,
258
+ style: [style, styles == null ? void 0 : styles.root]
259
+ }, props, {
260
+ children: [/*#__PURE__*/_jsxs(HStack, {
261
+ alignItems: "center",
262
+ justifyContent: "space-between",
263
+ paddingBottom: 2,
264
+ paddingStart: 1.5,
265
+ style: styles == null ? void 0 : styles.header,
266
+ children: [/*#__PURE__*/_jsx(Text, {
267
+ accessibilityRole: "header",
268
+ font: "headline",
269
+ style: styles == null ? void 0 : styles.title,
270
+ children: monthYearLabel
271
+ }), !hideControls && /*#__PURE__*/_jsxs(HStack, {
272
+ gap: 1,
273
+ style: styles == null ? void 0 : styles.navigation,
274
+ children: [/*#__PURE__*/_jsx(CalendarPressable, {
275
+ accessibilityLabel: previousArrowAccessibilityLabel,
276
+ accessibilityRole: "button",
277
+ accessibilityState: previousArrowAccessibilityState,
278
+ disabled: disableGoPreviousMonth,
279
+ feedback: "light",
280
+ onPress: disableGoPreviousMonth ? undefined : handleGoPreviousMonth,
281
+ children: /*#__PURE__*/_jsx(Icon, {
282
+ color: "fg",
283
+ name: "backArrow",
284
+ size: "s"
285
+ })
286
+ }), /*#__PURE__*/_jsx(CalendarPressable, {
287
+ accessibilityLabel: nextArrowAccessibilityLabel,
288
+ accessibilityRole: "button",
289
+ accessibilityState: nextArrowAccessibilityState,
290
+ disabled: disableGoNextMonth,
291
+ feedback: "light",
292
+ onPress: disableGoNextMonth ? undefined : handleGoNextMonth,
293
+ children: /*#__PURE__*/_jsx(Icon, {
294
+ color: "fg",
295
+ name: "forwardArrow",
296
+ size: "s"
297
+ })
298
+ })]
299
+ })]
300
+ }), /*#__PURE__*/_jsxs(VStack, {
301
+ gap: 1,
302
+ style: styles == null ? void 0 : styles.content,
303
+ children: [/*#__PURE__*/_jsx(HStack, {
304
+ "aria-hidden": true,
305
+ gap: 1,
306
+ justifyContent: "space-between",
307
+ paddingBottom: 1,
308
+ children: DAYS_OF_WEEK.map(day => /*#__PURE__*/_jsx(Box, {
309
+ alignItems: "center",
310
+ height: CALENDAR_DAY_DIMENSION,
311
+ justifyContent: "center",
312
+ width: CALENDAR_DAY_DIMENSION,
313
+ children: /*#__PURE__*/_jsx(Text, {
314
+ font: "body",
315
+ userSelect: "none",
316
+ children: day.charAt(0)
317
+ })
318
+ }, day))
319
+ }), calendarWeeks.map(_ref4 => {
320
+ let [weekId, week] = _ref4;
321
+ return /*#__PURE__*/_jsx(HStack, {
322
+ gap: 1,
323
+ justifyContent: "space-between",
324
+ children: week.map(date => {
325
+ const time = date.getTime();
326
+ return /*#__PURE__*/_jsx(CalendarDay, {
327
+ ref: time === focusTargetTime ? initialFocusRef : undefined,
328
+ active: time === selectedTime,
329
+ date: date,
330
+ disabled: disabled || minTime !== undefined && minTime !== null && time < minTime || maxTime !== undefined && maxTime !== null && time > maxTime || disabledTimes.has(time),
331
+ disabledError: disabledDateError,
332
+ highlighted: highlightedTimes.has(time),
333
+ highlightedDateAccessibilityHint: highlightedDateAccessibilityHint,
334
+ isCurrentMonth: date.getMonth() === calendarSeedDate.getMonth(),
335
+ isToday: time === todayTime,
336
+ onPress: onPressDate,
337
+ style: styles == null ? void 0 : styles.day,
338
+ todayAccessibilityHint: todayAccessibilityHint
339
+ }, time);
340
+ })
341
+ }, weekId);
342
+ })]
343
+ })]
344
+ }));
345
+ }));
346
+ Calendar.displayName = 'Calendar';
@@ -1,4 +1,4 @@
1
- const _excluded = ["date", "onChangeDate", "error", "onErrorDate", "required", "separator", "minDate", "maxDate", "requiredError", "invalidDateError", "disabledDateError", "start", "end", "placeholder", "helperText", "variant", "onBlur", "onChange", "onEndEditing", "testIDMap", "style"];
1
+ const _excluded = ["date", "onChangeDate", "error", "onErrorDate", "required", "separator", "disabledDates", "minDate", "maxDate", "requiredError", "invalidDateError", "disabledDateError", "start", "end", "placeholder", "helperText", "variant", "onBlur", "onChange", "onEndEditing", "testIDMap", "style"];
2
2
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
3
3
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
4
4
  import React, { forwardRef, memo, useCallback, useMemo, useRef } from 'react';
@@ -16,6 +16,7 @@ export const DateInput = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
16
16
  onErrorDate,
17
17
  required,
18
18
  separator = '/',
19
+ disabledDates,
19
20
  minDate,
20
21
  maxDate,
21
22
  requiredError,
@@ -53,6 +54,7 @@ export const DateInput = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
53
54
  onErrorDate,
54
55
  intlDateFormat,
55
56
  required,
57
+ disabledDates,
56
58
  minDate,
57
59
  maxDate,
58
60
  requiredError,
@@ -1,15 +1,24 @@
1
- const _excluded = ["date", "onChangeDate", "error", "onErrorDate", "required", "disabled", "seedDate", "minDate", "maxDate", "requiredError", "invalidDateError", "disabledDateError", "label", "accessibilityLabel", "accessibilityLabelledBy", "calendarIconButtonAccessibilityLabel", "dateInputStyle", "compact", "variant", "helperText", "width", "onOpen", "onClose", "onConfirm", "onCancel", "onChange"];
1
+ const _excluded = ["date", "styles", "highlightedDates", "highlightedDateAccessibilityHint", "nextArrowAccessibilityLabel", "previousArrowAccessibilityLabel", "disabledDates", "onChangeDate", "error", "onErrorDate", "required", "disabled", "seedDate", "minDate", "maxDate", "requiredError", "invalidDateError", "disabledDateError", "label", "accessibilityHint", "accessibilityLabel", "accessibilityLabelledBy", "calendarIconButtonAccessibilityLabel", "openCalendarAccessibilityLabel", "closeCalendarAccessibilityLabel", "dateInputStyle", "compact", "variant", "confirmText", "confirmButtonAccessibilityHint", "helperText", "width", "onOpen", "onClose", "onConfirm", "onCancel", "onChange"];
2
2
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
3
3
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
4
4
  import { forwardRef, memo, useCallback, useMemo, useRef, useState } from 'react';
5
- import NativeDatePicker from 'react-native-date-picker';
5
+ import { Button } from '../buttons/Button';
6
6
  import { InputIconButton } from '../controls/InputIconButton';
7
7
  import { Box, VStack } from '../layout';
8
+ import { Tray } from '../overlays/tray/Tray';
9
+ import { StickyFooter } from '../sticky-footer/StickyFooter';
10
+ import { Calendar } from './Calendar';
8
11
  import { DateInput } from './DateInput';
9
12
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
13
  export const DatePicker = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) => {
11
14
  let {
12
15
  date,
16
+ styles,
17
+ highlightedDates,
18
+ highlightedDateAccessibilityHint,
19
+ nextArrowAccessibilityLabel,
20
+ previousArrowAccessibilityLabel,
21
+ disabledDates,
13
22
  onChangeDate,
14
23
  error,
15
24
  onErrorDate,
@@ -22,12 +31,17 @@ export const DatePicker = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref)
22
31
  invalidDateError = 'Please enter a valid date',
23
32
  disabledDateError = 'Date unavailable',
24
33
  label,
34
+ accessibilityHint = 'Enter date or select from calendar using the calendar button.',
25
35
  accessibilityLabel,
26
36
  accessibilityLabelledBy,
27
37
  calendarIconButtonAccessibilityLabel,
38
+ openCalendarAccessibilityLabel = 'Open calendar',
39
+ closeCalendarAccessibilityLabel = 'Close calendar without selecting a date',
28
40
  dateInputStyle,
29
41
  compact,
30
42
  variant,
43
+ confirmText = 'Confirm',
44
+ confirmButtonAccessibilityHint,
31
45
  helperText,
32
46
  width = '100%',
33
47
  onOpen,
@@ -37,61 +51,78 @@ export const DatePicker = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref)
37
51
  onChange
38
52
  } = _ref,
39
53
  props = _objectWithoutPropertiesLoose(_ref, _excluded);
40
- const [showNativePicker, setShowNativePicker] = useState(false);
54
+ const [showPicker, setShowPicker] = useState(false);
55
+ const [calendarSelectedDate, setCalendarSelectedDate] = useState(null);
41
56
  const dateInputRef = useRef(null);
42
- const today = useMemo(() => new Date(), []);
43
-
57
+ const calendarButtonRef = useRef(null);
58
+ const calendarRef = useRef(null);
59
+ const closedByConfirmRef = useRef(false);
44
60
  /**
45
61
  * Be careful to preserve the correct event orders
46
- * 1. Selecting a date with the native picker: onOpen -> onConfirm -> onChangeDate -> onErrorDate -> onClose
47
- * 2. Closing the native picker without selecting a date: onOpen -> onCancel -> onClose
62
+ * 1. Selecting a date with the picker: onOpen -> onConfirm -> onChangeDate -> onErrorDate -> onClose
63
+ * 2. Closing the picker without selecting a date: onOpen -> onCancel -> onClose
48
64
  * 3. Typing a date in a blank DateInput: onChange -> onChange -> ... -> onChangeDate -> onErrorDate
49
65
  * 4. Typing a date in a DateInput that already had a date: onChange -> onChangeDate -> onChange -> onChange -> ... -> onChangeDate -> onErrorDate
50
66
  */
51
67
 
52
- const handleOpenNativePicker = useCallback(() => {
68
+ const handleOpenPicker = useCallback(() => {
53
69
  onOpen == null || onOpen();
54
- setShowNativePicker(true);
55
- }, [onOpen]);
56
- const handleCloseNativePicker = useCallback(() => {
57
- onClose == null || onClose();
58
- setShowNativePicker(false);
59
- }, [onClose]);
60
- const handleConfirmNativePicker = useCallback(date => {
61
- var _dateInputRef$current;
70
+ setCalendarSelectedDate(date); // Initialize with current date
71
+ setShowPicker(true);
72
+ }, [onOpen, date]);
73
+ const handleConfirmPicker = useCallback(selectedDate => {
74
+ closedByConfirmRef.current = true;
62
75
  onConfirm == null || onConfirm();
63
- onChangeDate(date);
64
- if (error && error.type !== 'custom') onErrorDate(null);
65
- handleCloseNativePicker();
66
- (_dateInputRef$current = dateInputRef.current) == null || _dateInputRef$current.focus();
67
- }, [onChangeDate, onConfirm, error, onErrorDate, handleCloseNativePicker]);
68
- const handleCancelNativePicker = useCallback(() => {
69
- onCancel == null || onCancel();
70
- handleCloseNativePicker();
71
- }, [onCancel, handleCloseNativePicker]);
76
+ onChangeDate(selectedDate);
77
+ if (error && error.type !== 'custom') {
78
+ onErrorDate(null);
79
+ }
80
+ }, [onChangeDate, onConfirm, error, onErrorDate]);
81
+ const handleTrayCloseComplete = useCallback(() => {
82
+ if (!closedByConfirmRef.current) {
83
+ onCancel == null || onCancel();
84
+ setCalendarSelectedDate(null);
85
+ }
86
+ onClose == null || onClose();
87
+ setShowPicker(false);
88
+ closedByConfirmRef.current = false;
89
+ }, [onCancel, onClose]);
90
+ const handleCalendarDatePress = useCallback(selectedDate => {
91
+ // Update local state, user must press confirm button
92
+ setCalendarSelectedDate(selectedDate);
93
+ }, []);
94
+ const handleModalShow = useCallback(() => {
95
+ var _calendarRef$current;
96
+ (_calendarRef$current = calendarRef.current) == null || _calendarRef$current.focusInitialDate();
97
+ }, []);
72
98
  const dateInputCalendarButton = useMemo(() => /*#__PURE__*/_jsx(VStack, {
99
+ accessible: true,
73
100
  paddingEnd: 0.5,
74
101
  children: /*#__PURE__*/_jsx(InputIconButton, {
102
+ ref: calendarButtonRef,
75
103
  disableInheritFocusStyle: true,
76
104
  transparent: true,
77
- accessibilityLabel: calendarIconButtonAccessibilityLabel != null ? calendarIconButtonAccessibilityLabel : showNativePicker ? 'Close calendar' : 'Open calendar',
105
+ accessibilityLabel: calendarIconButtonAccessibilityLabel != null ? calendarIconButtonAccessibilityLabel : openCalendarAccessibilityLabel,
106
+ disabled: disabled,
78
107
  name: "calendarEmpty",
79
- onPress: handleOpenNativePicker,
108
+ onPress: handleOpenPicker,
80
109
  variant: "secondary"
81
110
  })
82
- }), [handleOpenNativePicker, showNativePicker, calendarIconButtonAccessibilityLabel]);
111
+ }), [handleOpenPicker, openCalendarAccessibilityLabel, calendarIconButtonAccessibilityLabel, disabled]);
83
112
  return /*#__PURE__*/_jsxs(Box, {
84
113
  ref: ref,
85
114
  width: width,
86
115
  children: [/*#__PURE__*/_jsx(DateInput, _extends({
87
116
  ref: dateInputRef
88
117
  }, props, {
118
+ accessibilityHint: accessibilityHint,
89
119
  accessibilityLabel: accessibilityLabel,
90
120
  accessibilityLabelledBy: accessibilityLabelledBy,
91
121
  compact: compact,
92
122
  date: date,
93
123
  disabled: disabled,
94
124
  disabledDateError: disabledDateError,
125
+ disabledDates: disabledDates,
95
126
  end: dateInputCalendarButton,
96
127
  error: error,
97
128
  helperText: helperText,
@@ -104,17 +135,63 @@ export const DatePicker = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref)
104
135
  onErrorDate: onErrorDate,
105
136
  required: required,
106
137
  requiredError: requiredError,
107
- style: dateInputStyle,
138
+ style: [dateInputStyle, styles == null ? void 0 : styles.dateInput],
108
139
  variant: variant
109
- })), showNativePicker && /*#__PURE__*/_jsx(NativeDatePicker, {
110
- modal: true,
111
- date: date || seedDate || today,
112
- maximumDate: maxDate,
113
- minimumDate: minDate,
114
- mode: "date",
115
- onCancel: handleCancelNativePicker,
116
- onConfirm: handleConfirmNativePicker,
117
- open: showNativePicker
140
+ })), showPicker && /*#__PURE__*/_jsx(Tray, {
141
+ accessibilityRole: "none",
142
+ footer: _ref2 => {
143
+ let {
144
+ handleClose
145
+ } = _ref2;
146
+ return /*#__PURE__*/_jsx(StickyFooter, {
147
+ paddingTop: 3,
148
+ paddingX: 3,
149
+ role: "none",
150
+ children: /*#__PURE__*/_jsx(Button, {
151
+ block: true,
152
+ compact: true,
153
+ accessibilityHint: confirmButtonAccessibilityHint,
154
+ disabled: disabled || !calendarSelectedDate,
155
+ onPress: () => {
156
+ if (calendarSelectedDate) {
157
+ handleConfirmPicker(calendarSelectedDate);
158
+ handleClose();
159
+ }
160
+ },
161
+ children: confirmText
162
+ })
163
+ });
164
+ },
165
+ handleBarAccessibilityLabel: closeCalendarAccessibilityLabel,
166
+ handleBarVariant: "inside",
167
+ onCloseComplete: handleTrayCloseComplete,
168
+ onOpenComplete: handleModalShow,
169
+ children: /*#__PURE__*/_jsx(Calendar, {
170
+ ref: calendarRef,
171
+ disabled: disabled,
172
+ disabledDateError: disabledDateError,
173
+ disabledDates: disabledDates,
174
+ highlightedDateAccessibilityHint: highlightedDateAccessibilityHint,
175
+ highlightedDates: highlightedDates,
176
+ maxDate: maxDate,
177
+ minDate: minDate,
178
+ nextArrowAccessibilityLabel: nextArrowAccessibilityLabel,
179
+ onPressDate: handleCalendarDatePress,
180
+ paddingBottom: 2,
181
+ paddingX: 3,
182
+ previousArrowAccessibilityLabel: previousArrowAccessibilityLabel,
183
+ seedDate: seedDate,
184
+ selectedDate: calendarSelectedDate,
185
+ styles: {
186
+ root: styles == null ? void 0 : styles.calendar,
187
+ header: styles == null ? void 0 : styles.calendarHeader,
188
+ title: styles == null ? void 0 : styles.calendarTitle,
189
+ navigation: styles == null ? void 0 : styles.calendarNavigation,
190
+ content: styles == null ? void 0 : styles.calendarContent,
191
+ day: styles == null ? void 0 : styles.calendarDay
192
+ }
193
+ })
118
194
  })]
119
195
  });
120
- }));
196
+ }));
197
+ DatePicker.displayName = 'DatePicker';