@xaui/native 0.0.11 → 0.0.13

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 (42) hide show
  1. package/README.md +8 -1
  2. package/dist/accordion/index.cjs +7 -2
  3. package/dist/accordion/index.js +7 -2
  4. package/dist/alert/index.cjs +25 -188
  5. package/dist/alert/index.js +1 -2
  6. package/dist/autocomplete/index.cjs +106 -385
  7. package/dist/autocomplete/index.js +1 -3
  8. package/dist/button/index.cjs +126 -4
  9. package/dist/button/index.d.cts +63 -1
  10. package/dist/button/index.d.ts +63 -1
  11. package/dist/button/index.js +117 -3
  12. package/dist/checkbox/index.cjs +5 -1
  13. package/dist/checkbox/index.js +5 -1
  14. package/dist/{chunk-OFYJYQ2M.js → chunk-2T6FKPJW.js} +1 -3
  15. package/dist/chunk-7OFTYKK4.js +1627 -0
  16. package/dist/{chunk-63LRW4QD.js → chunk-MKHBEJLO.js} +8 -1
  17. package/dist/{chunk-W7JJVPK5.js → chunk-NMZUPH3R.js} +7 -12
  18. package/dist/datepicker/index.cjs +1708 -0
  19. package/dist/datepicker/index.d.cts +45 -0
  20. package/dist/datepicker/index.d.ts +45 -0
  21. package/dist/datepicker/index.js +7 -0
  22. package/dist/index.cjs +1794 -454
  23. package/dist/index.d.cts +1 -0
  24. package/dist/index.d.ts +1 -0
  25. package/dist/index.js +7 -5
  26. package/dist/indicator/index.cjs +8 -1
  27. package/dist/indicator/index.js +1 -1
  28. package/dist/menu/index.cjs +371 -0
  29. package/dist/menu/index.d.cts +107 -0
  30. package/dist/menu/index.d.ts +107 -0
  31. package/dist/menu/index.js +304 -0
  32. package/dist/select/index.cjs +40 -16
  33. package/dist/select/index.js +40 -16
  34. package/dist/view/index.cjs +12 -7
  35. package/dist/view/index.js +12 -7
  36. package/package.json +14 -6
  37. package/dist/chunk-RE3CO277.js +0 -444
  38. package/dist/chunk-SIXET7TJ.js +0 -172
  39. package/dist/icon/index.cjs +0 -680
  40. package/dist/icon/index.d.cts +0 -36
  41. package/dist/icon/index.d.ts +0 -36
  42. package/dist/icon/index.js +0 -15
@@ -0,0 +1,1627 @@
1
+ import {
2
+ Portal,
3
+ useXUITheme
4
+ } from "./chunk-NBRASCX4.js";
5
+
6
+ // src/components/datepicker/datepicker.tsx
7
+ import React7, { useCallback as useCallback5, useMemo as useMemo6, useRef as useRef6 } from "react";
8
+ import { Text as Text7, View as View7 } from "react-native";
9
+
10
+ // src/components/datepicker/datepicker.hook.ts
11
+ import { useMemo } from "react";
12
+ import { getSafeThemeColor } from "@xaui/core";
13
+ import { colors } from "@xaui/core/palette";
14
+ var useDatePickerColorScheme = (themeColor) => {
15
+ const theme = useXUITheme();
16
+ const safeThemeColor = getSafeThemeColor(themeColor);
17
+ const colorScheme = theme.colors[safeThemeColor];
18
+ return { theme, colorScheme };
19
+ };
20
+ var useDatePickerSizeStyles = (size) => {
21
+ const theme = useXUITheme();
22
+ return useMemo(() => {
23
+ const sizes = {
24
+ xs: {
25
+ minHeight: 34,
26
+ paddingHorizontal: theme.spacing.sm,
27
+ paddingVertical: theme.spacing.xs,
28
+ fontSize: theme.fontSizes.xs,
29
+ labelSize: theme.fontSizes.xs
30
+ },
31
+ sm: {
32
+ minHeight: 38,
33
+ paddingHorizontal: theme.spacing.md,
34
+ paddingVertical: theme.spacing.xs,
35
+ fontSize: theme.fontSizes.sm,
36
+ labelSize: theme.fontSizes.xs
37
+ },
38
+ md: {
39
+ minHeight: 42,
40
+ paddingHorizontal: theme.spacing.md,
41
+ paddingVertical: theme.spacing.sm,
42
+ fontSize: theme.fontSizes.md,
43
+ labelSize: theme.fontSizes.sm
44
+ },
45
+ lg: {
46
+ minHeight: 50,
47
+ paddingHorizontal: theme.spacing.lg,
48
+ paddingVertical: theme.spacing.md,
49
+ fontSize: theme.fontSizes.lg,
50
+ labelSize: theme.fontSizes.md
51
+ }
52
+ };
53
+ return sizes[size];
54
+ }, [size, theme]);
55
+ };
56
+ var useDatePickerRadiusStyles = (radius) => {
57
+ const theme = useXUITheme();
58
+ return useMemo(() => {
59
+ const radii = {
60
+ none: theme.borderRadius.none,
61
+ sm: theme.borderRadius.sm,
62
+ md: theme.borderRadius.md,
63
+ lg: theme.borderRadius.lg,
64
+ full: theme.borderRadius.full
65
+ };
66
+ return { borderRadius: radii[radius] };
67
+ }, [radius, theme]);
68
+ };
69
+ var useDatePickerVariantStyles = (themeColor, variant, isInvalid) => {
70
+ const { theme, colorScheme } = useDatePickerColorScheme(themeColor);
71
+ return useMemo(() => {
72
+ let borderColor = isInvalid ? theme.colors.danger.main : colorScheme.main;
73
+ if ((variant === "outlined" || variant === "faded") && themeColor === "default") {
74
+ borderColor = colors.gray[300];
75
+ }
76
+ const variantStyles = {
77
+ outlined: {
78
+ backgroundColor: "transparent",
79
+ borderWidth: theme.borderWidth.md,
80
+ borderColor
81
+ },
82
+ flat: {
83
+ backgroundColor: colorScheme.background,
84
+ borderWidth: 0
85
+ },
86
+ light: {
87
+ backgroundColor: "transparent",
88
+ borderWidth: 0
89
+ },
90
+ faded: {
91
+ backgroundColor: `${colorScheme.background}90`,
92
+ borderWidth: theme.borderWidth.md,
93
+ borderColor
94
+ },
95
+ underlined: {
96
+ backgroundColor: "transparent",
97
+ borderBottomWidth: theme.borderWidth.md,
98
+ borderColor
99
+ }
100
+ };
101
+ return variantStyles[variant];
102
+ }, [variant, theme, colorScheme, isInvalid, themeColor]);
103
+ };
104
+ var useDatePickerLabelStyle = (themeColor, isInvalid, labelSize) => {
105
+ const { theme, colorScheme } = useDatePickerColorScheme(themeColor);
106
+ return useMemo(() => {
107
+ let baseColor = theme.colors.foreground;
108
+ if (isInvalid) {
109
+ baseColor = theme.colors.danger.main;
110
+ } else if (themeColor !== "default") {
111
+ baseColor = colorScheme.main;
112
+ }
113
+ return {
114
+ fontSize: labelSize,
115
+ color: baseColor
116
+ };
117
+ }, [isInvalid, labelSize, theme, themeColor, colorScheme]);
118
+ };
119
+ var useDatePickerHelperColor = (isInvalid) => {
120
+ const theme = useXUITheme();
121
+ return useMemo(() => {
122
+ if (isInvalid) {
123
+ return theme.colors.danger.main;
124
+ }
125
+ return colors.gray[600];
126
+ }, [isInvalid, theme]);
127
+ };
128
+
129
+ // src/components/datepicker/datepicker.state.hook.ts
130
+ import { useCallback, useState } from "react";
131
+ var useDatePickerState = ({
132
+ value,
133
+ defaultValue,
134
+ onChange
135
+ }) => {
136
+ const [internalValue, setInternalValue] = useState(
137
+ defaultValue ?? null
138
+ );
139
+ const selectedDate = value !== void 0 ? value : internalValue;
140
+ const updateDate = useCallback(
141
+ (date) => {
142
+ if (value === void 0) {
143
+ setInternalValue(date);
144
+ }
145
+ onChange?.(date);
146
+ },
147
+ [value, onChange]
148
+ );
149
+ return { selectedDate, updateDate };
150
+ };
151
+ var useDatePickerOpenState = ({
152
+ isDisabled,
153
+ onOpenChange,
154
+ onOpen,
155
+ onClose
156
+ }) => {
157
+ const [isOpen, setInternalOpen] = useState(false);
158
+ const setOpen = useCallback(
159
+ (open) => {
160
+ if (isDisabled && open) return;
161
+ setInternalOpen(open);
162
+ onOpenChange?.(open);
163
+ if (open) {
164
+ onOpen?.();
165
+ } else {
166
+ onClose?.();
167
+ }
168
+ },
169
+ [isDisabled, onOpenChange, onOpen, onClose]
170
+ );
171
+ return { isOpen, setOpen };
172
+ };
173
+ var useDatePickerViewState = (initialDate) => {
174
+ const now = /* @__PURE__ */ new Date();
175
+ const [viewDate, setViewDate] = useState(initialDate ?? now);
176
+ const [viewMode, setViewMode] = useState("calendar");
177
+ const goToPreviousMonth = useCallback(() => {
178
+ setViewDate((prev) => new Date(prev.getFullYear(), prev.getMonth() - 1, 1));
179
+ }, []);
180
+ const goToNextMonth = useCallback(() => {
181
+ setViewDate((prev) => new Date(prev.getFullYear(), prev.getMonth() + 1, 1));
182
+ }, []);
183
+ const goToYear = useCallback((year) => {
184
+ setViewDate((prev) => new Date(year, prev.getMonth(), 1));
185
+ setViewMode("month");
186
+ }, []);
187
+ const goToMonth = useCallback((month) => {
188
+ setViewDate((prev) => new Date(prev.getFullYear(), month, 1));
189
+ setViewMode("calendar");
190
+ }, []);
191
+ const goToToday = useCallback(() => {
192
+ setViewDate(/* @__PURE__ */ new Date());
193
+ setViewMode("calendar");
194
+ }, []);
195
+ const toggleYearPicker = useCallback(() => {
196
+ setViewMode((prev) => prev === "year" ? "calendar" : "year");
197
+ }, []);
198
+ const syncViewToDate = useCallback((date) => {
199
+ setViewDate(date);
200
+ }, []);
201
+ return {
202
+ viewDate,
203
+ viewMode,
204
+ goToPreviousMonth,
205
+ goToNextMonth,
206
+ goToYear,
207
+ goToMonth,
208
+ goToToday,
209
+ toggleYearPicker,
210
+ syncViewToDate
211
+ };
212
+ };
213
+
214
+ // src/components/datepicker/datepicker.utils.ts
215
+ var getWeekdayNames = (locale, firstDayOfWeek) => {
216
+ const baseDate = new Date(2024, 0, 1);
217
+ const dayIndex = baseDate.getDay();
218
+ const offset = firstDayOfWeek - dayIndex;
219
+ const days = [];
220
+ for (let i = 0; i < 7; i++) {
221
+ const date = new Date(2024, 0, 1 + offset + i);
222
+ days.push(date.toLocaleDateString(locale, { weekday: "short" }).slice(0, 2));
223
+ }
224
+ return days;
225
+ };
226
+ var getMonthNames = (locale) => {
227
+ const months = [];
228
+ for (let i = 0; i < 12; i++) {
229
+ const date = new Date(2024, i, 1);
230
+ months.push(date.toLocaleDateString(locale, { month: "long" }));
231
+ }
232
+ return months;
233
+ };
234
+ var getMonthName = (month, locale) => {
235
+ const date = new Date(2024, month, 1);
236
+ return date.toLocaleDateString(locale, { month: "long" });
237
+ };
238
+ var formatDate = (date, locale) => {
239
+ return date.toLocaleDateString(locale, {
240
+ year: "numeric",
241
+ month: "short",
242
+ day: "numeric"
243
+ });
244
+ };
245
+ var isSameDay = (a, b) => {
246
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
247
+ };
248
+ var isToday = (date) => {
249
+ return isSameDay(date, /* @__PURE__ */ new Date());
250
+ };
251
+ var isDateInRange = (date, minDate, maxDate) => {
252
+ const normalized = new Date(date.getFullYear(), date.getMonth(), date.getDate());
253
+ if (minDate) {
254
+ const minNormalized = new Date(
255
+ minDate.getFullYear(),
256
+ minDate.getMonth(),
257
+ minDate.getDate()
258
+ );
259
+ if (normalized < minNormalized) return false;
260
+ }
261
+ if (maxDate) {
262
+ const maxNormalized = new Date(
263
+ maxDate.getFullYear(),
264
+ maxDate.getMonth(),
265
+ maxDate.getDate()
266
+ );
267
+ if (normalized > maxNormalized) return false;
268
+ }
269
+ return true;
270
+ };
271
+ var getCalendarDays = (year, month, firstDayOfWeek, minDate, maxDate) => {
272
+ const firstOfMonth = new Date(year, month, 1);
273
+ const lastOfMonth = new Date(year, month + 1, 0);
274
+ const daysInMonth = lastOfMonth.getDate();
275
+ let startDayOfWeek = firstOfMonth.getDay() - firstDayOfWeek;
276
+ if (startDayOfWeek < 0) startDayOfWeek += 7;
277
+ const days = [];
278
+ const prevMonth = new Date(year, month, 0);
279
+ const prevMonthDays = prevMonth.getDate();
280
+ for (let i = startDayOfWeek - 1; i >= 0; i--) {
281
+ const day = prevMonthDays - i;
282
+ const date = new Date(year, month - 1, day);
283
+ days.push({
284
+ date,
285
+ day,
286
+ isCurrentMonth: false,
287
+ isToday: isToday(date),
288
+ isDisabled: !isDateInRange(date, minDate, maxDate)
289
+ });
290
+ }
291
+ for (let day = 1; day <= daysInMonth; day++) {
292
+ const date = new Date(year, month, day);
293
+ days.push({
294
+ date,
295
+ day,
296
+ isCurrentMonth: true,
297
+ isToday: isToday(date),
298
+ isDisabled: !isDateInRange(date, minDate, maxDate)
299
+ });
300
+ }
301
+ const remainingSlots = 42 - days.length;
302
+ for (let day = 1; day <= remainingSlots; day++) {
303
+ const date = new Date(year, month + 1, day);
304
+ days.push({
305
+ date,
306
+ day,
307
+ isCurrentMonth: false,
308
+ isToday: isToday(date),
309
+ isDisabled: !isDateInRange(date, minDate, maxDate)
310
+ });
311
+ }
312
+ return days;
313
+ };
314
+ var getYearRange = (minDate, maxDate) => {
315
+ const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
316
+ const startYear = minDate ? minDate.getFullYear() : currentYear - 50;
317
+ const endYear = maxDate ? maxDate.getFullYear() : currentYear + 50;
318
+ const years = [];
319
+ for (let year = startYear; year <= endYear; year++) {
320
+ years.push(year);
321
+ }
322
+ return years;
323
+ };
324
+ var LOCALE_LABELS = {
325
+ fr: { selectDate: "Choisir une date", today: "Aujourd'hui", confirm: "OK" },
326
+ de: { selectDate: "Datum ausw\xE4hlen", today: "Heute", confirm: "OK" },
327
+ es: { selectDate: "Seleccionar fecha", today: "Hoy", confirm: "OK" },
328
+ it: { selectDate: "Seleziona data", today: "Oggi", confirm: "OK" },
329
+ pt: { selectDate: "Selecionar data", today: "Hoje", confirm: "OK" },
330
+ nl: { selectDate: "Datum selecteren", today: "Vandaag", confirm: "OK" },
331
+ pl: { selectDate: "Wybierz dat\u0119", today: "Dzisiaj", confirm: "OK" },
332
+ ru: { selectDate: "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0434\u0430\u0442\u0443", today: "\u0421\u0435\u0433\u043E\u0434\u043D\u044F", confirm: "OK" },
333
+ ja: { selectDate: "\u65E5\u4ED8\u3092\u9078\u629E", today: "\u4ECA\u65E5", confirm: "OK" },
334
+ ko: { selectDate: "\uB0A0\uC9DC \uC120\uD0DD", today: "\uC624\uB298", confirm: "\uD655\uC778" },
335
+ zh: { selectDate: "\u9009\u62E9\u65E5\u671F", today: "\u4ECA\u5929", confirm: "\u786E\u5B9A" },
336
+ ar: { selectDate: "\u0627\u062E\u062A\u0631 \u0627\u0644\u062A\u0627\u0631\u064A\u062E", today: "\u0627\u0644\u064A\u0648\u0645", confirm: "\u0645\u0648\u0627\u0641\u0642" },
337
+ tr: { selectDate: "Tarih se\xE7in", today: "Bug\xFCn", confirm: "Tamam" }
338
+ };
339
+ var DEFAULT_LABELS = {
340
+ selectDate: "Select date",
341
+ today: "Today",
342
+ confirm: "OK"
343
+ };
344
+ var getDatePickerLabels = (locale) => {
345
+ const baseLocale = locale.split("-")[0].toLowerCase();
346
+ return LOCALE_LABELS[baseLocale] ?? DEFAULT_LABELS;
347
+ };
348
+ var getFirstDayOfWeek = (locale) => {
349
+ const mondayLocales = [
350
+ "fr",
351
+ "de",
352
+ "es",
353
+ "it",
354
+ "pt",
355
+ "nl",
356
+ "pl",
357
+ "ru",
358
+ "sv",
359
+ "da",
360
+ "fi",
361
+ "nb",
362
+ "nn",
363
+ "cs",
364
+ "sk",
365
+ "hu",
366
+ "ro",
367
+ "bg",
368
+ "hr",
369
+ "sl",
370
+ "uk",
371
+ "tr",
372
+ "el",
373
+ "et",
374
+ "lt",
375
+ "lv"
376
+ ];
377
+ const baseLocale = locale.split("-")[0].toLowerCase();
378
+ return mondayLocales.includes(baseLocale) ? 1 : 0;
379
+ };
380
+
381
+ // src/components/datepicker/datepicker.style.ts
382
+ import { StyleSheet } from "react-native";
383
+ var styles = StyleSheet.create({
384
+ container: {
385
+ gap: 6,
386
+ position: "relative"
387
+ },
388
+ fullWidth: {
389
+ flexShrink: 1,
390
+ flexBasis: "auto",
391
+ width: "100%"
392
+ },
393
+ minWidth: {
394
+ minWidth: 170
395
+ },
396
+ label: {
397
+ fontWeight: "500"
398
+ },
399
+ trigger: {
400
+ flexDirection: "row",
401
+ alignItems: "center",
402
+ justifyContent: "space-between",
403
+ gap: 8
404
+ },
405
+ triggerContent: {
406
+ flexDirection: "row",
407
+ alignItems: "center",
408
+ flex: 1,
409
+ gap: 8
410
+ },
411
+ triggerText: {
412
+ flex: 1
413
+ },
414
+ clearButton: {
415
+ padding: 2,
416
+ paddingLeft: 4,
417
+ marginRight: -4
418
+ },
419
+ helperText: {
420
+ fontSize: 12
421
+ },
422
+ disabled: {
423
+ opacity: 0.5
424
+ },
425
+ outsideLeftRow: {
426
+ flexDirection: "row",
427
+ alignItems: "center",
428
+ gap: 12
429
+ }
430
+ });
431
+
432
+ // src/components/dialogs/datepicker-dialog/datepicker-dialog.tsx
433
+ import React5, { useCallback as useCallback4, useEffect as useEffect5, useRef as useRef5 } from "react";
434
+ import {
435
+ Animated as Animated5,
436
+ BackHandler,
437
+ Pressable as Pressable5,
438
+ Text as Text5,
439
+ View as View5,
440
+ useWindowDimensions
441
+ } from "react-native";
442
+ import { GestureHandlerRootView } from "react-native-gesture-handler";
443
+
444
+ // src/components/dialogs/datepicker-dialog/datepicker-dialog.animation.ts
445
+ import { useCallback as useCallback2, useEffect, useRef, useState as useState2 } from "react";
446
+ import { Animated, Easing } from "react-native";
447
+ var useDatePickerDialogAnimation = ({
448
+ visible,
449
+ fadeAnim,
450
+ slideAnim,
451
+ scaleAnim,
452
+ onCloseComplete
453
+ }) => {
454
+ const [shouldRender, setShouldRender] = useState2(false);
455
+ const isClosingRef = useRef(false);
456
+ useEffect(() => {
457
+ if (visible) {
458
+ setShouldRender(true);
459
+ isClosingRef.current = false;
460
+ Animated.parallel([
461
+ Animated.timing(fadeAnim, {
462
+ toValue: 1,
463
+ duration: 220,
464
+ useNativeDriver: true
465
+ }),
466
+ Animated.spring(slideAnim, {
467
+ toValue: 1,
468
+ useNativeDriver: true,
469
+ damping: 20,
470
+ stiffness: 300,
471
+ mass: 0.8
472
+ }),
473
+ Animated.spring(scaleAnim, {
474
+ toValue: 1,
475
+ useNativeDriver: true,
476
+ damping: 18,
477
+ stiffness: 280,
478
+ mass: 0.8
479
+ })
480
+ ]).start();
481
+ return;
482
+ }
483
+ if (!shouldRender || isClosingRef.current) return;
484
+ isClosingRef.current = true;
485
+ Animated.parallel([
486
+ Animated.timing(fadeAnim, {
487
+ toValue: 0,
488
+ duration: 180,
489
+ easing: Easing.out(Easing.ease),
490
+ useNativeDriver: true
491
+ }),
492
+ Animated.timing(slideAnim, {
493
+ toValue: 0,
494
+ duration: 180,
495
+ easing: Easing.out(Easing.ease),
496
+ useNativeDriver: true
497
+ }),
498
+ Animated.timing(scaleAnim, {
499
+ toValue: 0,
500
+ duration: 180,
501
+ easing: Easing.out(Easing.ease),
502
+ useNativeDriver: true
503
+ })
504
+ ]).start(() => {
505
+ setShouldRender(false);
506
+ isClosingRef.current = false;
507
+ onCloseComplete();
508
+ });
509
+ }, [visible, fadeAnim, slideAnim, scaleAnim, shouldRender, onCloseComplete]);
510
+ return { shouldRender };
511
+ };
512
+ var useViewTransitionAnimation = ({
513
+ fadeAnim
514
+ }) => {
515
+ const animate = useCallback2(() => {
516
+ fadeAnim.setValue(0);
517
+ Animated.timing(fadeAnim, {
518
+ toValue: 1,
519
+ duration: 200,
520
+ useNativeDriver: true
521
+ }).start();
522
+ }, [fadeAnim]);
523
+ return { animate };
524
+ };
525
+ var useMonthSlideAnimation = ({
526
+ slideAnim,
527
+ fadeAnim
528
+ }) => {
529
+ const animate = useCallback2(
530
+ (direction) => {
531
+ const startX = direction === "right" ? 60 : -60;
532
+ slideAnim.setValue(startX);
533
+ fadeAnim.setValue(0);
534
+ Animated.parallel([
535
+ Animated.spring(slideAnim, {
536
+ toValue: 0,
537
+ useNativeDriver: true,
538
+ damping: 22,
539
+ stiffness: 280,
540
+ mass: 0.7
541
+ }),
542
+ Animated.timing(fadeAnim, {
543
+ toValue: 1,
544
+ duration: 180,
545
+ useNativeDriver: true
546
+ })
547
+ ]).start();
548
+ },
549
+ [slideAnim, fadeAnim]
550
+ );
551
+ return { animate };
552
+ };
553
+
554
+ // src/components/dialogs/datepicker-dialog/datepicker-dialog-calendar.tsx
555
+ import React, { useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2 } from "react";
556
+ import { Animated as Animated2, Pressable, Text, View } from "react-native";
557
+ import {
558
+ PanGestureHandler,
559
+ State
560
+ } from "react-native-gesture-handler";
561
+
562
+ // src/components/dialogs/datepicker-dialog/datepicker-dialog.style.ts
563
+ import { StyleSheet as StyleSheet2 } from "react-native";
564
+ var styles2 = StyleSheet2.create({
565
+ backdrop: {
566
+ ...StyleSheet2.absoluteFillObject,
567
+ backgroundColor: "rgba(0, 0, 0, 0.5)"
568
+ },
569
+ dialogContainer: {
570
+ flex: 1,
571
+ justifyContent: "center",
572
+ alignItems: "center",
573
+ zIndex: 1,
574
+ paddingHorizontal: 24
575
+ },
576
+ container: {
577
+ width: "100%",
578
+ maxWidth: 360,
579
+ borderRadius: 16,
580
+ overflow: "hidden",
581
+ elevation: 6,
582
+ shadowColor: "#000",
583
+ shadowOffset: { width: 0, height: 2 },
584
+ shadowOpacity: 0.25,
585
+ shadowRadius: 8
586
+ },
587
+ header: {
588
+ paddingHorizontal: 24,
589
+ paddingTop: 16,
590
+ paddingBottom: 12
591
+ },
592
+ headerLabel: {
593
+ fontSize: 12,
594
+ fontWeight: "500",
595
+ textTransform: "uppercase",
596
+ letterSpacing: 0.5,
597
+ marginBottom: 8
598
+ },
599
+ headerDateRow: {
600
+ flexDirection: "row",
601
+ alignItems: "center",
602
+ justifyContent: "space-between"
603
+ },
604
+ headerDate: {
605
+ fontSize: 24,
606
+ fontWeight: "400"
607
+ },
608
+ navigationRow: {
609
+ flexDirection: "row",
610
+ alignItems: "center",
611
+ justifyContent: "space-between",
612
+ paddingHorizontal: 12,
613
+ paddingVertical: 8
614
+ },
615
+ monthYearButton: {
616
+ flexDirection: "row",
617
+ alignItems: "center",
618
+ gap: 4,
619
+ paddingVertical: 8,
620
+ paddingHorizontal: 12,
621
+ borderRadius: 20
622
+ },
623
+ monthYearText: {
624
+ fontSize: 14,
625
+ fontWeight: "600"
626
+ },
627
+ navButtons: {
628
+ flexDirection: "row",
629
+ alignItems: "center",
630
+ gap: 4
631
+ },
632
+ navButton: {
633
+ padding: 8,
634
+ borderRadius: 20
635
+ },
636
+ calendarGrid: {
637
+ paddingHorizontal: 12
638
+ },
639
+ weekdayRow: {
640
+ flexDirection: "row",
641
+ justifyContent: "space-around",
642
+ marginBottom: 4
643
+ },
644
+ weekdayCell: {
645
+ width: 44,
646
+ height: 32,
647
+ justifyContent: "center",
648
+ alignItems: "center"
649
+ },
650
+ weekdayText: {
651
+ fontSize: 12,
652
+ fontWeight: "500"
653
+ },
654
+ dayRow: {
655
+ flexDirection: "row",
656
+ justifyContent: "space-around"
657
+ },
658
+ dayCell: {
659
+ width: 44,
660
+ height: 44,
661
+ justifyContent: "center",
662
+ alignItems: "center",
663
+ borderRadius: 22
664
+ },
665
+ dayText: {
666
+ fontSize: 14
667
+ },
668
+ todayCell: {
669
+ borderWidth: 1
670
+ },
671
+ selectedCell: {
672
+ borderWidth: 0
673
+ },
674
+ selectedCellInner: {
675
+ width: 44,
676
+ height: 44,
677
+ justifyContent: "center",
678
+ alignItems: "center",
679
+ borderRadius: 22
680
+ },
681
+ disabledText: {
682
+ opacity: 0.3
683
+ },
684
+ otherMonthText: {
685
+ opacity: 0.4
686
+ },
687
+ footer: {
688
+ flexDirection: "row",
689
+ justifyContent: "flex-end",
690
+ alignItems: "center",
691
+ gap: 8,
692
+ paddingHorizontal: 12,
693
+ paddingVertical: 12
694
+ },
695
+ footerButton: {
696
+ paddingVertical: 10,
697
+ paddingHorizontal: 16,
698
+ borderRadius: 20
699
+ },
700
+ footerButtonText: {
701
+ fontSize: 14,
702
+ fontWeight: "600"
703
+ },
704
+ yearPickerContainer: {
705
+ paddingHorizontal: 12,
706
+ height: 280
707
+ },
708
+ yearGrid: {
709
+ flexDirection: "row",
710
+ flexWrap: "wrap",
711
+ justifyContent: "center",
712
+ gap: 4
713
+ },
714
+ yearCell: {
715
+ width: 76,
716
+ height: 44,
717
+ justifyContent: "center",
718
+ alignItems: "center",
719
+ borderRadius: 22,
720
+ margin: 2
721
+ },
722
+ yearCellInner: {
723
+ width: 76,
724
+ height: 44,
725
+ justifyContent: "center",
726
+ alignItems: "center",
727
+ borderRadius: 22
728
+ },
729
+ yearText: {
730
+ fontSize: 14
731
+ },
732
+ monthPickerContainer: {
733
+ paddingHorizontal: 24,
734
+ paddingVertical: 8
735
+ },
736
+ monthGrid: {
737
+ flexDirection: "row",
738
+ flexWrap: "wrap",
739
+ justifyContent: "center",
740
+ gap: 8
741
+ },
742
+ monthCell: {
743
+ width: 90,
744
+ height: 44,
745
+ justifyContent: "center",
746
+ alignItems: "center",
747
+ borderRadius: 22
748
+ },
749
+ monthCellInner: {
750
+ width: 90,
751
+ height: 44,
752
+ justifyContent: "center",
753
+ alignItems: "center",
754
+ borderRadius: 22
755
+ },
756
+ monthText: {
757
+ fontSize: 14
758
+ }
759
+ });
760
+
761
+ // src/components/dialogs/datepicker-dialog/datepicker-dialog-calendar.tsx
762
+ var AnimatedDayCell = ({
763
+ isSelected,
764
+ isToday: isToday2,
765
+ isCurrentMonth,
766
+ isDisabled,
767
+ day,
768
+ date,
769
+ locale,
770
+ themeColor,
771
+ onSelectDay
772
+ }) => {
773
+ const theme = useXUITheme();
774
+ const colorScheme = theme.colors[themeColor] ?? theme.colors.primary;
775
+ const isDefault = themeColor === "default";
776
+ const accentColor = isDefault ? theme.colors.foreground : colorScheme.main;
777
+ const accentFg = isDefault ? theme.colors.background : colorScheme.foreground;
778
+ const scaleAnim = useRef2(new Animated2.Value(isSelected ? 1 : 0)).current;
779
+ useEffect2(() => {
780
+ if (isSelected) {
781
+ scaleAnim.setValue(0.92);
782
+ Animated2.spring(scaleAnim, {
783
+ toValue: 1,
784
+ useNativeDriver: true,
785
+ damping: 20,
786
+ stiffness: 300,
787
+ mass: 0.6
788
+ }).start();
789
+ } else {
790
+ scaleAnim.setValue(0);
791
+ }
792
+ }, [isSelected, scaleAnim]);
793
+ const animatedStyle = isSelected ? { transform: [{ scale: scaleAnim }] } : void 0;
794
+ return /* @__PURE__ */ React.createElement(
795
+ Pressable,
796
+ {
797
+ style: [
798
+ styles2.dayCell,
799
+ isToday2 && !isSelected && {
800
+ ...styles2.todayCell,
801
+ borderColor: accentColor
802
+ }
803
+ ],
804
+ onPress: () => {
805
+ if (!isDisabled) {
806
+ onSelectDay(date);
807
+ }
808
+ },
809
+ disabled: isDisabled,
810
+ accessibilityLabel: date.toLocaleDateString(locale),
811
+ accessibilityRole: "button",
812
+ accessibilityState: {
813
+ selected: isSelected,
814
+ disabled: isDisabled
815
+ }
816
+ },
817
+ isSelected ? /* @__PURE__ */ React.createElement(
818
+ Animated2.View,
819
+ {
820
+ style: [
821
+ styles2.selectedCellInner,
822
+ { backgroundColor: accentColor },
823
+ animatedStyle
824
+ ]
825
+ },
826
+ /* @__PURE__ */ React.createElement(Text, { style: [styles2.dayText, { color: accentFg }] }, day)
827
+ ) : /* @__PURE__ */ React.createElement(
828
+ Text,
829
+ {
830
+ style: [
831
+ styles2.dayText,
832
+ { color: theme.colors.foreground },
833
+ !isCurrentMonth && styles2.otherMonthText,
834
+ isDisabled && styles2.disabledText,
835
+ isToday2 && {
836
+ color: accentColor,
837
+ fontWeight: "600"
838
+ }
839
+ ]
840
+ },
841
+ day
842
+ )
843
+ );
844
+ };
845
+ var DatePickerDialogCalendar = ({
846
+ viewDate,
847
+ selectedDate,
848
+ locale,
849
+ firstDayOfWeek,
850
+ themeColor,
851
+ minDate,
852
+ maxDate,
853
+ onSelectDay,
854
+ onPreviousMonth,
855
+ onNextMonth
856
+ }) => {
857
+ const theme = useXUITheme();
858
+ const swipeHandledRef = useRef2(false);
859
+ const weekdays = useMemo2(
860
+ () => getWeekdayNames(locale, firstDayOfWeek),
861
+ [locale, firstDayOfWeek]
862
+ );
863
+ const days = useMemo2(
864
+ () => getCalendarDays(
865
+ viewDate.getFullYear(),
866
+ viewDate.getMonth(),
867
+ firstDayOfWeek,
868
+ minDate,
869
+ maxDate
870
+ ),
871
+ [viewDate, firstDayOfWeek, minDate, maxDate]
872
+ );
873
+ const weeks = useMemo2(() => {
874
+ const result = [];
875
+ for (let i = 0; i < days.length; i += 7) {
876
+ result.push(days.slice(i, i + 7));
877
+ }
878
+ return result;
879
+ }, [days]);
880
+ const onSwipeEnd = (event) => {
881
+ const { state, translationX, velocityX } = event.nativeEvent;
882
+ if (state !== State.END || swipeHandledRef.current) return;
883
+ const shouldSwipe = Math.abs(translationX) > 40 || Math.abs(velocityX) > 600;
884
+ if (!shouldSwipe) return;
885
+ swipeHandledRef.current = true;
886
+ if (translationX < 0) {
887
+ onNextMonth();
888
+ } else {
889
+ onPreviousMonth();
890
+ }
891
+ };
892
+ const onSwipeStateChange = (event) => {
893
+ if (event.nativeEvent.state === State.BEGAN) {
894
+ swipeHandledRef.current = false;
895
+ }
896
+ onSwipeEnd(event);
897
+ };
898
+ return /* @__PURE__ */ React.createElement(
899
+ PanGestureHandler,
900
+ {
901
+ activeOffsetX: [-12, 12],
902
+ failOffsetY: [-12, 12],
903
+ onHandlerStateChange: onSwipeStateChange
904
+ },
905
+ /* @__PURE__ */ React.createElement(View, { style: styles2.calendarGrid }, /* @__PURE__ */ React.createElement(View, { style: styles2.weekdayRow }, weekdays.map((day, index) => /* @__PURE__ */ React.createElement(View, { key: index, style: styles2.weekdayCell }, /* @__PURE__ */ React.createElement(
906
+ Text,
907
+ {
908
+ style: [
909
+ styles2.weekdayText,
910
+ { color: theme.colors.foreground, opacity: 0.6 }
911
+ ]
912
+ },
913
+ day
914
+ )))), weeks.map((week, weekIndex) => /* @__PURE__ */ React.createElement(View, { key: weekIndex, style: styles2.dayRow }, week.map((dayInfo, dayIndex) => /* @__PURE__ */ React.createElement(
915
+ AnimatedDayCell,
916
+ {
917
+ key: dayIndex,
918
+ isSelected: !!(selectedDate && isSameDay(dayInfo.date, selectedDate)),
919
+ isToday: dayInfo.isToday,
920
+ isCurrentMonth: dayInfo.isCurrentMonth,
921
+ isDisabled: dayInfo.isDisabled,
922
+ day: dayInfo.day,
923
+ date: dayInfo.date,
924
+ locale,
925
+ themeColor,
926
+ onSelectDay
927
+ }
928
+ )))))
929
+ );
930
+ };
931
+
932
+ // src/components/dialogs/datepicker-dialog/datepicker-dialog-header.tsx
933
+ import React2, { useMemo as useMemo3 } from "react";
934
+ import { Pressable as Pressable2, Text as Text2, View as View2 } from "react-native";
935
+ import { ChevronDownIcon } from "@xaui/icons/chevron-down";
936
+ import { ChevronLeftIcon } from "@xaui/icons/chevron-left";
937
+ import { ChevronRightIcon } from "@xaui/icons/chevron-right";
938
+ import { CloseIcon } from "@xaui/icons/close";
939
+ var DatePickerDialogHeader = ({
940
+ viewDate,
941
+ selectedDate,
942
+ locale,
943
+ themeColor,
944
+ selectDateLabel,
945
+ onClearValue,
946
+ onPreviousMonth,
947
+ onNextMonth,
948
+ onToggleYearPicker
949
+ }) => {
950
+ const theme = useXUITheme();
951
+ const colorScheme = theme.colors[themeColor] ?? theme.colors.primary;
952
+ const dateText = useMemo3(() => {
953
+ if (!selectedDate) return "---";
954
+ return formatDate(selectedDate, locale);
955
+ }, [selectedDate, locale]);
956
+ const monthYearLabel = useMemo3(() => {
957
+ const month = getMonthName(viewDate.getMonth(), locale);
958
+ return `${month} ${viewDate.getFullYear()}`;
959
+ }, [viewDate, locale]);
960
+ return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(View2, { style: [styles2.header, { backgroundColor: colorScheme.main }] }, /* @__PURE__ */ React2.createElement(Text2, { style: [styles2.headerLabel, { color: colorScheme.foreground }] }, selectDateLabel), /* @__PURE__ */ React2.createElement(View2, { style: styles2.headerDateRow }, /* @__PURE__ */ React2.createElement(Text2, { style: [styles2.headerDate, { color: colorScheme.foreground }] }, dateText), selectedDate ? /* @__PURE__ */ React2.createElement(
961
+ Pressable2,
962
+ {
963
+ onPress: onClearValue,
964
+ hitSlop: { top: 8, right: 8, bottom: 8, left: 8 },
965
+ accessibilityLabel: "Clear date",
966
+ accessibilityRole: "button"
967
+ },
968
+ /* @__PURE__ */ React2.createElement(CloseIcon, { size: 20, color: colorScheme.foreground })
969
+ ) : null)), /* @__PURE__ */ React2.createElement(View2, { style: styles2.navigationRow }, /* @__PURE__ */ React2.createElement(
970
+ Pressable2,
971
+ {
972
+ style: styles2.monthYearButton,
973
+ onPress: onToggleYearPicker,
974
+ accessibilityLabel: `${monthYearLabel}, tap to change`,
975
+ accessibilityRole: "button"
976
+ },
977
+ /* @__PURE__ */ React2.createElement(Text2, { style: [styles2.monthYearText, { color: theme.colors.foreground }] }, monthYearLabel),
978
+ /* @__PURE__ */ React2.createElement(ChevronDownIcon, { size: 18, color: theme.colors.foreground })
979
+ ), /* @__PURE__ */ React2.createElement(View2, { style: styles2.navButtons }, /* @__PURE__ */ React2.createElement(
980
+ Pressable2,
981
+ {
982
+ style: styles2.navButton,
983
+ onPress: onPreviousMonth,
984
+ accessibilityLabel: "Previous month",
985
+ accessibilityRole: "button"
986
+ },
987
+ /* @__PURE__ */ React2.createElement(ChevronLeftIcon, { size: 20, color: theme.colors.foreground })
988
+ ), /* @__PURE__ */ React2.createElement(
989
+ Pressable2,
990
+ {
991
+ style: styles2.navButton,
992
+ onPress: onNextMonth,
993
+ accessibilityLabel: "Next month",
994
+ accessibilityRole: "button"
995
+ },
996
+ /* @__PURE__ */ React2.createElement(ChevronRightIcon, { size: 20, color: theme.colors.foreground })
997
+ ))));
998
+ };
999
+
1000
+ // src/components/dialogs/datepicker-dialog/datepicker-dialog-month-picker.tsx
1001
+ import React3, { useEffect as useEffect3, useMemo as useMemo4, useRef as useRef3 } from "react";
1002
+ import { Animated as Animated3, Easing as Easing2, Pressable as Pressable3, Text as Text3, View as View3 } from "react-native";
1003
+ var DatePickerDialogMonthPicker = ({ viewDate, locale, themeColor, onSelectMonth }) => {
1004
+ const theme = useXUITheme();
1005
+ const colorScheme = theme.colors[themeColor] ?? theme.colors.primary;
1006
+ const isDefault = themeColor === "default";
1007
+ const accentColor = isDefault ? theme.colors.foreground : colorScheme.main;
1008
+ const accentFg = isDefault ? theme.colors.background : colorScheme.foreground;
1009
+ const months = useMemo4(() => getMonthNames(locale), [locale]);
1010
+ const currentMonth = viewDate.getMonth();
1011
+ const groupAnim = useRef3(new Animated3.Value(0)).current;
1012
+ useEffect3(() => {
1013
+ groupAnim.setValue(0);
1014
+ Animated3.timing(groupAnim, {
1015
+ toValue: 1,
1016
+ duration: 220,
1017
+ easing: Easing2.out(Easing2.cubic),
1018
+ useNativeDriver: true
1019
+ }).start();
1020
+ }, [groupAnim]);
1021
+ return /* @__PURE__ */ React3.createElement(View3, { style: styles2.monthPickerContainer }, /* @__PURE__ */ React3.createElement(
1022
+ Animated3.View,
1023
+ {
1024
+ style: {
1025
+ opacity: groupAnim,
1026
+ transform: [
1027
+ {
1028
+ translateY: groupAnim.interpolate({
1029
+ inputRange: [0, 1],
1030
+ outputRange: [12, 0]
1031
+ })
1032
+ }
1033
+ ]
1034
+ }
1035
+ },
1036
+ /* @__PURE__ */ React3.createElement(View3, { style: styles2.monthGrid }, months.map((name, index) => {
1037
+ const isCurrentMonth = index === currentMonth;
1038
+ return /* @__PURE__ */ React3.createElement(
1039
+ Pressable3,
1040
+ {
1041
+ key: index,
1042
+ style: [
1043
+ styles2.monthCell,
1044
+ isCurrentMonth && { backgroundColor: accentColor }
1045
+ ],
1046
+ onPress: () => onSelectMonth(index),
1047
+ accessibilityLabel: name,
1048
+ accessibilityRole: "button",
1049
+ accessibilityState: { selected: isCurrentMonth }
1050
+ },
1051
+ /* @__PURE__ */ React3.createElement(
1052
+ Text3,
1053
+ {
1054
+ style: [
1055
+ styles2.monthText,
1056
+ { color: theme.colors.foreground },
1057
+ isCurrentMonth && {
1058
+ color: accentFg,
1059
+ fontWeight: "600"
1060
+ }
1061
+ ]
1062
+ },
1063
+ name
1064
+ )
1065
+ );
1066
+ }))
1067
+ ));
1068
+ };
1069
+
1070
+ // src/components/dialogs/datepicker-dialog/datepicker-dialog-year-picker.tsx
1071
+ import React4, { useCallback as useCallback3, useEffect as useEffect4, useMemo as useMemo5, useRef as useRef4 } from "react";
1072
+ import { Animated as Animated4, Easing as Easing3, FlatList, Pressable as Pressable4, Text as Text4, View as View4 } from "react-native";
1073
+ var ITEM_HEIGHT = 48;
1074
+ var NUM_COLUMNS = 4;
1075
+ var DatePickerDialogYearPicker = ({ viewDate, themeColor, minDate, maxDate, onSelectYear }) => {
1076
+ const listRef = useRef4(null);
1077
+ const groupAnim = useRef4(new Animated4.Value(0)).current;
1078
+ const theme = useXUITheme();
1079
+ const colorScheme = theme.colors[themeColor] ?? theme.colors.primary;
1080
+ const isDefault = themeColor === "default";
1081
+ const accentColor = isDefault ? theme.colors.foreground : colorScheme.main;
1082
+ const accentFg = isDefault ? theme.colors.background : colorScheme.foreground;
1083
+ const years = useMemo5(() => getYearRange(minDate, maxDate), [minDate, maxDate]);
1084
+ const currentYear = viewDate.getFullYear();
1085
+ const initialIndex = useMemo5(() => {
1086
+ const index = years.indexOf(currentYear);
1087
+ const rowIndex = Math.floor(index / NUM_COLUMNS);
1088
+ return Math.max(0, rowIndex);
1089
+ }, [years, currentYear]);
1090
+ useEffect4(() => {
1091
+ groupAnim.setValue(0);
1092
+ Animated4.timing(groupAnim, {
1093
+ toValue: 1,
1094
+ duration: 220,
1095
+ easing: Easing3.out(Easing3.cubic),
1096
+ useNativeDriver: true
1097
+ }).start();
1098
+ }, [groupAnim]);
1099
+ const getItemLayout = useCallback3(
1100
+ (_, index) => ({
1101
+ length: ITEM_HEIGHT,
1102
+ offset: ITEM_HEIGHT * index,
1103
+ index
1104
+ }),
1105
+ []
1106
+ );
1107
+ const renderYear = useCallback3(
1108
+ ({ item }) => {
1109
+ const isCurrentYear = item === currentYear;
1110
+ return /* @__PURE__ */ React4.createElement(
1111
+ Pressable4,
1112
+ {
1113
+ style: [
1114
+ styles2.yearCell,
1115
+ isCurrentYear && { backgroundColor: accentColor }
1116
+ ],
1117
+ onPress: () => onSelectYear(item),
1118
+ accessibilityLabel: `${item}`,
1119
+ accessibilityRole: "button",
1120
+ accessibilityState: { selected: isCurrentYear }
1121
+ },
1122
+ /* @__PURE__ */ React4.createElement(
1123
+ Text4,
1124
+ {
1125
+ style: [
1126
+ styles2.yearText,
1127
+ { color: theme.colors.foreground },
1128
+ isCurrentYear && {
1129
+ color: accentFg,
1130
+ fontWeight: "600"
1131
+ }
1132
+ ]
1133
+ },
1134
+ item
1135
+ )
1136
+ );
1137
+ },
1138
+ [currentYear, onSelectYear, accentColor, accentFg, theme.colors.foreground]
1139
+ );
1140
+ return /* @__PURE__ */ React4.createElement(View4, { style: styles2.yearPickerContainer }, /* @__PURE__ */ React4.createElement(
1141
+ Animated4.View,
1142
+ {
1143
+ style: {
1144
+ opacity: groupAnim,
1145
+ transform: [
1146
+ {
1147
+ translateY: groupAnim.interpolate({
1148
+ inputRange: [0, 1],
1149
+ outputRange: [12, 0]
1150
+ })
1151
+ }
1152
+ ]
1153
+ }
1154
+ },
1155
+ /* @__PURE__ */ React4.createElement(
1156
+ FlatList,
1157
+ {
1158
+ ref: listRef,
1159
+ data: years,
1160
+ renderItem: renderYear,
1161
+ keyExtractor: (item) => String(item),
1162
+ numColumns: NUM_COLUMNS,
1163
+ getItemLayout,
1164
+ initialScrollIndex: initialIndex,
1165
+ showsVerticalScrollIndicator: false,
1166
+ columnWrapperStyle: { justifyContent: "center" }
1167
+ }
1168
+ )
1169
+ ));
1170
+ };
1171
+
1172
+ // src/components/dialogs/datepicker-dialog/datepicker-dialog.tsx
1173
+ var DatePickerDialog = ({
1174
+ visible,
1175
+ selectedDate,
1176
+ locale,
1177
+ firstDayOfWeek,
1178
+ themeColor = "primary",
1179
+ minDate,
1180
+ maxDate,
1181
+ style,
1182
+ todayLabel,
1183
+ confirmLabel,
1184
+ onDateSelect,
1185
+ onClearValue,
1186
+ onClose
1187
+ }) => {
1188
+ const theme = useXUITheme();
1189
+ const { width: screenWidth, height: screenHeight } = useWindowDimensions();
1190
+ const fadeAnim = useRef5(new Animated5.Value(0)).current;
1191
+ const slideAnim = useRef5(new Animated5.Value(0)).current;
1192
+ const scaleAnim = useRef5(new Animated5.Value(0)).current;
1193
+ const viewFadeAnim = useRef5(new Animated5.Value(1)).current;
1194
+ const monthSlideXAnim = useRef5(new Animated5.Value(0)).current;
1195
+ const monthFadeAnim = useRef5(new Animated5.Value(1)).current;
1196
+ const colorScheme = theme.colors[themeColor] ?? theme.colors.primary;
1197
+ const isDefault = themeColor === "default";
1198
+ const accentColor = isDefault ? theme.colors.foreground : colorScheme.main;
1199
+ const labels = getDatePickerLabels(locale);
1200
+ const resolvedTodayLabel = todayLabel ?? labels.today;
1201
+ const resolvedConfirmLabel = confirmLabel ?? labels.confirm;
1202
+ const {
1203
+ viewDate,
1204
+ viewMode,
1205
+ goToPreviousMonth,
1206
+ goToNextMonth,
1207
+ goToYear,
1208
+ goToMonth,
1209
+ goToToday,
1210
+ toggleYearPicker,
1211
+ syncViewToDate
1212
+ } = useDatePickerViewState(selectedDate);
1213
+ const onCloseComplete = useCallback4(() => {
1214
+ fadeAnim.setValue(0);
1215
+ slideAnim.setValue(0);
1216
+ scaleAnim.setValue(0);
1217
+ viewFadeAnim.setValue(1);
1218
+ monthSlideXAnim.setValue(0);
1219
+ monthFadeAnim.setValue(1);
1220
+ }, [fadeAnim, slideAnim, scaleAnim, viewFadeAnim, monthSlideXAnim, monthFadeAnim]);
1221
+ const { shouldRender } = useDatePickerDialogAnimation({
1222
+ visible,
1223
+ fadeAnim,
1224
+ slideAnim,
1225
+ scaleAnim,
1226
+ onCloseComplete
1227
+ });
1228
+ const { animate: animateViewTransition } = useViewTransitionAnimation({
1229
+ fadeAnim: viewFadeAnim
1230
+ });
1231
+ const { animate: animateMonthSlide } = useMonthSlideAnimation({
1232
+ slideAnim: monthSlideXAnim,
1233
+ fadeAnim: monthFadeAnim
1234
+ });
1235
+ const prevViewModeRef = useRef5(viewMode);
1236
+ useEffect5(() => {
1237
+ if (prevViewModeRef.current !== viewMode) {
1238
+ prevViewModeRef.current = viewMode;
1239
+ animateViewTransition();
1240
+ }
1241
+ }, [viewMode, animateViewTransition]);
1242
+ useEffect5(() => {
1243
+ if (visible && selectedDate) {
1244
+ syncViewToDate(selectedDate);
1245
+ }
1246
+ }, [visible, selectedDate, syncViewToDate]);
1247
+ useEffect5(() => {
1248
+ if (!visible) return;
1249
+ const sub = BackHandler.addEventListener("hardwareBackPress", () => {
1250
+ onClose();
1251
+ return true;
1252
+ });
1253
+ return () => sub.remove();
1254
+ }, [visible, onClose]);
1255
+ const handlePreviousMonth = useCallback4(() => {
1256
+ goToPreviousMonth();
1257
+ animateMonthSlide("left");
1258
+ }, [goToPreviousMonth, animateMonthSlide]);
1259
+ const handleNextMonth = useCallback4(() => {
1260
+ goToNextMonth();
1261
+ animateMonthSlide("right");
1262
+ }, [goToNextMonth, animateMonthSlide]);
1263
+ const handleDaySelect = useCallback4(
1264
+ (date) => {
1265
+ onDateSelect(date);
1266
+ },
1267
+ [onDateSelect]
1268
+ );
1269
+ const handleTodayPress = useCallback4(() => {
1270
+ const today = /* @__PURE__ */ new Date();
1271
+ if (!isDateInRange(today, minDate, maxDate)) return;
1272
+ goToToday();
1273
+ onDateSelect(today);
1274
+ }, [goToToday, onDateSelect, minDate, maxDate]);
1275
+ if (!shouldRender) return null;
1276
+ const overlayStyle = {
1277
+ position: "absolute",
1278
+ top: 0,
1279
+ left: 0,
1280
+ width: screenWidth,
1281
+ height: screenHeight
1282
+ };
1283
+ const containerAnimatedStyle = {
1284
+ opacity: fadeAnim,
1285
+ transform: [
1286
+ {
1287
+ scale: scaleAnim.interpolate({
1288
+ inputRange: [0, 1],
1289
+ outputRange: [0.92, 1]
1290
+ })
1291
+ },
1292
+ {
1293
+ translateY: slideAnim.interpolate({
1294
+ inputRange: [0, 1],
1295
+ outputRange: [40, 0]
1296
+ })
1297
+ }
1298
+ ]
1299
+ };
1300
+ const viewTransitionStyle = {
1301
+ opacity: viewFadeAnim,
1302
+ transform: [
1303
+ {
1304
+ translateY: viewFadeAnim.interpolate({
1305
+ inputRange: [0, 1],
1306
+ outputRange: [8, 0]
1307
+ })
1308
+ }
1309
+ ]
1310
+ };
1311
+ const monthSlideStyle = {
1312
+ opacity: monthFadeAnim,
1313
+ transform: [{ translateX: monthSlideXAnim }]
1314
+ };
1315
+ const renderContent = () => {
1316
+ switch (viewMode) {
1317
+ case "year":
1318
+ return /* @__PURE__ */ React5.createElement(
1319
+ DatePickerDialogYearPicker,
1320
+ {
1321
+ viewDate,
1322
+ themeColor,
1323
+ minDate,
1324
+ maxDate,
1325
+ onSelectYear: goToYear
1326
+ }
1327
+ );
1328
+ case "month":
1329
+ return /* @__PURE__ */ React5.createElement(
1330
+ DatePickerDialogMonthPicker,
1331
+ {
1332
+ viewDate,
1333
+ locale,
1334
+ themeColor,
1335
+ onSelectMonth: goToMonth
1336
+ }
1337
+ );
1338
+ case "calendar":
1339
+ default:
1340
+ return /* @__PURE__ */ React5.createElement(Animated5.View, { style: [viewTransitionStyle, monthSlideStyle] }, /* @__PURE__ */ React5.createElement(
1341
+ DatePickerDialogCalendar,
1342
+ {
1343
+ viewDate,
1344
+ selectedDate,
1345
+ locale,
1346
+ firstDayOfWeek,
1347
+ themeColor,
1348
+ minDate,
1349
+ maxDate,
1350
+ onSelectDay: handleDaySelect,
1351
+ onPreviousMonth: handlePreviousMonth,
1352
+ onNextMonth: handleNextMonth
1353
+ }
1354
+ ));
1355
+ }
1356
+ };
1357
+ return /* @__PURE__ */ React5.createElement(Portal, null, /* @__PURE__ */ React5.createElement(GestureHandlerRootView, { style: [overlayStyle, style] }, /* @__PURE__ */ React5.createElement(View5, { style: overlayStyle }, /* @__PURE__ */ React5.createElement(Animated5.View, { style: [styles2.backdrop, { opacity: fadeAnim }] }, /* @__PURE__ */ React5.createElement(
1358
+ Pressable5,
1359
+ {
1360
+ style: { flex: 1 },
1361
+ onPress: onClose,
1362
+ accessibilityLabel: "Close calendar",
1363
+ accessibilityRole: "button"
1364
+ }
1365
+ )), /* @__PURE__ */ React5.createElement(Animated5.View, { style: [styles2.dialogContainer, containerAnimatedStyle] }, /* @__PURE__ */ React5.createElement(
1366
+ View5,
1367
+ {
1368
+ style: [
1369
+ styles2.container,
1370
+ { backgroundColor: theme.colors.background }
1371
+ ]
1372
+ },
1373
+ /* @__PURE__ */ React5.createElement(
1374
+ DatePickerDialogHeader,
1375
+ {
1376
+ viewDate,
1377
+ selectedDate,
1378
+ locale,
1379
+ themeColor,
1380
+ selectDateLabel: labels.selectDate,
1381
+ onClearValue,
1382
+ onPreviousMonth: handlePreviousMonth,
1383
+ onNextMonth: handleNextMonth,
1384
+ onToggleYearPicker: toggleYearPicker
1385
+ }
1386
+ ),
1387
+ renderContent(),
1388
+ /* @__PURE__ */ React5.createElement(View5, { style: styles2.footer }, /* @__PURE__ */ React5.createElement(
1389
+ Pressable5,
1390
+ {
1391
+ style: styles2.footerButton,
1392
+ onPress: handleTodayPress,
1393
+ accessibilityLabel: resolvedTodayLabel,
1394
+ accessibilityRole: "button"
1395
+ },
1396
+ /* @__PURE__ */ React5.createElement(Text5, { style: [styles2.footerButtonText, { color: accentColor }] }, resolvedTodayLabel)
1397
+ ), /* @__PURE__ */ React5.createElement(
1398
+ Pressable5,
1399
+ {
1400
+ style: styles2.footerButton,
1401
+ onPress: onClose,
1402
+ accessibilityLabel: resolvedConfirmLabel,
1403
+ accessibilityRole: "button"
1404
+ },
1405
+ /* @__PURE__ */ React5.createElement(Text5, { style: [styles2.footerButtonText, { color: accentColor }] }, resolvedConfirmLabel)
1406
+ ))
1407
+ )))));
1408
+ };
1409
+
1410
+ // src/components/datepicker/datepicker-trigger.tsx
1411
+ import React6 from "react";
1412
+ import { Pressable as Pressable6, Text as Text6, TouchableOpacity, View as View6 } from "react-native";
1413
+ import { CalendarIcon } from "@xaui/icons/calendar";
1414
+ import { CloseIcon as CloseIcon2 } from "@xaui/icons/close";
1415
+ var DatePickerTrigger = ({
1416
+ triggerRef,
1417
+ isDisabled,
1418
+ hasValue,
1419
+ displayValue,
1420
+ sizeStyles,
1421
+ radiusStyles,
1422
+ variantStyles,
1423
+ theme,
1424
+ isClearable,
1425
+ label,
1426
+ labelText,
1427
+ isLabelInside,
1428
+ calendarIcon,
1429
+ style,
1430
+ textStyle,
1431
+ onPress: handleTriggerPress,
1432
+ onClear: handleClear,
1433
+ onLayout: handleTriggerLayout
1434
+ }) => {
1435
+ const renderLabel = isLabelInside && label;
1436
+ return /* @__PURE__ */ React6.createElement(
1437
+ Pressable6,
1438
+ {
1439
+ ref: triggerRef,
1440
+ onPress: handleTriggerPress,
1441
+ onLayout: handleTriggerLayout,
1442
+ disabled: isDisabled,
1443
+ style: [
1444
+ styles.trigger,
1445
+ {
1446
+ minHeight: sizeStyles.minHeight,
1447
+ paddingHorizontal: sizeStyles.paddingHorizontal,
1448
+ paddingVertical: sizeStyles.paddingVertical
1449
+ },
1450
+ radiusStyles,
1451
+ variantStyles,
1452
+ isDisabled && styles.disabled,
1453
+ style
1454
+ ],
1455
+ accessibilityLabel: labelText ?? (typeof label === "string" ? label : void 0),
1456
+ accessibilityRole: "button",
1457
+ accessibilityState: { disabled: isDisabled }
1458
+ },
1459
+ /* @__PURE__ */ React6.createElement(View6, { style: styles.triggerContent }, isLabelInside && renderLabel, /* @__PURE__ */ React6.createElement(
1460
+ Text6,
1461
+ {
1462
+ style: [
1463
+ styles.triggerText,
1464
+ { fontSize: sizeStyles.fontSize, color: theme.colors.foreground },
1465
+ !hasValue && { opacity: 0.5 },
1466
+ textStyle
1467
+ ],
1468
+ numberOfLines: 1,
1469
+ ellipsizeMode: "tail"
1470
+ },
1471
+ displayValue
1472
+ )),
1473
+ isClearable && hasValue ? /* @__PURE__ */ React6.createElement(
1474
+ TouchableOpacity,
1475
+ {
1476
+ onPress: handleClear,
1477
+ style: styles.clearButton,
1478
+ hitSlop: { top: 8, right: 8, bottom: 8, left: 8 }
1479
+ },
1480
+ /* @__PURE__ */ React6.createElement(CloseIcon2, { color: theme.colors.foreground, size: 20 })
1481
+ ) : calendarIcon ?? /* @__PURE__ */ React6.createElement(CalendarIcon, { color: theme.colors.foreground, size: 20 })
1482
+ );
1483
+ };
1484
+
1485
+ // src/components/datepicker/datepicker.tsx
1486
+ var DatePicker = ({
1487
+ value,
1488
+ defaultValue,
1489
+ onChange,
1490
+ locale = "en",
1491
+ minDate,
1492
+ maxDate,
1493
+ firstDayOfWeek: firstDayOfWeekProp,
1494
+ variant = "flat",
1495
+ themeColor = "default",
1496
+ size = "md",
1497
+ radius = "md",
1498
+ label,
1499
+ placeholder = "Select a date",
1500
+ description,
1501
+ errorMessage,
1502
+ labelPlacement = "outside",
1503
+ fullWidth = false,
1504
+ isDisabled = false,
1505
+ isInvalid = false,
1506
+ isReadOnly = false,
1507
+ isClearable = true,
1508
+ customAppearance,
1509
+ calendarIcon,
1510
+ onOpen,
1511
+ onClose,
1512
+ onOpenChange
1513
+ }) => {
1514
+ const theme = useXUITheme();
1515
+ const { selectedDate, updateDate } = useDatePickerState({
1516
+ value,
1517
+ defaultValue,
1518
+ onChange
1519
+ });
1520
+ const { isOpen, setOpen } = useDatePickerOpenState({
1521
+ isDisabled: isDisabled || isReadOnly,
1522
+ onOpenChange,
1523
+ onOpen,
1524
+ onClose
1525
+ });
1526
+ const triggerRef = useRef6(null);
1527
+ const handleTriggerLayout = useCallback5(() => {
1528
+ }, []);
1529
+ const firstDayOfWeek = useMemo6(
1530
+ () => firstDayOfWeekProp ?? getFirstDayOfWeek(locale),
1531
+ [firstDayOfWeekProp, locale]
1532
+ );
1533
+ const sizeStyles = useDatePickerSizeStyles(size);
1534
+ const radiusStyles = useDatePickerRadiusStyles(radius);
1535
+ const variantStyles = useDatePickerVariantStyles(themeColor, variant, isInvalid);
1536
+ const labelStyle = useDatePickerLabelStyle(
1537
+ themeColor,
1538
+ isInvalid,
1539
+ sizeStyles.labelSize
1540
+ );
1541
+ const helperColor = useDatePickerHelperColor(isInvalid);
1542
+ const displayValue = useMemo6(() => {
1543
+ if (!selectedDate) return placeholder;
1544
+ return formatDate(selectedDate, locale);
1545
+ }, [selectedDate, locale, placeholder]);
1546
+ const handleTriggerPress = useCallback5(() => {
1547
+ if (!isDisabled && !isReadOnly) {
1548
+ setOpen(true);
1549
+ }
1550
+ }, [isDisabled, isReadOnly, setOpen]);
1551
+ const handleClear = useCallback5(() => {
1552
+ if (isDisabled || isReadOnly) return;
1553
+ updateDate(null);
1554
+ }, [isDisabled, isReadOnly, updateDate]);
1555
+ const handleDateSelect = useCallback5(
1556
+ (date) => {
1557
+ updateDate(date);
1558
+ },
1559
+ [updateDate]
1560
+ );
1561
+ const handleClose = useCallback5(() => {
1562
+ setOpen(false);
1563
+ }, [setOpen]);
1564
+ const isLabelInside = labelPlacement === "inside";
1565
+ const isLabelOutsideLeft = labelPlacement === "outside-left";
1566
+ const isLabelOutside = labelPlacement === "outside" || labelPlacement === "outside-top";
1567
+ const renderLabel = label ? typeof label === "string" || typeof label === "number" ? /* @__PURE__ */ React7.createElement(Text7, { style: [styles.label, labelStyle] }, label) : /* @__PURE__ */ React7.createElement(View7, null, label) : null;
1568
+ const shouldShowHelper = Boolean(description || errorMessage);
1569
+ const helperContent = isInvalid && errorMessage ? errorMessage : description;
1570
+ const triggerContent = /* @__PURE__ */ React7.createElement(
1571
+ DatePickerTrigger,
1572
+ {
1573
+ triggerRef,
1574
+ isDisabled: isDisabled || isReadOnly,
1575
+ hasValue: !!selectedDate,
1576
+ displayValue,
1577
+ sizeStyles,
1578
+ radiusStyles,
1579
+ variantStyles,
1580
+ theme,
1581
+ isClearable,
1582
+ label: renderLabel,
1583
+ labelText: typeof label === "string" ? label : void 0,
1584
+ isLabelInside,
1585
+ calendarIcon,
1586
+ style: customAppearance?.trigger,
1587
+ textStyle: customAppearance?.text,
1588
+ onPress: handleTriggerPress,
1589
+ onClear: handleClear,
1590
+ onLayout: handleTriggerLayout
1591
+ }
1592
+ );
1593
+ const labelBlock = isLabelOutside || isLabelInside ? renderLabel : null;
1594
+ return /* @__PURE__ */ React7.createElement(
1595
+ View7,
1596
+ {
1597
+ style: [
1598
+ styles.container,
1599
+ fullWidth ? styles.fullWidth : styles.minWidth,
1600
+ customAppearance?.container
1601
+ ]
1602
+ },
1603
+ isLabelOutside && labelBlock,
1604
+ isLabelOutsideLeft ? /* @__PURE__ */ React7.createElement(View7, { style: styles.outsideLeftRow }, renderLabel, triggerContent) : triggerContent,
1605
+ shouldShowHelper && helperContent ? typeof helperContent === "string" || typeof helperContent === "number" ? /* @__PURE__ */ React7.createElement(Text7, { style: [styles.helperText, { color: helperColor }] }, helperContent) : /* @__PURE__ */ React7.createElement(View7, null, helperContent) : null,
1606
+ /* @__PURE__ */ React7.createElement(
1607
+ DatePickerDialog,
1608
+ {
1609
+ visible: isOpen,
1610
+ selectedDate,
1611
+ locale,
1612
+ firstDayOfWeek,
1613
+ themeColor,
1614
+ minDate,
1615
+ maxDate,
1616
+ style: customAppearance?.calendar,
1617
+ onDateSelect: handleDateSelect,
1618
+ onClearValue: handleClear,
1619
+ onClose: handleClose
1620
+ }
1621
+ )
1622
+ );
1623
+ };
1624
+
1625
+ export {
1626
+ DatePicker
1627
+ };