@xaui/native 0.0.17 → 0.0.19

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