@xaui/native 0.0.16 → 0.0.18

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 (62) hide show
  1. package/dist/accordion/index.cjs +1 -1
  2. package/dist/accordion/index.js +5 -4
  3. package/dist/alert/index.js +352 -3
  4. package/dist/autocomplete/index.cjs +5 -11
  5. package/dist/autocomplete/index.js +1122 -5
  6. package/dist/avatar/index.js +276 -4
  7. package/dist/badge/index.js +193 -3
  8. package/dist/bottom-sheet/index.cjs +9 -20
  9. package/dist/bottom-sheet/index.js +364 -3
  10. package/dist/button/index.js +3 -2
  11. package/dist/card/index.cjs +429 -0
  12. package/dist/card/index.d.cts +186 -0
  13. package/dist/card/index.d.ts +186 -0
  14. package/dist/card/index.js +336 -0
  15. package/dist/carousel/index.cjs +458 -0
  16. package/dist/carousel/index.d.cts +147 -0
  17. package/dist/carousel/index.d.ts +147 -0
  18. package/dist/carousel/index.js +381 -0
  19. package/dist/checkbox/index.js +2 -1
  20. package/dist/chip/index.cjs +2 -8
  21. package/dist/chip/index.js +497 -5
  22. package/dist/chunk-DXXNBF5P.js +7 -0
  23. package/dist/{chunk-MKHBEJLO.js → chunk-F7WH4DMG.js} +1 -1
  24. package/dist/{chunk-II4QINLG.js → chunk-JEGEPGVU.js} +2 -2
  25. package/dist/{chunk-NBRASCX4.js → chunk-LTKYHG5V.js} +6 -13
  26. package/dist/{chunk-GNJIET26.js → chunk-LUBWRVI2.js} +1 -1
  27. package/dist/core/index.cjs +1 -1
  28. package/dist/core/index.js +5 -3
  29. package/dist/datepicker/index.js +1623 -3
  30. package/dist/divider/index.js +3 -2
  31. package/dist/fab/index.js +4 -3
  32. package/dist/fab-menu/index.cjs +4 -13
  33. package/dist/fab-menu/index.js +325 -6
  34. package/dist/index.cjs +0 -5709
  35. package/dist/index.d.cts +2 -17
  36. package/dist/index.d.ts +2 -17
  37. package/dist/index.js +0 -62
  38. package/dist/indicator/index.js +3 -2
  39. package/dist/menu/index.cjs +8 -7
  40. package/dist/menu/index.js +15 -9
  41. package/dist/progress/index.js +2 -1
  42. package/dist/segment-button/index.cjs +492 -0
  43. package/dist/segment-button/index.d.cts +141 -0
  44. package/dist/segment-button/index.d.ts +141 -0
  45. package/dist/segment-button/index.js +405 -0
  46. package/dist/select/index.js +2 -1
  47. package/dist/switch/index.js +2 -1
  48. package/dist/typography/index.js +146 -3
  49. package/dist/view/index.cjs +153 -78
  50. package/dist/view/index.d.cts +77 -1
  51. package/dist/view/index.d.ts +77 -1
  52. package/dist/view/index.js +125 -52
  53. package/package.json +16 -1
  54. package/dist/chunk-2T6FKPJW.js +0 -356
  55. package/dist/chunk-4LFRYVSR.js +0 -281
  56. package/dist/chunk-7OFTYKK4.js +0 -1627
  57. package/dist/chunk-EI5OMBFE.js +0 -338
  58. package/dist/chunk-GAOI4KIV.js +0 -379
  59. package/dist/chunk-NMZUPH3R.js +0 -1133
  60. package/dist/chunk-QLEQYKG5.js +0 -509
  61. package/dist/chunk-XJKA22BK.js +0 -197
  62. package/dist/chunk-ZYTBRHLJ.js +0 -150
@@ -1,9 +1,1126 @@
1
1
  import {
2
- Autocomplete,
3
- AutocompleteItem
4
- } from "../chunk-NMZUPH3R.js";
5
- import "../chunk-GBHQCAKW.js";
6
- import "../chunk-NBRASCX4.js";
2
+ CheckmarkIcon
3
+ } from "../chunk-GBHQCAKW.js";
4
+ import "../chunk-DXXNBF5P.js";
5
+ import {
6
+ Portal,
7
+ useXUITheme
8
+ } from "../chunk-LTKYHG5V.js";
9
+
10
+ // src/components/autocomplete/autocomplete.tsx
11
+ import React4, { useCallback as useCallback3, useMemo as useMemo3, useRef as useRef3, useState as useState3 } from "react";
12
+ import { Keyboard as Keyboard2, Text as Text3, View as View4 } from "react-native";
13
+
14
+ // src/components/autocomplete/autocomplete-context.ts
15
+ import { createContext } from "react";
16
+ var AutocompleteContext = createContext({
17
+ size: "md",
18
+ themeColor: "default",
19
+ isDisabled: false
20
+ });
21
+
22
+ // src/components/autocomplete/autocomplete.hook.ts
23
+ import { useMemo } from "react";
24
+ import { getSafeThemeColor } from "@xaui/core";
25
+ import { colors } from "@xaui/core/palette";
26
+ var useAutocompleteColorScheme = (themeColor) => {
27
+ const theme = useXUITheme();
28
+ const safeThemeColor = getSafeThemeColor(themeColor);
29
+ const colorScheme = theme.colors[safeThemeColor];
30
+ return { theme, colorScheme };
31
+ };
32
+ var useAutocompleteSizeStyles = (size) => {
33
+ const theme = useXUITheme();
34
+ return useMemo(() => {
35
+ const sizes = {
36
+ xs: {
37
+ minHeight: 34,
38
+ paddingHorizontal: theme.spacing.sm,
39
+ paddingVertical: theme.spacing.xs,
40
+ fontSize: theme.fontSizes.xs,
41
+ labelSize: theme.fontSizes.xs
42
+ },
43
+ sm: {
44
+ minHeight: 38,
45
+ paddingHorizontal: theme.spacing.md,
46
+ paddingVertical: theme.spacing.xs,
47
+ fontSize: theme.fontSizes.sm,
48
+ labelSize: theme.fontSizes.xs
49
+ },
50
+ md: {
51
+ minHeight: 42,
52
+ paddingHorizontal: theme.spacing.md,
53
+ paddingVertical: theme.spacing.sm,
54
+ fontSize: theme.fontSizes.md,
55
+ labelSize: theme.fontSizes.sm
56
+ },
57
+ lg: {
58
+ minHeight: 50,
59
+ paddingHorizontal: theme.spacing.lg,
60
+ paddingVertical: theme.spacing.md,
61
+ fontSize: theme.fontSizes.lg,
62
+ labelSize: theme.fontSizes.md
63
+ }
64
+ };
65
+ return sizes[size];
66
+ }, [size, theme]);
67
+ };
68
+ var useAutocompleteRadiusStyles = (radius) => {
69
+ const theme = useXUITheme();
70
+ const radiusStyles = useMemo(() => {
71
+ const radii = {
72
+ none: theme.borderRadius.none,
73
+ sm: theme.borderRadius.sm,
74
+ md: theme.borderRadius.md,
75
+ lg: theme.borderRadius.lg,
76
+ full: theme.borderRadius.full
77
+ };
78
+ return { borderRadius: radii[radius] };
79
+ }, [radius, theme]);
80
+ const listboxRadius = useMemo(() => {
81
+ const radii = {
82
+ none: theme.borderRadius.none,
83
+ sm: theme.borderRadius.sm,
84
+ md: theme.borderRadius.md,
85
+ lg: theme.borderRadius.lg,
86
+ full: theme.borderRadius.full
87
+ };
88
+ return Math.min(radii[radius], theme.borderRadius.lg);
89
+ }, [radius, theme]);
90
+ return { radiusStyles, listboxRadius };
91
+ };
92
+ var useAutocompleteVariantStyles = (themeColor, variant, isInvalid) => {
93
+ const { theme, colorScheme } = useAutocompleteColorScheme(themeColor);
94
+ return useMemo(() => {
95
+ let borderColor = isInvalid ? theme.colors.danger.main : colorScheme.main;
96
+ if ((variant === "outlined" || variant === "faded") && themeColor === "default") {
97
+ borderColor = colors.gray[300];
98
+ }
99
+ const styles4 = {
100
+ outlined: {
101
+ backgroundColor: "transparent",
102
+ borderWidth: theme.borderWidth.md,
103
+ borderColor
104
+ },
105
+ flat: {
106
+ backgroundColor: colorScheme.background,
107
+ borderWidth: 0
108
+ },
109
+ light: {
110
+ backgroundColor: "transparent",
111
+ borderWidth: 0
112
+ },
113
+ faded: {
114
+ backgroundColor: `${colorScheme.background}90`,
115
+ borderWidth: theme.borderWidth.md,
116
+ borderColor
117
+ },
118
+ underlined: {
119
+ backgroundColor: "transparent",
120
+ borderBottomWidth: theme.borderWidth.md,
121
+ borderColor
122
+ }
123
+ };
124
+ return styles4[variant];
125
+ }, [variant, theme, colorScheme, isInvalid, themeColor]);
126
+ };
127
+ var useAutocompleteLabelStyle = (themeColor, isInvalid, labelSize) => {
128
+ const { theme, colorScheme } = useAutocompleteColorScheme(themeColor);
129
+ return useMemo(() => {
130
+ let baseColor = theme.colors.foreground;
131
+ if (isInvalid) {
132
+ baseColor = theme.colors.danger.main;
133
+ } else if (themeColor !== "default") {
134
+ baseColor = colorScheme.main;
135
+ }
136
+ return {
137
+ fontSize: labelSize,
138
+ color: baseColor
139
+ };
140
+ }, [isInvalid, labelSize, theme, themeColor, colorScheme]);
141
+ };
142
+ var useAutocompleteHelperColor = (isInvalid) => {
143
+ const theme = useXUITheme();
144
+ return useMemo(() => {
145
+ if (isInvalid) {
146
+ return theme.colors.danger.main;
147
+ }
148
+ return colors.gray[600];
149
+ }, [isInvalid, theme]);
150
+ };
151
+
152
+ // src/components/autocomplete/autocomplete.style.ts
153
+ import { StyleSheet } from "react-native";
154
+ var styles = StyleSheet.create({
155
+ container: {
156
+ gap: 6,
157
+ position: "relative"
158
+ },
159
+ fullWidth: {
160
+ flexShrink: 1,
161
+ flexBasis: "auto",
162
+ width: "100%"
163
+ },
164
+ minWidth: {
165
+ minWidth: 170
166
+ },
167
+ label: {
168
+ fontWeight: "500"
169
+ },
170
+ trigger: {
171
+ flexDirection: "row",
172
+ alignItems: "center",
173
+ justifyContent: "space-between",
174
+ gap: 8
175
+ },
176
+ triggerText: {
177
+ flex: 1
178
+ },
179
+ triggerWrapper: {
180
+ position: "relative"
181
+ },
182
+ triggerContent: {
183
+ flexDirection: "row",
184
+ alignItems: "center",
185
+ flex: 1,
186
+ gap: 8
187
+ },
188
+ triggerContentColumn: {
189
+ flexDirection: "column",
190
+ alignItems: "flex-start"
191
+ },
192
+ inputWrapper: {
193
+ flex: 1,
194
+ gap: 2
195
+ },
196
+ input: {
197
+ flexShrink: 1,
198
+ padding: 0
199
+ },
200
+ endSlot: {
201
+ flexDirection: "row",
202
+ alignItems: "center",
203
+ gap: 8
204
+ },
205
+ clearButton: {
206
+ padding: 2,
207
+ paddingLeft: 4,
208
+ marginRight: -4
209
+ },
210
+ helperText: {
211
+ fontSize: 12
212
+ },
213
+ disabled: {
214
+ opacity: 0.5
215
+ },
216
+ listbox: {
217
+ overflow: "hidden",
218
+ marginTop: 0,
219
+ position: "absolute",
220
+ left: 0,
221
+ right: 0,
222
+ zIndex: 50,
223
+ elevation: 4
224
+ },
225
+ listboxContent: {
226
+ flexShrink: 1
227
+ },
228
+ emptyMessage: {
229
+ paddingHorizontal: 16,
230
+ paddingVertical: 12,
231
+ textAlign: "center"
232
+ },
233
+ outsideLeftRow: {
234
+ flexDirection: "row",
235
+ alignItems: "center",
236
+ gap: 12
237
+ }
238
+ });
239
+
240
+ // src/components/autocomplete/autocomplete.state.hook.ts
241
+ import { useCallback, useEffect, useRef, useState } from "react";
242
+ var useAutocompleteOpenState = ({
243
+ isOpened,
244
+ isDisabled,
245
+ onOpenChange,
246
+ onClose
247
+ }) => {
248
+ const [internalIsOpen, setInternalIsOpen] = useState(false);
249
+ const isOpen = isOpened !== void 0 ? isOpened : internalIsOpen;
250
+ const setOpen = useCallback(
251
+ (open) => {
252
+ if (isDisabled) {
253
+ return;
254
+ }
255
+ if (isOpened === void 0) {
256
+ setInternalIsOpen(open);
257
+ }
258
+ onOpenChange?.(open);
259
+ if (!open) {
260
+ onClose?.();
261
+ }
262
+ },
263
+ [isDisabled, isOpened, onOpenChange, onClose]
264
+ );
265
+ return { isOpen, setOpen };
266
+ };
267
+ var useAutocompleteInputState = ({
268
+ inputValue,
269
+ defaultInputValue,
270
+ selectedKey,
271
+ onInputChange
272
+ }) => {
273
+ const [internalInputValue, setInternalInputValue] = useState(
274
+ defaultInputValue ?? ""
275
+ );
276
+ const currentInputValue = inputValue !== void 0 ? inputValue : internalInputValue;
277
+ const updateInputValue = useCallback(
278
+ (value) => {
279
+ if (inputValue === void 0) {
280
+ setInternalInputValue(value);
281
+ }
282
+ onInputChange?.(value);
283
+ },
284
+ [inputValue, onInputChange]
285
+ );
286
+ useEffect(() => {
287
+ if (selectedKey === null && inputValue === void 0) {
288
+ setInternalInputValue("");
289
+ }
290
+ }, [selectedKey, inputValue]);
291
+ return { currentInputValue, updateInputValue };
292
+ };
293
+ var useAutocompleteSelection = ({
294
+ onSelectionChange
295
+ }) => {
296
+ const [currentSelectedKey, setCurrentSelectedKey] = useState(null);
297
+ const updateSelection = useCallback(
298
+ (key) => {
299
+ setCurrentSelectedKey(key);
300
+ onSelectionChange?.(key);
301
+ },
302
+ [onSelectionChange]
303
+ );
304
+ return { currentSelectedKey, updateSelection };
305
+ };
306
+
307
+ // src/components/autocomplete/autocomplete.utils.ts
308
+ var getTextValue = (node) => {
309
+ if (typeof node === "string" || typeof node === "number") {
310
+ return String(node);
311
+ }
312
+ return null;
313
+ };
314
+ var defaultFilterFunction = (textValue, inputValue) => {
315
+ const normalizedText = textValue.toLowerCase().trim();
316
+ const normalizedInput = inputValue.toLowerCase().trim();
317
+ return normalizedText.includes(normalizedInput);
318
+ };
319
+
320
+ // src/components/dialogs/autocomplete-dialog/autocomplete-dialog.tsx
321
+ import React2, { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
322
+ import {
323
+ Animated as Animated3,
324
+ BackHandler,
325
+ FlatList,
326
+ InteractionManager,
327
+ Keyboard,
328
+ Platform,
329
+ Pressable as Pressable2,
330
+ View as View2,
331
+ useWindowDimensions
332
+ } from "react-native";
333
+
334
+ // src/components/dialogs/autocomplete-dialog/autocomplete-dialog-header.tsx
335
+ import React from "react";
336
+ import {
337
+ Animated,
338
+ Pressable,
339
+ Text,
340
+ TextInput,
341
+ View
342
+ } from "react-native";
343
+ import { ArrowBackIcon, CloseIcon } from "@xaui/icons";
344
+
345
+ // src/components/dialogs/autocomplete-dialog/autocomplete-dialog.style.ts
346
+ import { StyleSheet as StyleSheet2 } from "react-native";
347
+ var styles2 = StyleSheet2.create({
348
+ backdrop: {
349
+ ...StyleSheet2.absoluteFillObject,
350
+ backgroundColor: "rgba(0, 0, 0, 0.5)"
351
+ },
352
+ dialogContainer: {
353
+ flex: 1,
354
+ zIndex: 1
355
+ },
356
+ container: {
357
+ flex: 1,
358
+ paddingTop: 55,
359
+ paddingHorizontal: 16
360
+ },
361
+ header: {
362
+ marginBottom: 12
363
+ },
364
+ titleRow: {
365
+ flexDirection: "row",
366
+ alignItems: "center",
367
+ gap: 8,
368
+ marginBottom: 16
369
+ },
370
+ backButton: {
371
+ padding: 4
372
+ },
373
+ title: {
374
+ fontSize: 20,
375
+ fontWeight: "600"
376
+ },
377
+ inputContainer: {
378
+ flexDirection: "row",
379
+ alignItems: "center",
380
+ gap: 8
381
+ },
382
+ inputWrapper: {
383
+ flex: 1,
384
+ flexDirection: "row",
385
+ alignItems: "center",
386
+ position: "relative"
387
+ },
388
+ input: {
389
+ flex: 1,
390
+ paddingVertical: 12,
391
+ paddingHorizontal: 16,
392
+ paddingRight: 40,
393
+ borderRadius: 8,
394
+ fontSize: 16
395
+ },
396
+ clearInputButton: {
397
+ position: "absolute",
398
+ right: 8,
399
+ padding: 4
400
+ },
401
+ listContainer: {
402
+ flex: 1
403
+ },
404
+ listContentContainer: {
405
+ paddingBottom: 80
406
+ },
407
+ checkmarkButtonContainer: {
408
+ position: "absolute",
409
+ bottom: 24,
410
+ right: 24
411
+ },
412
+ checkmarkButton: {
413
+ width: 54,
414
+ height: 54,
415
+ borderRadius: 27,
416
+ justifyContent: "center",
417
+ alignItems: "center",
418
+ elevation: 8
419
+ }
420
+ });
421
+
422
+ // src/components/dialogs/autocomplete-dialog/autocomplete-dialog-header.tsx
423
+ import { withOpacity } from "@xaui/core";
424
+ var AutocompleteDialogHeader = ({
425
+ title,
426
+ inputValue,
427
+ placeholder = "Search...",
428
+ inputRef,
429
+ inputAnimatedStyle,
430
+ inputTextStyle,
431
+ onInputChange,
432
+ onClose,
433
+ onCheckmarkPress,
434
+ onFocus,
435
+ onBlur
436
+ }) => {
437
+ const theme = useXUITheme();
438
+ return /* @__PURE__ */ React.createElement(View, { style: styles2.header }, title ? /* @__PURE__ */ React.createElement(View, { style: styles2.titleRow }, /* @__PURE__ */ React.createElement(
439
+ Pressable,
440
+ {
441
+ style: styles2.backButton,
442
+ onPress: onClose,
443
+ accessibilityLabel: "Back",
444
+ accessibilityRole: "button"
445
+ },
446
+ /* @__PURE__ */ React.createElement(ArrowBackIcon, { size: 20, color: theme.colors.foreground })
447
+ ), /* @__PURE__ */ React.createElement(Text, { style: [styles2.title, { color: theme.colors.foreground }] }, title)) : null, /* @__PURE__ */ React.createElement(View, { style: styles2.inputContainer }, /* @__PURE__ */ React.createElement(Animated.View, { style: [styles2.inputWrapper, inputAnimatedStyle] }, /* @__PURE__ */ React.createElement(
448
+ TextInput,
449
+ {
450
+ ref: inputRef,
451
+ value: inputValue,
452
+ onChangeText: onInputChange,
453
+ placeholder,
454
+ placeholderTextColor: withOpacity(theme.colors.foreground, 0.5),
455
+ style: [
456
+ styles2.input,
457
+ {
458
+ backgroundColor: theme.colors.default.background,
459
+ color: theme.colors.foreground
460
+ },
461
+ inputTextStyle
462
+ ],
463
+ autoFocus: true,
464
+ returnKeyType: "done",
465
+ onSubmitEditing: onCheckmarkPress,
466
+ onFocus,
467
+ onBlur
468
+ }
469
+ ), inputValue ? /* @__PURE__ */ React.createElement(
470
+ Pressable,
471
+ {
472
+ style: styles2.clearInputButton,
473
+ onPress: () => onInputChange?.(""),
474
+ accessibilityLabel: "Clear input",
475
+ accessibilityRole: "button"
476
+ },
477
+ /* @__PURE__ */ React.createElement(CloseIcon, { color: theme.colors.foreground })
478
+ ) : null)));
479
+ };
480
+
481
+ // src/components/dialogs/autocomplete-dialog/autocomplete-dialog.animation.ts
482
+ import { useEffect as useEffect2 } from "react";
483
+ import { Animated as Animated2 } from "react-native";
484
+ var useAutocompleteDialogAnimation = ({
485
+ visible,
486
+ fadeAnim,
487
+ slideAnim,
488
+ scaleAnim
489
+ }) => {
490
+ useEffect2(() => {
491
+ if (visible) {
492
+ Animated2.parallel([
493
+ Animated2.timing(fadeAnim, {
494
+ toValue: 1,
495
+ duration: 250,
496
+ useNativeDriver: true
497
+ }),
498
+ Animated2.spring(slideAnim, {
499
+ toValue: 1,
500
+ useNativeDriver: true,
501
+ tension: 65,
502
+ friction: 10
503
+ }),
504
+ Animated2.spring(scaleAnim, {
505
+ toValue: 1,
506
+ useNativeDriver: true,
507
+ tension: 50,
508
+ friction: 8
509
+ })
510
+ ]).start();
511
+ } else {
512
+ fadeAnim.setValue(0);
513
+ slideAnim.setValue(0);
514
+ scaleAnim.setValue(0);
515
+ }
516
+ }, [visible, fadeAnim, slideAnim, scaleAnim]);
517
+ };
518
+
519
+ // src/components/dialogs/autocomplete-dialog/autocomplete-dialog.tsx
520
+ var AutocompleteDialog = ({
521
+ visible,
522
+ inputValue,
523
+ placeholder = "Search...",
524
+ title,
525
+ themeColor = "primary",
526
+ children,
527
+ showCheckmark = true,
528
+ checkmarkIcon,
529
+ inputTextStyle,
530
+ style,
531
+ onInputChange,
532
+ onClose,
533
+ onCheckmark,
534
+ onFocus,
535
+ onBlur
536
+ }) => {
537
+ const theme = useXUITheme();
538
+ const { width: screenWidth, height: screenHeight } = useWindowDimensions();
539
+ const fadeAnim = useRef2(new Animated3.Value(0)).current;
540
+ const slideAnim = useRef2(new Animated3.Value(0)).current;
541
+ const scaleAnim = useRef2(new Animated3.Value(0)).current;
542
+ const inputRef = useRef2(null);
543
+ const [keyboardHeight, setKeyboardHeight] = useState2(0);
544
+ useEffect3(() => {
545
+ const showEvent = Platform.OS === "ios" ? "keyboardWillShow" : "keyboardDidShow";
546
+ const hideEvent = Platform.OS === "ios" ? "keyboardWillHide" : "keyboardDidHide";
547
+ const showSub = Keyboard.addListener(showEvent, (e) => {
548
+ setKeyboardHeight(e.endCoordinates.height);
549
+ });
550
+ const hideSub = Keyboard.addListener(hideEvent, () => {
551
+ setKeyboardHeight(0);
552
+ });
553
+ return () => {
554
+ showSub.remove();
555
+ hideSub.remove();
556
+ };
557
+ }, []);
558
+ const items = useMemo2(
559
+ () => React2.Children.toArray(children).filter(
560
+ React2.isValidElement
561
+ ),
562
+ [children]
563
+ );
564
+ const checkmarkColor = theme.colors[themeColor].main;
565
+ const checkmarkBackgroundColor = theme.colors[themeColor].background;
566
+ useAutocompleteDialogAnimation({ visible, fadeAnim, slideAnim, scaleAnim });
567
+ useEffect3(() => {
568
+ if (!visible) return;
569
+ const sub = BackHandler.addEventListener("hardwareBackPress", () => {
570
+ onClose?.();
571
+ return true;
572
+ });
573
+ return () => sub.remove();
574
+ }, [visible, onClose]);
575
+ const focusInput = useCallback2(() => {
576
+ const delay = Platform.OS === "android" ? 300 : 100;
577
+ InteractionManager.runAfterInteractions(() => {
578
+ setTimeout(() => {
579
+ inputRef.current?.focus();
580
+ }, delay);
581
+ });
582
+ }, []);
583
+ const handleCheckmarkPress = () => {
584
+ onCheckmark?.();
585
+ Keyboard.dismiss();
586
+ };
587
+ useEffect3(() => {
588
+ if (!visible) {
589
+ Keyboard.dismiss();
590
+ return;
591
+ }
592
+ focusInput();
593
+ }, [focusInput, visible]);
594
+ const listBottomPadding = useMemo2(() => {
595
+ const basePadding = showCheckmark ? 96 : 64;
596
+ return (keyboardHeight > 0 ? keyboardHeight : 0) + basePadding;
597
+ }, [keyboardHeight, showCheckmark]);
598
+ if (!visible) return null;
599
+ const overlayStyle = {
600
+ position: "absolute",
601
+ top: 0,
602
+ left: 0,
603
+ width: screenWidth,
604
+ height: screenHeight
605
+ };
606
+ const containerAnimatedStyle = {
607
+ transform: [
608
+ {
609
+ translateY: slideAnim.interpolate({
610
+ inputRange: [0, 1],
611
+ outputRange: [screenHeight, 0]
612
+ })
613
+ }
614
+ ]
615
+ };
616
+ const inputAnimatedStyle = {
617
+ transform: [{ scaleX: scaleAnim }]
618
+ };
619
+ const listHeader = /* @__PURE__ */ React2.createElement(
620
+ AutocompleteDialogHeader,
621
+ {
622
+ title,
623
+ inputValue,
624
+ placeholder,
625
+ inputRef,
626
+ inputAnimatedStyle,
627
+ inputTextStyle,
628
+ onInputChange,
629
+ onClose,
630
+ onCheckmarkPress: handleCheckmarkPress,
631
+ onFocus,
632
+ onBlur
633
+ }
634
+ );
635
+ return /* @__PURE__ */ React2.createElement(Portal, null, /* @__PURE__ */ React2.createElement(View2, { style: [overlayStyle, style] }, /* @__PURE__ */ React2.createElement(Animated3.View, { style: [styles2.backdrop, { opacity: fadeAnim }] }), /* @__PURE__ */ React2.createElement(Animated3.View, { style: [styles2.dialogContainer, containerAnimatedStyle] }, /* @__PURE__ */ React2.createElement(
636
+ View2,
637
+ {
638
+ style: [styles2.container, { backgroundColor: theme.colors.background }]
639
+ },
640
+ listHeader,
641
+ /* @__PURE__ */ React2.createElement(
642
+ FlatList,
643
+ {
644
+ data: items,
645
+ renderItem: ({ item }) => item,
646
+ keyExtractor: (_, index) => String(index),
647
+ style: styles2.listContainer,
648
+ contentContainerStyle: {
649
+ paddingBottom: listBottomPadding
650
+ },
651
+ keyboardShouldPersistTaps: "always",
652
+ keyboardDismissMode: "none",
653
+ showsVerticalScrollIndicator: false
654
+ }
655
+ ),
656
+ showCheckmark ? /* @__PURE__ */ React2.createElement(View2, { style: styles2.checkmarkButtonContainer }, /* @__PURE__ */ React2.createElement(
657
+ Pressable2,
658
+ {
659
+ style: [
660
+ styles2.checkmarkButton,
661
+ { backgroundColor: checkmarkBackgroundColor }
662
+ ],
663
+ onPress: handleCheckmarkPress,
664
+ accessibilityLabel: "Confirm",
665
+ accessibilityRole: "button"
666
+ },
667
+ checkmarkIcon ?? /* @__PURE__ */ React2.createElement(CheckmarkIcon, { color: checkmarkColor, size: 20 })
668
+ )) : null
669
+ ))));
670
+ };
671
+
672
+ // src/components/autocomplete/autocomplete-trigger.tsx
673
+ import React3 from "react";
674
+ import { Pressable as Pressable3, Text as Text2, TouchableOpacity, View as View3 } from "react-native";
675
+ import { CloseIcon as CloseIcon2 } from "@xaui/icons";
676
+ var AutocompleteTrigger = ({
677
+ triggerRef,
678
+ isDisabled,
679
+ currentSelectedKey,
680
+ currentInputValue,
681
+ displayValue,
682
+ sizeStyles,
683
+ radiusStyles,
684
+ variantStyles,
685
+ theme,
686
+ isClearable,
687
+ label,
688
+ labelText,
689
+ isLabelInside,
690
+ clearIcon,
691
+ style,
692
+ textStyle,
693
+ onPress: handleTriggerPress,
694
+ onClear: handleClear,
695
+ onLayout: handleTriggerLayout
696
+ }) => {
697
+ const renderLabel = isLabelInside && label;
698
+ return /* @__PURE__ */ React3.createElement(
699
+ Pressable3,
700
+ {
701
+ ref: triggerRef,
702
+ onPress: handleTriggerPress,
703
+ onLayout: handleTriggerLayout,
704
+ disabled: isDisabled,
705
+ style: [
706
+ styles.trigger,
707
+ {
708
+ minHeight: sizeStyles.minHeight,
709
+ paddingHorizontal: sizeStyles.paddingHorizontal,
710
+ paddingVertical: sizeStyles.paddingVertical
711
+ },
712
+ radiusStyles,
713
+ variantStyles,
714
+ isDisabled && styles.disabled,
715
+ style
716
+ ],
717
+ accessibilityLabel: labelText ?? (typeof label === "string" ? label : void 0),
718
+ accessibilityRole: "button",
719
+ accessibilityState: { disabled: isDisabled }
720
+ },
721
+ /* @__PURE__ */ React3.createElement(View3, { style: styles.triggerContent }, isLabelInside && renderLabel, /* @__PURE__ */ React3.createElement(
722
+ Text2,
723
+ {
724
+ style: [
725
+ styles.triggerText,
726
+ { fontSize: sizeStyles.fontSize, color: theme.colors.foreground },
727
+ !currentSelectedKey && !currentInputValue && { opacity: 0.5 },
728
+ textStyle
729
+ ],
730
+ numberOfLines: 1,
731
+ ellipsizeMode: "tail"
732
+ },
733
+ displayValue
734
+ )),
735
+ isClearable && (currentSelectedKey || currentInputValue) ? /* @__PURE__ */ React3.createElement(
736
+ TouchableOpacity,
737
+ {
738
+ onPress: handleClear,
739
+ style: styles.clearButton,
740
+ hitSlop: { top: 8, right: 8, bottom: 8, left: 8 }
741
+ },
742
+ clearIcon ?? /* @__PURE__ */ React3.createElement(CloseIcon2, { color: theme.colors.foreground, size: 20 })
743
+ ) : null
744
+ );
745
+ };
746
+
747
+ // src/components/autocomplete/autocomplete.tsx
748
+ var defaultPlaceholder = "Search...";
749
+ var Autocomplete = ({
750
+ children,
751
+ variant = "flat",
752
+ themeColor = "default",
753
+ size = "md",
754
+ radius = "md",
755
+ placeholder = defaultPlaceholder,
756
+ labelPlacement = "outside",
757
+ label,
758
+ description,
759
+ errorMessage,
760
+ clearIcon,
761
+ fullWidth = false,
762
+ isDisabled = false,
763
+ isInvalid = false,
764
+ isClearable = true,
765
+ allowsCustomValue = false,
766
+ forceSelection = false,
767
+ allowsEmptyCollection = true,
768
+ disableLocalFilter = false,
769
+ inputValue,
770
+ defaultInputValue,
771
+ customAppearance,
772
+ onClose,
773
+ onOpenChange,
774
+ onSelectionChange,
775
+ onInputChange,
776
+ onClear
777
+ }) => {
778
+ const { currentSelectedKey, updateSelection } = useAutocompleteSelection({
779
+ onSelectionChange
780
+ });
781
+ const { currentInputValue, updateInputValue } = useAutocompleteInputState({
782
+ inputValue,
783
+ defaultInputValue,
784
+ selectedKey: currentSelectedKey,
785
+ onInputChange
786
+ });
787
+ const { isOpen, setOpen } = useAutocompleteOpenState({
788
+ isOpened: void 0,
789
+ isDisabled,
790
+ onOpenChange,
791
+ onClose
792
+ });
793
+ const triggerRef = useRef3(null);
794
+ const [triggerLayout, setTriggerLayout] = useState3();
795
+ const handleTriggerLayout = useCallback3(() => {
796
+ triggerRef.current?.measureInWindow((x, y, width, height) => {
797
+ setTriggerLayout({ x, y, width, height });
798
+ });
799
+ }, []);
800
+ const items = useMemo3(() => {
801
+ const elements = React4.Children.toArray(children).filter(Boolean);
802
+ return elements.map((child, index) => {
803
+ if (!React4.isValidElement(child)) {
804
+ return null;
805
+ }
806
+ const key = child.props.value ?? String(index);
807
+ const labelText = getTextValue(child.props.label) ?? key;
808
+ return {
809
+ key,
810
+ element: child,
811
+ labelText
812
+ };
813
+ }).filter((item) => item !== null);
814
+ }, [children]);
815
+ const filteredItems = useMemo3(() => {
816
+ if (disableLocalFilter || !currentInputValue.trim()) {
817
+ return items;
818
+ }
819
+ return items.filter(
820
+ (item) => defaultFilterFunction(item.labelText, currentInputValue)
821
+ );
822
+ }, [disableLocalFilter, items, currentInputValue]);
823
+ const theme = useXUITheme();
824
+ const sizeStyles = useAutocompleteSizeStyles(size);
825
+ const { radiusStyles } = useAutocompleteRadiusStyles(radius);
826
+ const variantStyles = useAutocompleteVariantStyles(themeColor, variant, isInvalid);
827
+ const labelStyle = useAutocompleteLabelStyle(
828
+ themeColor,
829
+ isInvalid,
830
+ sizeStyles.labelSize
831
+ );
832
+ const helperColor = useAutocompleteHelperColor(isInvalid);
833
+ const selectedItem = items.find((item) => item.key === currentSelectedKey);
834
+ const displayValue = forceSelection ? selectedItem?.labelText || placeholder : currentInputValue || placeholder;
835
+ const handleInputChange = useCallback3(
836
+ (text) => {
837
+ updateInputValue(text);
838
+ const selectedLabel = selectedItem?.labelText ?? "";
839
+ const shouldClearSelection = !text.trim() && !allowsCustomValue || currentSelectedKey !== null && text !== selectedLabel;
840
+ if (shouldClearSelection) {
841
+ updateSelection(null);
842
+ }
843
+ },
844
+ [
845
+ updateInputValue,
846
+ allowsCustomValue,
847
+ updateSelection,
848
+ selectedItem,
849
+ currentSelectedKey
850
+ ]
851
+ );
852
+ const handleItemSelection = useCallback3(
853
+ (key, itemLabel) => {
854
+ if (isDisabled) {
855
+ return;
856
+ }
857
+ updateSelection(key);
858
+ updateInputValue(itemLabel);
859
+ setTimeout(() => {
860
+ Keyboard2.dismiss();
861
+ setOpen(false);
862
+ }, 50);
863
+ },
864
+ [isDisabled, updateSelection, updateInputValue, setOpen]
865
+ );
866
+ const handleCheckmark = useCallback3(() => {
867
+ setOpen(false);
868
+ }, [setOpen]);
869
+ const handleClear = useCallback3(() => {
870
+ if (isDisabled) {
871
+ return;
872
+ }
873
+ updateSelection(null);
874
+ updateInputValue("");
875
+ onClear?.();
876
+ }, [isDisabled, updateSelection, updateInputValue, onClear]);
877
+ const handleTriggerPress = useCallback3(() => {
878
+ if (!isDisabled) {
879
+ if (selectedItem && !currentInputValue) {
880
+ updateInputValue(selectedItem.labelText);
881
+ }
882
+ setOpen(true);
883
+ }
884
+ }, [isDisabled, setOpen, selectedItem, currentInputValue, updateInputValue]);
885
+ const listItems = filteredItems.map((item) => {
886
+ const itemProps = item.element.props;
887
+ const itemDisabled = isDisabled || itemProps.isDisabled;
888
+ const itemSelected = itemProps.isSelected ?? currentSelectedKey === item.key;
889
+ const handleItemSelected = () => {
890
+ if (itemDisabled || itemProps.isReadOnly) {
891
+ return;
892
+ }
893
+ handleItemSelection(item.key, item.labelText);
894
+ itemProps.onSelected?.();
895
+ };
896
+ return React4.cloneElement(item.element, {
897
+ key: item.key,
898
+ isDisabled: itemDisabled,
899
+ isSelected: itemSelected,
900
+ onSelected: handleItemSelected
901
+ });
902
+ });
903
+ const showEmptyMessage = !allowsEmptyCollection && listItems.length === 0;
904
+ const isLabelInside = labelPlacement === "inside";
905
+ const isLabelOutsideLeft = labelPlacement === "outside-left";
906
+ const isLabelOutside = labelPlacement === "outside" || labelPlacement === "outside-top";
907
+ const renderLabel = label ? typeof label === "string" || typeof label === "number" ? /* @__PURE__ */ React4.createElement(Text3, { style: [styles.label, labelStyle] }, label) : /* @__PURE__ */ React4.createElement(View4, null, label) : null;
908
+ const shouldShowHelper = Boolean(description || errorMessage);
909
+ const helperContent = isInvalid && errorMessage ? errorMessage : description;
910
+ const triggerContent = /* @__PURE__ */ React4.createElement(
911
+ AutocompleteTrigger,
912
+ {
913
+ triggerRef,
914
+ isDisabled,
915
+ currentSelectedKey,
916
+ currentInputValue,
917
+ displayValue,
918
+ sizeStyles,
919
+ radiusStyles,
920
+ variantStyles,
921
+ theme,
922
+ isClearable,
923
+ label: renderLabel,
924
+ labelText: typeof label === "string" ? label : void 0,
925
+ isLabelInside,
926
+ clearIcon,
927
+ style: customAppearance?.container,
928
+ textStyle: customAppearance?.text,
929
+ onPress: handleTriggerPress,
930
+ onClear: handleClear,
931
+ onLayout: handleTriggerLayout
932
+ }
933
+ );
934
+ const labelBlock = isLabelOutside || isLabelInside ? renderLabel : null;
935
+ return /* @__PURE__ */ React4.createElement(View4, { style: [styles.container, fullWidth ? styles.fullWidth : styles.minWidth] }, isLabelOutside && labelBlock, isLabelOutsideLeft ? /* @__PURE__ */ React4.createElement(View4, { style: styles.outsideLeftRow }, renderLabel, triggerContent) : triggerContent, shouldShowHelper && helperContent ? typeof helperContent === "string" || typeof helperContent === "number" ? /* @__PURE__ */ React4.createElement(Text3, { style: [styles.helperText, { color: helperColor }] }, helperContent) : /* @__PURE__ */ React4.createElement(View4, null, helperContent) : null, /* @__PURE__ */ React4.createElement(
936
+ AutocompleteDialog,
937
+ {
938
+ visible: isOpen,
939
+ inputValue: currentInputValue,
940
+ placeholder,
941
+ title: typeof label === "string" ? label : void 0,
942
+ themeColor,
943
+ _triggerLayout: triggerLayout,
944
+ showCheckmark: false,
945
+ onInputChange: handleInputChange,
946
+ onClose: () => setOpen(false),
947
+ onCheckmark: handleCheckmark
948
+ },
949
+ /* @__PURE__ */ React4.createElement(AutocompleteContext.Provider, { value: { size, themeColor, isDisabled } }, showEmptyMessage ? /* @__PURE__ */ React4.createElement(Text3, { style: [styles.emptyMessage, { color: theme.colors.foreground }] }, "No results found") : listItems)
950
+ ));
951
+ };
952
+
953
+ // src/components/autocomplete/autocomplete-item.tsx
954
+ import React5, { useContext as useContext2 } from "react";
955
+ import { Pressable as Pressable4, Text as Text4, View as View5 } from "react-native";
956
+
957
+ // src/components/autocomplete/autocomplete-item.style.ts
958
+ import { StyleSheet as StyleSheet3 } from "react-native";
959
+ var styles3 = StyleSheet3.create({
960
+ item: {
961
+ flexDirection: "row",
962
+ alignItems: "center",
963
+ gap: 8
964
+ },
965
+ content: {
966
+ flex: 1,
967
+ gap: 2
968
+ },
969
+ title: {
970
+ fontWeight: "500"
971
+ },
972
+ description: {
973
+ opacity: 0.7
974
+ },
975
+ disabled: {
976
+ opacity: 0.5
977
+ }
978
+ });
979
+
980
+ // src/components/autocomplete/autocomplete-item.hook.ts
981
+ import { useContext, useMemo as useMemo4 } from "react";
982
+ import { getSafeThemeColor as getSafeThemeColor2 } from "@xaui/core";
983
+ var useAutocompleteItemSizeStyles = (size) => {
984
+ const theme = useXUITheme();
985
+ return useMemo4(() => {
986
+ const sizes = {
987
+ xs: {
988
+ paddingVertical: theme.spacing.sm,
989
+ paddingHorizontal: theme.spacing.sm,
990
+ titleSize: theme.fontSizes.xs,
991
+ descriptionSize: theme.fontSizes.xs
992
+ },
993
+ sm: {
994
+ paddingVertical: theme.spacing.sm,
995
+ paddingHorizontal: theme.spacing.sm,
996
+ titleSize: theme.fontSizes.sm,
997
+ descriptionSize: theme.fontSizes.xs
998
+ },
999
+ md: {
1000
+ paddingVertical: theme.spacing.sm,
1001
+ paddingHorizontal: theme.spacing.sm,
1002
+ titleSize: theme.fontSizes.md,
1003
+ descriptionSize: theme.fontSizes.xs
1004
+ },
1005
+ lg: {
1006
+ paddingVertical: theme.spacing.sm,
1007
+ paddingHorizontal: theme.spacing.sm,
1008
+ titleSize: theme.fontSizes.lg,
1009
+ descriptionSize: theme.fontSizes.md
1010
+ }
1011
+ };
1012
+ return sizes[size];
1013
+ }, [size, theme]);
1014
+ };
1015
+ var useAutocompleteItemBackgroundColor = (themeColor, isSelected) => {
1016
+ const theme = useXUITheme();
1017
+ const safeThemeColor = getSafeThemeColor2(themeColor);
1018
+ const colorScheme = theme.colors[safeThemeColor];
1019
+ return useMemo4(() => {
1020
+ return "transparent";
1021
+ }, [isSelected, colorScheme]);
1022
+ };
1023
+ var useAutocompleteItemTextColors = () => {
1024
+ const theme = useXUITheme();
1025
+ return useMemo4(() => {
1026
+ return {
1027
+ textColor: theme.colors.foreground,
1028
+ descriptionColor: theme.colors.foreground
1029
+ };
1030
+ }, [theme]);
1031
+ };
1032
+ var useAutocompleteItemCheckmarkColor = (themeColor) => {
1033
+ const theme = useXUITheme();
1034
+ const safeThemeColor = getSafeThemeColor2(themeColor);
1035
+ const colorScheme = theme.colors[safeThemeColor];
1036
+ return useMemo4(() => {
1037
+ if (themeColor === "default") {
1038
+ return theme.colors.primary.main;
1039
+ }
1040
+ return colorScheme.main;
1041
+ }, [themeColor, colorScheme, theme]);
1042
+ };
1043
+ var useAutocompleteItemStyles = (isSelected, _isDisabled) => {
1044
+ const context = useContext(AutocompleteContext);
1045
+ const backgroundColor = useAutocompleteItemBackgroundColor(
1046
+ context.themeColor,
1047
+ isSelected
1048
+ );
1049
+ const { textColor, descriptionColor } = useAutocompleteItemTextColors();
1050
+ const checkmarkColor = useAutocompleteItemCheckmarkColor(context.themeColor);
1051
+ return {
1052
+ backgroundColor,
1053
+ labelColor: textColor,
1054
+ descriptionColor,
1055
+ checkmarkColor
1056
+ };
1057
+ };
1058
+
1059
+ // src/components/autocomplete/autocomplete-item.tsx
1060
+ var defaultSize = "md";
1061
+ var AutocompleteItem = ({
1062
+ label,
1063
+ description,
1064
+ startContent,
1065
+ endContent,
1066
+ selectedIcon: _selectedIcon,
1067
+ isDisabled = false,
1068
+ isSelected = false,
1069
+ isReadOnly = false,
1070
+ customAppearance,
1071
+ onSelected
1072
+ }) => {
1073
+ const context = useContext2(AutocompleteContext);
1074
+ const size = context?.size ?? defaultSize;
1075
+ const isItemDisabled = context?.isDisabled ? true : isDisabled;
1076
+ const sizeStyles = useAutocompleteItemSizeStyles(size);
1077
+ const { backgroundColor, labelColor, descriptionColor } = useAutocompleteItemStyles(isSelected, isItemDisabled);
1078
+ const handlePress = () => {
1079
+ if (isItemDisabled || isReadOnly) {
1080
+ return;
1081
+ }
1082
+ onSelected?.();
1083
+ };
1084
+ return /* @__PURE__ */ React5.createElement(
1085
+ Pressable4,
1086
+ {
1087
+ onPress: handlePress,
1088
+ disabled: isItemDisabled,
1089
+ style: [
1090
+ styles3.item,
1091
+ {
1092
+ paddingVertical: sizeStyles.paddingVertical,
1093
+ paddingHorizontal: sizeStyles.paddingHorizontal,
1094
+ backgroundColor
1095
+ },
1096
+ isItemDisabled && styles3.disabled,
1097
+ customAppearance?.container
1098
+ ]
1099
+ },
1100
+ startContent,
1101
+ /* @__PURE__ */ React5.createElement(View5, { style: styles3.content }, /* @__PURE__ */ React5.createElement(
1102
+ Text4,
1103
+ {
1104
+ style: [
1105
+ styles3.title,
1106
+ { fontSize: sizeStyles.titleSize, color: labelColor },
1107
+ customAppearance?.text
1108
+ ]
1109
+ },
1110
+ label
1111
+ ), description && /* @__PURE__ */ React5.createElement(
1112
+ Text4,
1113
+ {
1114
+ style: [
1115
+ styles3.description,
1116
+ { fontSize: sizeStyles.descriptionSize, color: descriptionColor }
1117
+ ]
1118
+ },
1119
+ description
1120
+ )),
1121
+ endContent
1122
+ );
1123
+ };
7
1124
  export {
8
1125
  Autocomplete,
9
1126
  AutocompleteItem