@xsolla/xui-date-picker 0.64.0-pr56.1768440195

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.
@@ -0,0 +1,938 @@
1
+ // src/DatePicker.tsx
2
+ import { forwardRef as forwardRef4, useCallback as useCallback3, useEffect as useEffect2, useRef, useState as useState2 } from "react";
3
+
4
+ // ../primitives-native/src/Box.tsx
5
+ import {
6
+ View,
7
+ Pressable,
8
+ Image
9
+ } from "react-native";
10
+ import { jsx } from "react/jsx-runtime";
11
+ var Box = ({
12
+ children,
13
+ onPress,
14
+ onLayout,
15
+ onMoveShouldSetResponder,
16
+ onResponderGrant,
17
+ onResponderMove,
18
+ onResponderRelease,
19
+ onResponderTerminate,
20
+ backgroundColor,
21
+ borderColor,
22
+ borderWidth,
23
+ borderBottomWidth,
24
+ borderBottomColor,
25
+ borderTopWidth,
26
+ borderTopColor,
27
+ borderLeftWidth,
28
+ borderLeftColor,
29
+ borderRightWidth,
30
+ borderRightColor,
31
+ borderRadius,
32
+ borderStyle,
33
+ height,
34
+ padding,
35
+ paddingHorizontal,
36
+ paddingVertical,
37
+ margin,
38
+ marginTop,
39
+ marginBottom,
40
+ marginLeft,
41
+ marginRight,
42
+ flexDirection,
43
+ alignItems,
44
+ justifyContent,
45
+ position,
46
+ top,
47
+ bottom,
48
+ left,
49
+ right,
50
+ width,
51
+ flex,
52
+ overflow,
53
+ zIndex,
54
+ hoverStyle,
55
+ pressStyle,
56
+ style,
57
+ "data-testid": dataTestId,
58
+ testID,
59
+ as,
60
+ src,
61
+ alt,
62
+ ...rest
63
+ }) => {
64
+ const getContainerStyle = (pressed) => ({
65
+ backgroundColor: pressed && pressStyle?.backgroundColor ? pressStyle.backgroundColor : backgroundColor,
66
+ borderColor,
67
+ borderWidth,
68
+ borderBottomWidth,
69
+ borderBottomColor,
70
+ borderTopWidth,
71
+ borderTopColor,
72
+ borderLeftWidth,
73
+ borderLeftColor,
74
+ borderRightWidth,
75
+ borderRightColor,
76
+ borderRadius,
77
+ borderStyle,
78
+ overflow,
79
+ zIndex,
80
+ height,
81
+ width,
82
+ padding,
83
+ paddingHorizontal,
84
+ paddingVertical,
85
+ margin,
86
+ marginTop,
87
+ marginBottom,
88
+ marginLeft,
89
+ marginRight,
90
+ flexDirection,
91
+ alignItems,
92
+ justifyContent,
93
+ position,
94
+ top,
95
+ bottom,
96
+ left,
97
+ right,
98
+ flex,
99
+ ...style
100
+ });
101
+ const finalTestID = dataTestId || testID;
102
+ const {
103
+ role,
104
+ tabIndex,
105
+ onKeyDown,
106
+ onKeyUp,
107
+ "aria-label": _ariaLabel,
108
+ "aria-labelledby": _ariaLabelledBy,
109
+ "aria-current": _ariaCurrent,
110
+ "aria-disabled": _ariaDisabled,
111
+ "aria-live": _ariaLive,
112
+ className,
113
+ "data-testid": _dataTestId,
114
+ ...nativeRest
115
+ } = rest;
116
+ if (as === "img" && src) {
117
+ const imageStyle = {
118
+ width,
119
+ height,
120
+ borderRadius,
121
+ position,
122
+ top,
123
+ bottom,
124
+ left,
125
+ right,
126
+ ...style
127
+ };
128
+ return /* @__PURE__ */ jsx(
129
+ Image,
130
+ {
131
+ source: { uri: src },
132
+ style: imageStyle,
133
+ testID: finalTestID,
134
+ resizeMode: "cover",
135
+ ...nativeRest
136
+ }
137
+ );
138
+ }
139
+ if (onPress) {
140
+ return /* @__PURE__ */ jsx(
141
+ Pressable,
142
+ {
143
+ onPress,
144
+ onLayout,
145
+ onMoveShouldSetResponder,
146
+ onResponderGrant,
147
+ onResponderMove,
148
+ onResponderRelease,
149
+ onResponderTerminate,
150
+ style: ({ pressed }) => getContainerStyle(pressed),
151
+ testID: finalTestID,
152
+ ...nativeRest,
153
+ children
154
+ }
155
+ );
156
+ }
157
+ return /* @__PURE__ */ jsx(
158
+ View,
159
+ {
160
+ style: getContainerStyle(),
161
+ testID: finalTestID,
162
+ onLayout,
163
+ onMoveShouldSetResponder,
164
+ onResponderGrant,
165
+ onResponderMove,
166
+ onResponderRelease,
167
+ onResponderTerminate,
168
+ ...nativeRest,
169
+ children
170
+ }
171
+ );
172
+ };
173
+
174
+ // ../primitives-native/src/Text.tsx
175
+ import { Text as RNText } from "react-native";
176
+ import { jsx as jsx2 } from "react/jsx-runtime";
177
+ var roleMap = {
178
+ alert: "alert",
179
+ heading: "header",
180
+ button: "button",
181
+ link: "link",
182
+ text: "text"
183
+ };
184
+ var Text = ({
185
+ children,
186
+ color,
187
+ fontSize,
188
+ fontWeight,
189
+ fontFamily,
190
+ id,
191
+ role,
192
+ ...props
193
+ }) => {
194
+ let resolvedFontFamily = fontFamily ? fontFamily.split(",")[0].replace(/['"]/g, "").trim() : void 0;
195
+ if (resolvedFontFamily === "Pilat Wide Bold") {
196
+ resolvedFontFamily = void 0;
197
+ }
198
+ const style = {
199
+ color,
200
+ fontSize: typeof fontSize === "number" ? fontSize : void 0,
201
+ fontWeight,
202
+ fontFamily: resolvedFontFamily,
203
+ textDecorationLine: props.textDecoration
204
+ };
205
+ const accessibilityRole = role ? roleMap[role] : void 0;
206
+ return /* @__PURE__ */ jsx2(RNText, { style, testID: id, accessibilityRole, children });
207
+ };
208
+
209
+ // ../primitives-native/src/Spinner.tsx
210
+ import { ActivityIndicator, View as View2 } from "react-native";
211
+ import { jsx as jsx3 } from "react/jsx-runtime";
212
+ var Spinner = ({
213
+ color,
214
+ size,
215
+ role,
216
+ "aria-label": ariaLabel,
217
+ "aria-live": ariaLive,
218
+ "aria-describedby": ariaDescribedBy,
219
+ testID
220
+ }) => {
221
+ return /* @__PURE__ */ jsx3(
222
+ View2,
223
+ {
224
+ accessible: true,
225
+ accessibilityRole: role === "status" ? "none" : void 0,
226
+ accessibilityLabel: ariaLabel,
227
+ accessibilityLiveRegion: ariaLive === "polite" ? "polite" : ariaLive === "assertive" ? "assertive" : "none",
228
+ testID,
229
+ children: /* @__PURE__ */ jsx3(
230
+ ActivityIndicator,
231
+ {
232
+ color,
233
+ size: typeof size === "number" ? size : "small"
234
+ }
235
+ )
236
+ }
237
+ );
238
+ };
239
+ Spinner.displayName = "Spinner";
240
+
241
+ // ../primitives-native/src/Icon.tsx
242
+ import React from "react";
243
+ import { View as View3 } from "react-native";
244
+ import { jsx as jsx4 } from "react/jsx-runtime";
245
+
246
+ // ../primitives-native/src/Divider.tsx
247
+ import { View as View4 } from "react-native";
248
+ import { jsx as jsx5 } from "react/jsx-runtime";
249
+
250
+ // ../primitives-native/src/Input.tsx
251
+ import { forwardRef } from "react";
252
+ import { TextInput as RNTextInput } from "react-native";
253
+ import { jsx as jsx6 } from "react/jsx-runtime";
254
+ var keyboardTypeMap = {
255
+ text: "default",
256
+ number: "numeric",
257
+ email: "email-address",
258
+ tel: "phone-pad",
259
+ url: "url",
260
+ decimal: "decimal-pad"
261
+ };
262
+ var inputModeToKeyboardType = {
263
+ none: "default",
264
+ text: "default",
265
+ decimal: "decimal-pad",
266
+ numeric: "number-pad",
267
+ tel: "phone-pad",
268
+ search: "default",
269
+ email: "email-address",
270
+ url: "url"
271
+ };
272
+ var autoCompleteToTextContentType = {
273
+ "one-time-code": "oneTimeCode",
274
+ email: "emailAddress",
275
+ username: "username",
276
+ password: "password",
277
+ "new-password": "newPassword",
278
+ tel: "telephoneNumber",
279
+ "postal-code": "postalCode",
280
+ name: "name"
281
+ };
282
+ var InputPrimitive = forwardRef(
283
+ ({
284
+ value,
285
+ placeholder,
286
+ onChange,
287
+ onChangeText,
288
+ onFocus,
289
+ onBlur,
290
+ onKeyDown,
291
+ disabled,
292
+ secureTextEntry,
293
+ style,
294
+ color,
295
+ fontSize,
296
+ placeholderTextColor,
297
+ maxLength,
298
+ name,
299
+ type,
300
+ inputMode,
301
+ autoComplete,
302
+ id,
303
+ "aria-invalid": ariaInvalid,
304
+ "aria-describedby": ariaDescribedBy,
305
+ "aria-labelledby": ariaLabelledBy,
306
+ "aria-label": ariaLabel,
307
+ "aria-disabled": ariaDisabled,
308
+ "data-testid": dataTestId
309
+ }, ref) => {
310
+ const handleChangeText = (text) => {
311
+ onChangeText?.(text);
312
+ if (onChange) {
313
+ const syntheticEvent = {
314
+ target: { value: text },
315
+ currentTarget: { value: text },
316
+ type: "change",
317
+ nativeEvent: { text },
318
+ preventDefault: () => {
319
+ },
320
+ stopPropagation: () => {
321
+ },
322
+ isTrusted: false
323
+ };
324
+ onChange(syntheticEvent);
325
+ }
326
+ };
327
+ const keyboardType = inputMode ? inputModeToKeyboardType[inputMode] || "default" : type ? keyboardTypeMap[type] || "default" : "default";
328
+ const textContentType = autoComplete ? autoCompleteToTextContentType[autoComplete] : void 0;
329
+ return /* @__PURE__ */ jsx6(
330
+ RNTextInput,
331
+ {
332
+ ref,
333
+ value,
334
+ placeholder,
335
+ onChangeText: handleChangeText,
336
+ onFocus,
337
+ onBlur,
338
+ onKeyPress: (e) => {
339
+ if (onKeyDown) {
340
+ onKeyDown({
341
+ key: e.nativeEvent.key,
342
+ preventDefault: () => {
343
+ }
344
+ });
345
+ }
346
+ },
347
+ editable: !disabled,
348
+ secureTextEntry: secureTextEntry || type === "password",
349
+ keyboardType,
350
+ textContentType,
351
+ style: [
352
+ {
353
+ color,
354
+ fontSize: typeof fontSize === "number" ? fontSize : void 0,
355
+ flex: 1,
356
+ padding: 0,
357
+ textAlign: style?.textAlign || "left"
358
+ },
359
+ style
360
+ ],
361
+ placeholderTextColor,
362
+ maxLength,
363
+ testID: dataTestId || id,
364
+ accessibilityLabel: ariaLabel,
365
+ accessibilityHint: ariaDescribedBy,
366
+ accessibilityState: {
367
+ disabled: disabled || ariaDisabled
368
+ },
369
+ accessible: true
370
+ }
371
+ );
372
+ }
373
+ );
374
+ InputPrimitive.displayName = "InputPrimitive";
375
+
376
+ // ../primitives-native/src/TextArea.tsx
377
+ import { forwardRef as forwardRef2 } from "react";
378
+ import { TextInput as RNTextInput2 } from "react-native";
379
+ import { jsx as jsx7 } from "react/jsx-runtime";
380
+ var TextAreaPrimitive = forwardRef2(
381
+ ({
382
+ value,
383
+ placeholder,
384
+ onChange,
385
+ onChangeText,
386
+ onFocus,
387
+ onBlur,
388
+ onKeyDown,
389
+ disabled,
390
+ style,
391
+ color,
392
+ fontSize,
393
+ placeholderTextColor,
394
+ maxLength,
395
+ rows,
396
+ id,
397
+ "aria-invalid": ariaInvalid,
398
+ "aria-describedby": ariaDescribedBy,
399
+ "aria-labelledby": ariaLabelledBy,
400
+ "aria-label": ariaLabel,
401
+ "aria-disabled": ariaDisabled,
402
+ "data-testid": dataTestId
403
+ }, ref) => {
404
+ const handleChangeText = (text) => {
405
+ onChangeText?.(text);
406
+ if (onChange) {
407
+ const syntheticEvent = {
408
+ target: { value: text },
409
+ currentTarget: { value: text },
410
+ type: "change",
411
+ nativeEvent: { text },
412
+ preventDefault: () => {
413
+ },
414
+ stopPropagation: () => {
415
+ },
416
+ isTrusted: false
417
+ };
418
+ onChange(syntheticEvent);
419
+ }
420
+ };
421
+ return /* @__PURE__ */ jsx7(
422
+ RNTextInput2,
423
+ {
424
+ ref,
425
+ value,
426
+ placeholder,
427
+ onChangeText: handleChangeText,
428
+ onFocus,
429
+ onBlur,
430
+ onKeyPress: (e) => {
431
+ if (onKeyDown) {
432
+ onKeyDown({
433
+ key: e.nativeEvent.key,
434
+ preventDefault: () => {
435
+ }
436
+ });
437
+ }
438
+ },
439
+ editable: !disabled,
440
+ multiline: true,
441
+ numberOfLines: rows || 4,
442
+ style: [
443
+ {
444
+ color,
445
+ fontSize: typeof fontSize === "number" ? fontSize : void 0,
446
+ flex: 1,
447
+ padding: 0,
448
+ textAlignVertical: "top",
449
+ textAlign: style?.textAlign || "left"
450
+ },
451
+ style
452
+ ],
453
+ placeholderTextColor,
454
+ maxLength,
455
+ testID: dataTestId || id,
456
+ accessibilityLabel: ariaLabel,
457
+ accessibilityHint: ariaDescribedBy,
458
+ accessibilityState: {
459
+ disabled: disabled || ariaDisabled
460
+ },
461
+ accessible: true
462
+ }
463
+ );
464
+ }
465
+ );
466
+ TextAreaPrimitive.displayName = "TextAreaPrimitive";
467
+
468
+ // src/DatePicker.tsx
469
+ import { Input } from "@xsolla/xui-input";
470
+ import { useDesignSystem as useDesignSystem2, isWeb, isNative } from "@xsolla/xui-core";
471
+ import { format as format3 } from "date-fns";
472
+
473
+ // src/Calendar.tsx
474
+ import { forwardRef as forwardRef3, useCallback as useCallback2, useEffect, useMemo as useMemo2, useState } from "react";
475
+ import { useDesignSystem } from "@xsolla/xui-core";
476
+ import {
477
+ addDays,
478
+ addMonths,
479
+ eachDayOfInterval,
480
+ endOfDay,
481
+ endOfMonth,
482
+ endOfWeek,
483
+ format as format2,
484
+ isAfter,
485
+ isBefore,
486
+ isSameDay,
487
+ isSameMonth,
488
+ isToday,
489
+ isWithinInterval,
490
+ startOfDay,
491
+ startOfMonth,
492
+ startOfWeek,
493
+ subMonths
494
+ } from "date-fns";
495
+ import * as locales2 from "date-fns/locale";
496
+
497
+ // src/CalendarHeader.tsx
498
+ import { useCallback, useMemo } from "react";
499
+ import { IconButton } from "@xsolla/xui-button";
500
+ import { Select } from "@xsolla/xui-select";
501
+
502
+ // src/utils.ts
503
+ import { format, setMonth } from "date-fns";
504
+ import * as locales from "date-fns/locale";
505
+ var defaultLocale = "enUS";
506
+ function formatDate(date, formatStr, locale = defaultLocale) {
507
+ const localeObj = locales[locale] || locales[defaultLocale];
508
+ return format(date, formatStr, {
509
+ locale: localeObj
510
+ });
511
+ }
512
+ function getMonthInLocale(month, locale = defaultLocale) {
513
+ return formatDate(setMonth(/* @__PURE__ */ new Date(), month), "LLLL", locale);
514
+ }
515
+
516
+ // src/CalendarHeader.tsx
517
+ import { jsx as jsx8, jsxs } from "react/jsx-runtime";
518
+ var ArrowLeft = () => /* @__PURE__ */ jsx8("svg", { viewBox: "0 0 24 24", width: 16, height: 16, fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx8("polyline", { points: "15 18 9 12 15 6" }) });
519
+ var ArrowRight = () => /* @__PURE__ */ jsx8("svg", { viewBox: "0 0 24 24", width: 16, height: 16, fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx8("polyline", { points: "9 18 15 12 9 6" }) });
520
+ var months = [
521
+ "january",
522
+ "february",
523
+ "march",
524
+ "april",
525
+ "may",
526
+ "june",
527
+ "july",
528
+ "august",
529
+ "september",
530
+ "october",
531
+ "november",
532
+ "december"
533
+ ];
534
+ var CalendarHeader = ({
535
+ monthDate,
536
+ decreaseMonth,
537
+ increaseMonth,
538
+ changeYear,
539
+ changeMonth,
540
+ prevMonthButtonDisabled,
541
+ nextMonthButtonDisabled,
542
+ locale,
543
+ minDate,
544
+ maxDate,
545
+ contextMenuMaxHeight = 240
546
+ }) => {
547
+ const handleChangeMonth = useCallback(
548
+ (value) => {
549
+ changeMonth(months.indexOf(value));
550
+ },
551
+ [changeMonth]
552
+ );
553
+ const handleChangeYear = useCallback(
554
+ (value) => {
555
+ changeYear(parseInt(value, 10));
556
+ },
557
+ [changeYear]
558
+ );
559
+ const monthOptions = useMemo(() => {
560
+ return months.map((month, index) => ({
561
+ label: getMonthInLocale(index, locale),
562
+ value: month
563
+ }));
564
+ }, [locale]);
565
+ const yearOptions = useMemo(() => {
566
+ const options = [];
567
+ const yearStart = minDate ? minDate.getFullYear() : 1900;
568
+ const yearEnd = maxDate ? maxDate.getFullYear() : (/* @__PURE__ */ new Date()).getFullYear() + 100;
569
+ for (let i = yearEnd; i >= yearStart; i--) {
570
+ options.push({ value: i.toString(), label: i.toString() });
571
+ }
572
+ return options;
573
+ }, [minDate, maxDate]);
574
+ return /* @__PURE__ */ jsxs(
575
+ Box,
576
+ {
577
+ width: "100%",
578
+ flexDirection: "row",
579
+ justifyContent: "space-between",
580
+ alignItems: "center",
581
+ marginBottom: 16,
582
+ gap: 8,
583
+ children: [
584
+ /* @__PURE__ */ jsx8(
585
+ IconButton,
586
+ {
587
+ size: "xs",
588
+ tone: "mono",
589
+ variant: "secondary",
590
+ onPress: decreaseMonth,
591
+ disabled: prevMonthButtonDisabled,
592
+ icon: /* @__PURE__ */ jsx8(ArrowLeft, {}),
593
+ "aria-label": "Previous month"
594
+ }
595
+ ),
596
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", flex: 1, gap: 4, children: [
597
+ /* @__PURE__ */ jsx8(Box, { flex: 1.5, children: /* @__PURE__ */ jsx8(
598
+ Select,
599
+ {
600
+ value: months[monthDate.getMonth()],
601
+ onValueChange: handleChangeMonth,
602
+ options: monthOptions,
603
+ size: "s"
604
+ }
605
+ ) }),
606
+ /* @__PURE__ */ jsx8(Box, { flex: 1, children: /* @__PURE__ */ jsx8(
607
+ Select,
608
+ {
609
+ value: monthDate.getFullYear().toString(),
610
+ onValueChange: handleChangeYear,
611
+ options: yearOptions,
612
+ size: "s"
613
+ }
614
+ ) })
615
+ ] }),
616
+ /* @__PURE__ */ jsx8(
617
+ IconButton,
618
+ {
619
+ size: "xs",
620
+ tone: "mono",
621
+ variant: "secondary",
622
+ onPress: increaseMonth,
623
+ disabled: nextMonthButtonDisabled,
624
+ icon: /* @__PURE__ */ jsx8(ArrowRight, {}),
625
+ "aria-label": "Next month"
626
+ }
627
+ )
628
+ ]
629
+ }
630
+ );
631
+ };
632
+
633
+ // src/Calendar.tsx
634
+ import { jsx as jsx9, jsxs as jsxs2 } from "react/jsx-runtime";
635
+ var Calendar = forwardRef3(
636
+ ({
637
+ locale = "enUS",
638
+ onChange,
639
+ startDate,
640
+ endDate,
641
+ selectedDate,
642
+ selectsRange = false,
643
+ contextMenuMaxHeight,
644
+ topContent,
645
+ bottomContent,
646
+ testID,
647
+ minDate,
648
+ maxDate,
649
+ firstDayOfWeek = 0,
650
+ month,
651
+ initialMonth
652
+ }, ref) => {
653
+ const { theme } = useDesignSystem();
654
+ const localeObj = locales2[locale] || locales2.enUS;
655
+ const [currentMonth, setCurrentMonth] = useState(
656
+ month || initialMonth || selectedDate || startDate || /* @__PURE__ */ new Date()
657
+ );
658
+ const [selectedStartDate, setSelectedStartDate] = useState(startDate);
659
+ const [selectedEndDate, setSelectedEndDate] = useState(endDate);
660
+ const [locSelectedDate, setLocSelectedDate] = useState(selectedDate);
661
+ const [selectingRange, setSelectingRange] = useState(null);
662
+ useEffect(() => {
663
+ setSelectedStartDate(startDate);
664
+ setSelectedEndDate(endDate);
665
+ setLocSelectedDate(selectedDate);
666
+ if (month !== void 0) {
667
+ setCurrentMonth(month);
668
+ }
669
+ }, [startDate, endDate, selectedDate, month]);
670
+ const handleChange = useCallback2(
671
+ (date) => {
672
+ const newDate = new Date(
673
+ currentMonth.getFullYear(),
674
+ currentMonth.getMonth(),
675
+ date.getDate()
676
+ );
677
+ if (!selectsRange) {
678
+ setLocSelectedDate(newDate);
679
+ onChange?.(newDate);
680
+ } else {
681
+ if (!selectedStartDate || selectedStartDate && selectedEndDate) {
682
+ setSelectedStartDate(newDate);
683
+ setSelectedEndDate(null);
684
+ setSelectingRange(newDate);
685
+ onChange?.([newDate, null]);
686
+ } else {
687
+ const start = selectedStartDate < newDate ? selectedStartDate : newDate;
688
+ const end = selectedStartDate < newDate ? newDate : selectedStartDate;
689
+ setSelectedStartDate(start);
690
+ setSelectedEndDate(end);
691
+ setSelectingRange(null);
692
+ onChange?.([start, end]);
693
+ }
694
+ }
695
+ },
696
+ [onChange, selectsRange, selectedStartDate, selectedEndDate, currentMonth]
697
+ );
698
+ const decreaseMonth = useCallback2(() => setCurrentMonth((prev) => subMonths(prev, 1)), []);
699
+ const increaseMonth = useCallback2(() => setCurrentMonth((prev) => addMonths(prev, 1)), []);
700
+ const changeMonth = useCallback2((m) => setCurrentMonth((prev) => new Date(prev.getFullYear(), m, 1)), []);
701
+ const changeYear = useCallback2((y) => setCurrentMonth((prev) => new Date(y, prev.getMonth(), 1)), []);
702
+ const monthStart = startOfMonth(currentMonth);
703
+ const monthEnd = endOfMonth(currentMonth);
704
+ const weekStartsOn = firstDayOfWeek ?? 0;
705
+ const calendarStart = startOfWeek(monthStart, { weekStartsOn });
706
+ const calendarEnd = endOfWeek(monthEnd, { weekStartsOn });
707
+ const days = eachDayOfInterval({ start: calendarStart, end: calendarEnd });
708
+ const weekDays = useMemo2(() => {
709
+ return Array.from({ length: 7 }, (_, i) => {
710
+ const day = addDays(calendarStart, i);
711
+ return format2(day, "EEEEEE", { locale: localeObj });
712
+ });
713
+ }, [calendarStart, localeObj]);
714
+ const weeks = useMemo2(() => {
715
+ const weekArray = [];
716
+ for (let i = 0; i < days.length; i += 7) {
717
+ weekArray.push(days.slice(i, i + 7));
718
+ }
719
+ return weekArray;
720
+ }, [days]);
721
+ const isDateDisabled = useCallback2(
722
+ (date) => {
723
+ if (minDate && isBefore(date, startOfDay(minDate))) return true;
724
+ if (maxDate && isAfter(date, endOfDay(maxDate))) return true;
725
+ return false;
726
+ },
727
+ [minDate, maxDate]
728
+ );
729
+ const isDateInRange = useCallback2(
730
+ (date) => {
731
+ if (!selectsRange || !selectedStartDate) return false;
732
+ const rangeEnd = selectedEndDate || selectingRange;
733
+ if (!rangeEnd) return false;
734
+ const start = selectedStartDate < rangeEnd ? selectedStartDate : rangeEnd;
735
+ const end = selectedStartDate < rangeEnd ? rangeEnd : selectedStartDate;
736
+ return isWithinInterval(date, { start: startOfDay(start), end: endOfDay(end) });
737
+ },
738
+ [selectsRange, selectedStartDate, selectedEndDate, selectingRange]
739
+ );
740
+ return /* @__PURE__ */ jsxs2(
741
+ Box,
742
+ {
743
+ ref,
744
+ testID,
745
+ backgroundColor: theme.colors.background.secondary,
746
+ borderRadius: 8,
747
+ padding: 16,
748
+ overflow: "hidden",
749
+ style: {
750
+ boxShadow: "0px 4px 16px 0px rgba(7, 7, 8, 0.1)",
751
+ width: 312
752
+ },
753
+ children: [
754
+ topContent?.({ close: () => {
755
+ } }),
756
+ /* @__PURE__ */ jsx9(
757
+ CalendarHeader,
758
+ {
759
+ monthDate: currentMonth,
760
+ decreaseMonth,
761
+ increaseMonth,
762
+ changeYear,
763
+ changeMonth,
764
+ locale,
765
+ minDate,
766
+ maxDate,
767
+ contextMenuMaxHeight
768
+ }
769
+ ),
770
+ /* @__PURE__ */ jsx9(Box, { flexDirection: "row", justifyContent: "space-between", marginBottom: 8, children: weekDays.map((day, i) => /* @__PURE__ */ jsx9(Box, { width: 40, alignItems: "center", children: /* @__PURE__ */ jsx9(Text, { fontSize: 12, fontWeight: "600", color: theme.colors.content.tertiary, children: day.toUpperCase() }) }, i)) }),
771
+ /* @__PURE__ */ jsx9(Box, { gap: 2, children: weeks.map((week, i) => /* @__PURE__ */ jsx9(Box, { flexDirection: "row", justifyContent: "space-between", children: week.map((day, j) => {
772
+ const isOutsideMonth = !isSameMonth(day, currentMonth);
773
+ const isSelected = !selectsRange && locSelectedDate && isSameDay(day, locSelectedDate) || selectsRange && selectedStartDate && selectedEndDate && isSameDay(day, selectedStartDate) && isSameDay(day, selectedEndDate);
774
+ const isRangeStart = selectsRange && selectedStartDate && isSameDay(day, selectedStartDate);
775
+ const isRangeEnd = selectsRange && selectedEndDate && isSameDay(day, selectedEndDate);
776
+ const inRange = isDateInRange(day);
777
+ const today = isToday(day);
778
+ const disabled = isDateDisabled(day);
779
+ let bgColor = "transparent";
780
+ let textColor = theme.colors.content.primary;
781
+ if (isSelected || isRangeStart || isRangeEnd) {
782
+ bgColor = theme.colors.background.brand.primary;
783
+ textColor = theme.colors.content.on.brand;
784
+ } else if (inRange) {
785
+ bgColor = theme.colors.overlay.brand;
786
+ } else if (today) {
787
+ bgColor = theme.colors.overlay.mono;
788
+ }
789
+ if (isOutsideMonth || disabled) {
790
+ textColor = theme.colors.content.tertiary;
791
+ }
792
+ return /* @__PURE__ */ jsx9(
793
+ Box,
794
+ {
795
+ width: 40,
796
+ height: 32,
797
+ alignItems: "center",
798
+ justifyContent: "center",
799
+ borderRadius: isSelected || isRangeStart || isRangeEnd ? 4 : 0,
800
+ backgroundColor: bgColor,
801
+ cursor: disabled || isOutsideMonth ? "default" : "pointer",
802
+ onPress: () => !disabled && !isOutsideMonth && handleChange(day),
803
+ hoverStyle: !disabled && !isOutsideMonth && !isSelected ? { backgroundColor: theme.colors.overlay.mono } : void 0,
804
+ children: /* @__PURE__ */ jsx9(Text, { color: textColor, fontSize: 14, fontWeight: isSelected || isRangeStart || isRangeEnd ? "600" : "400", children: format2(day, "d") })
805
+ },
806
+ j
807
+ );
808
+ }) }, i)) }),
809
+ bottomContent?.({ close: () => {
810
+ } })
811
+ ]
812
+ }
813
+ );
814
+ }
815
+ );
816
+ Calendar.displayName = "Calendar";
817
+
818
+ // src/DatePicker.tsx
819
+ import { jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
820
+ var DatePicker = forwardRef4(
821
+ ({
822
+ onChange,
823
+ size = "m",
824
+ locale = "enUS",
825
+ selectsRange = false,
826
+ startDate,
827
+ endDate,
828
+ selectedDate,
829
+ placeholder,
830
+ backgroundColor,
831
+ testID,
832
+ ...rest
833
+ }, ref) => {
834
+ const { theme } = useDesignSystem2();
835
+ const [open, setOpen] = useState2(false);
836
+ const [inputValue, setInputValue] = useState2("");
837
+ const containerRef = useRef(null);
838
+ const formatDateForDisplay = (date) => {
839
+ if (!date) return "";
840
+ try {
841
+ return format3(date, "MM/dd/yyyy");
842
+ } catch {
843
+ return "";
844
+ }
845
+ };
846
+ const getDisplayValue = useCallback3(() => {
847
+ if (selectsRange) {
848
+ if (startDate && endDate) {
849
+ return `${formatDateForDisplay(startDate)} - ${formatDateForDisplay(endDate)}`;
850
+ } else if (startDate) {
851
+ return formatDateForDisplay(startDate);
852
+ }
853
+ return "";
854
+ } else {
855
+ return formatDateForDisplay(selectedDate);
856
+ }
857
+ }, [selectsRange, startDate, endDate, selectedDate]);
858
+ useEffect2(() => {
859
+ setInputValue(getDisplayValue());
860
+ }, [getDisplayValue]);
861
+ const handleInputChange = (text) => {
862
+ setInputValue(text);
863
+ };
864
+ const handleDateChange = (date) => {
865
+ if (!selectsRange) {
866
+ onChange?.(date);
867
+ setOpen(false);
868
+ } else {
869
+ const range = date;
870
+ onChange?.(range);
871
+ if (range[0] && range[1]) {
872
+ setOpen(false);
873
+ }
874
+ }
875
+ };
876
+ useEffect2(() => {
877
+ if (isNative) return;
878
+ const handleClickOutside = (event) => {
879
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
880
+ setOpen(false);
881
+ }
882
+ };
883
+ document.addEventListener("mousedown", handleClickOutside);
884
+ return () => document.removeEventListener("mousedown", handleClickOutside);
885
+ }, []);
886
+ const renderCalendar = () => /* @__PURE__ */ jsx10(
887
+ Calendar,
888
+ {
889
+ locale,
890
+ startDate,
891
+ endDate,
892
+ selectedDate,
893
+ onChange: handleDateChange,
894
+ selectsRange,
895
+ ...rest
896
+ }
897
+ );
898
+ return /* @__PURE__ */ jsxs3(Box, { ref: containerRef, position: "relative", width: "100%", children: [
899
+ /* @__PURE__ */ jsx10(
900
+ Input,
901
+ {
902
+ ...rest,
903
+ size,
904
+ placeholder: placeholder || (selectsRange ? "MM/DD/YYYY - MM/DD/YYYY" : "MM/DD/YYYY"),
905
+ value: inputValue,
906
+ onChangeText: handleInputChange,
907
+ onFocus: () => setOpen(true),
908
+ backgroundColor,
909
+ testID
910
+ }
911
+ ),
912
+ open && (isWeb ? /* @__PURE__ */ jsx10(
913
+ Box,
914
+ {
915
+ position: "absolute",
916
+ top: "100%",
917
+ left: 0,
918
+ marginTop: 4,
919
+ zIndex: 1e3,
920
+ children: renderCalendar()
921
+ }
922
+ ) : (
923
+ // Native implementation could use a Modal here
924
+ // For now, we just show it below the input if needed,
925
+ // but usually a bottom sheet or centered modal is better.
926
+ /* @__PURE__ */ jsx10(Box, { marginTop: 4, children: renderCalendar() })
927
+ ))
928
+ ] });
929
+ }
930
+ );
931
+ DatePicker.displayName = "DatePicker";
932
+ export {
933
+ Calendar,
934
+ DatePicker,
935
+ formatDate,
936
+ getMonthInLocale
937
+ };
938
+ //# sourceMappingURL=index.mjs.map