@boostdev/design-system-react-native 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,4421 @@
1
+ // src/native/ThemeContext.tsx
2
+ import { createContext, useContext, useMemo } from "react";
3
+ import { useColorScheme } from "react-native";
4
+
5
+ // src/native/tokens.ts
6
+ import { colors, spacing, font, border, zIndex, animation } from "@boostdev/design-system-foundation/native";
7
+ var lineHeight = {
8
+ display: Math.round(font.size.display * font.lineHeight.display),
9
+ heading1: Math.round(font.size.heading1 * font.lineHeight.heading),
10
+ heading2: Math.round(font.size.heading2 * font.lineHeight.heading),
11
+ heading3: Math.round(font.size.heading3 * font.lineHeight.heading),
12
+ body: Math.round(font.size.body * font.lineHeight.body),
13
+ bodyS: Math.round(font.size.bodyS * font.lineHeight.body)
14
+ };
15
+
16
+ // src/native/ThemeContext.tsx
17
+ import { jsx } from "react/jsx-runtime";
18
+ var ThemeContext = createContext(null);
19
+ function ThemeProvider({ children, colorScheme }) {
20
+ const systemScheme = useColorScheme();
21
+ const isDark = (colorScheme ?? systemScheme) === "dark";
22
+ const value = useMemo(
23
+ () => ({ colors: isDark ? colors.dark : colors.light, isDark }),
24
+ [isDark]
25
+ );
26
+ return /* @__PURE__ */ jsx(ThemeContext.Provider, { value, children });
27
+ }
28
+ function useTheme() {
29
+ const ctx = useContext(ThemeContext);
30
+ if (!ctx) throw new Error("useTheme must be used within ThemeProvider");
31
+ return ctx;
32
+ }
33
+
34
+ // src/components/ui/Typography/Typography.native.tsx
35
+ import { StyleSheet, Text } from "react-native";
36
+ import { jsx as jsx2 } from "react/jsx-runtime";
37
+ var styles = StyleSheet.create({
38
+ base: {
39
+ fontFamily: font.family.body,
40
+ fontWeight: font.weight.body
41
+ },
42
+ h1: {
43
+ fontSize: font.size.heading1,
44
+ fontFamily: font.family.heading,
45
+ fontWeight: font.weight.heading,
46
+ lineHeight: lineHeight.heading1
47
+ },
48
+ h2: {
49
+ fontSize: font.size.heading2,
50
+ fontFamily: font.family.heading,
51
+ fontWeight: font.weight.heading,
52
+ lineHeight: lineHeight.heading2
53
+ },
54
+ h3: {
55
+ fontSize: font.size.heading3,
56
+ fontFamily: font.family.heading,
57
+ fontWeight: font.weight.heading,
58
+ lineHeight: lineHeight.heading3
59
+ },
60
+ body: {
61
+ fontSize: font.size.body,
62
+ lineHeight: lineHeight.body
63
+ },
64
+ body_s: {
65
+ fontSize: font.size.bodyS,
66
+ lineHeight: lineHeight.bodyS
67
+ }
68
+ });
69
+ var accessibilityRoles = {
70
+ h1: "header",
71
+ h2: "header",
72
+ h3: "header",
73
+ body: "text",
74
+ body_s: "text"
75
+ };
76
+ function Typography({ variant = "body", children, style }) {
77
+ const { colors: colors2 } = useTheme();
78
+ return /* @__PURE__ */ jsx2(
79
+ Text,
80
+ {
81
+ accessibilityRole: accessibilityRoles[variant],
82
+ style: [styles.base, styles[variant], { color: colors2.colorOnBg }, style],
83
+ children
84
+ }
85
+ );
86
+ }
87
+
88
+ // src/components/ui/Badge/Badge.native.tsx
89
+ import { StyleSheet as StyleSheet2, View, Text as Text2 } from "react-native";
90
+ import { jsx as jsx3 } from "react/jsx-runtime";
91
+ var styles2 = StyleSheet2.create({
92
+ badge: {
93
+ alignSelf: "flex-start",
94
+ flexDirection: "row",
95
+ alignItems: "center",
96
+ justifyContent: "center",
97
+ paddingVertical: spacing.xxs,
98
+ paddingHorizontal: spacing.xs,
99
+ borderRadius: border.radius.full
100
+ },
101
+ text: {
102
+ fontSize: font.size.bodyS,
103
+ fontFamily: font.family.body,
104
+ fontWeight: font.weight.semibold,
105
+ lineHeight: font.size.bodyS
106
+ }
107
+ });
108
+ function Badge({ children, variant = "primary", style }) {
109
+ const { colors: colors2 } = useTheme();
110
+ const variantColors = {
111
+ primary: { bg: colors2.colorInteractive, text: colors2.colorOnInteractive },
112
+ secondary: { bg: colors2.colorBgSubtle, text: colors2.colorOnBgSubtle },
113
+ success: { bg: colors2.colorSuccess, text: colors2.colorOnSuccess },
114
+ error: { bg: colors2.colorError, text: colors2.colorOnError },
115
+ warning: { bg: colors2.colorWarning, text: colors2.colorOnWarning }
116
+ };
117
+ const { bg, text } = variantColors[variant];
118
+ return /* @__PURE__ */ jsx3(View, { style: [styles2.badge, { backgroundColor: bg }, style], children: /* @__PURE__ */ jsx3(Text2, { style: [styles2.text, { color: text }], children }) });
119
+ }
120
+
121
+ // src/components/ui/Avatar/Avatar.native.tsx
122
+ import { StyleSheet as StyleSheet3, View as View2, Text as Text3, Image } from "react-native";
123
+ import { jsx as jsx4 } from "react/jsx-runtime";
124
+ var sizeMap = {
125
+ small: { container: 32, fontSize: font.size.bodyS },
126
+ medium: { container: 48, fontSize: font.size.body },
127
+ large: { container: 72, fontSize: font.size.heading3 }
128
+ };
129
+ function getInitials(name) {
130
+ return name.split(" ").filter(Boolean).slice(0, 2).map((word) => word[0].toUpperCase()).join("");
131
+ }
132
+ var styles3 = StyleSheet3.create({
133
+ container: {
134
+ borderRadius: border.radius.full,
135
+ overflow: "hidden",
136
+ alignItems: "center",
137
+ justifyContent: "center"
138
+ },
139
+ image: {
140
+ width: "100%",
141
+ height: "100%"
142
+ },
143
+ initials: {
144
+ fontFamily: font.family.body,
145
+ fontWeight: font.weight.semibold
146
+ }
147
+ });
148
+ function Avatar({ src, alt, name, size = "medium", style }) {
149
+ const { colors: colors2 } = useTheme();
150
+ const { container, fontSize } = sizeMap[size];
151
+ const label = alt ?? name ?? "User avatar";
152
+ if (src) {
153
+ return /* @__PURE__ */ jsx4(
154
+ View2,
155
+ {
156
+ style: [styles3.container, { width: container, height: container }, style],
157
+ accessibilityLabel: label,
158
+ accessibilityRole: "image",
159
+ children: /* @__PURE__ */ jsx4(Image, { source: { uri: src }, style: styles3.image })
160
+ }
161
+ );
162
+ }
163
+ const initials = name ? getInitials(name) : "";
164
+ return /* @__PURE__ */ jsx4(
165
+ View2,
166
+ {
167
+ style: [
168
+ styles3.container,
169
+ { width: container, height: container, backgroundColor: colors2.colorBlue },
170
+ style
171
+ ],
172
+ accessibilityLabel: label,
173
+ accessibilityRole: "image",
174
+ children: /* @__PURE__ */ jsx4(
175
+ Text3,
176
+ {
177
+ style: [styles3.initials, { fontSize, color: colors2.colorOnBlue }],
178
+ importantForAccessibility: "no",
179
+ accessibilityElementsHidden: true,
180
+ children: initials
181
+ }
182
+ )
183
+ }
184
+ );
185
+ }
186
+
187
+ // src/components/ui/Separator/Separator.native.tsx
188
+ import { StyleSheet as StyleSheet4, View as View3 } from "react-native";
189
+ import { jsx as jsx5 } from "react/jsx-runtime";
190
+ var styles4 = StyleSheet4.create({
191
+ horizontal: {
192
+ height: StyleSheet4.hairlineWidth,
193
+ width: "100%"
194
+ },
195
+ vertical: {
196
+ width: StyleSheet4.hairlineWidth,
197
+ alignSelf: "stretch"
198
+ }
199
+ });
200
+ function Separator({ orientation = "horizontal", style }) {
201
+ const { colors: colors2 } = useTheme();
202
+ return /* @__PURE__ */ jsx5(
203
+ View3,
204
+ {
205
+ accessibilityRole: "none",
206
+ style: [
207
+ orientation === "vertical" ? styles4.vertical : styles4.horizontal,
208
+ { backgroundColor: colors2.colorBgSubtle },
209
+ style
210
+ ]
211
+ }
212
+ );
213
+ }
214
+
215
+ // src/components/ui/Loading/Loading.native.tsx
216
+ import { ActivityIndicator } from "react-native";
217
+ import { jsx as jsx6 } from "react/jsx-runtime";
218
+ var rnSize = {
219
+ small: "small",
220
+ medium: "large",
221
+ large: "large"
222
+ };
223
+ function Loading({ size = "medium", accessibilityLabel = "Loading", style }) {
224
+ const { colors: colors2 } = useTheme();
225
+ return /* @__PURE__ */ jsx6(
226
+ ActivityIndicator,
227
+ {
228
+ size: rnSize[size],
229
+ color: colors2.colorInteractive,
230
+ style,
231
+ accessibilityRole: "progressbar",
232
+ accessibilityLabel
233
+ }
234
+ );
235
+ }
236
+
237
+ // src/components/ui/Progress/Progress.native.tsx
238
+ import { StyleSheet as StyleSheet5, View as View4, Text as Text4 } from "react-native";
239
+ import { jsx as jsx7, jsxs } from "react/jsx-runtime";
240
+ var trackHeight = {
241
+ small: 4,
242
+ medium: 8,
243
+ large: 12
244
+ };
245
+ var styles5 = StyleSheet5.create({
246
+ container: {
247
+ width: "100%"
248
+ },
249
+ labelRow: {
250
+ flexDirection: "row",
251
+ justifyContent: "space-between",
252
+ marginBottom: spacing.xxs
253
+ },
254
+ labelText: {
255
+ fontSize: font.size.bodyS,
256
+ fontFamily: font.family.body,
257
+ lineHeight: lineHeight.bodyS
258
+ },
259
+ track: {
260
+ width: "100%",
261
+ borderRadius: border.radius.full,
262
+ overflow: "hidden"
263
+ },
264
+ fill: {
265
+ height: "100%",
266
+ borderRadius: border.radius.full
267
+ }
268
+ });
269
+ function Progress({
270
+ value,
271
+ max = 100,
272
+ label,
273
+ showLabel = false,
274
+ size = "medium",
275
+ style
276
+ }) {
277
+ const { colors: colors2 } = useTheme();
278
+ const percentage = Math.min(100, Math.max(0, value / max * 100));
279
+ const height = trackHeight[size];
280
+ return /* @__PURE__ */ jsxs(View4, { style: [styles5.container, style], children: [
281
+ showLabel && /* @__PURE__ */ jsxs(View4, { style: styles5.labelRow, children: [
282
+ /* @__PURE__ */ jsx7(Text4, { style: [styles5.labelText, { color: colors2.colorOnBg }], children: label }),
283
+ /* @__PURE__ */ jsxs(Text4, { style: [styles5.labelText, { color: colors2.colorOnBgSubtle }], children: [
284
+ Math.round(percentage),
285
+ "%"
286
+ ] })
287
+ ] }),
288
+ /* @__PURE__ */ jsx7(
289
+ View4,
290
+ {
291
+ style: [styles5.track, { height, backgroundColor: colors2.colorBgSubtle }],
292
+ accessibilityRole: "progressbar",
293
+ accessibilityLabel: label,
294
+ accessibilityValue: { min: 0, max, now: value },
295
+ children: /* @__PURE__ */ jsx7(
296
+ View4,
297
+ {
298
+ style: [
299
+ styles5.fill,
300
+ { width: `${percentage}%`, backgroundColor: colors2.colorInteractive }
301
+ ]
302
+ }
303
+ )
304
+ }
305
+ )
306
+ ] });
307
+ }
308
+
309
+ // src/components/ui/Skeleton/Skeleton.native.tsx
310
+ import { useEffect, useRef } from "react";
311
+ import { Animated, StyleSheet as StyleSheet6 } from "react-native";
312
+ import { jsx as jsx8 } from "react/jsx-runtime";
313
+ var styles6 = StyleSheet6.create({
314
+ skeleton: {
315
+ borderRadius: border.radius.xs,
316
+ overflow: "hidden"
317
+ }
318
+ });
319
+ function Skeleton({ style }) {
320
+ const { colors: colors2 } = useTheme();
321
+ const opacity = useRef(new Animated.Value(1)).current;
322
+ useEffect(() => {
323
+ const anim = Animated.loop(
324
+ Animated.sequence([
325
+ Animated.timing(opacity, { toValue: 0.4, duration: 700, useNativeDriver: true }),
326
+ Animated.timing(opacity, { toValue: 1, duration: 700, useNativeDriver: true })
327
+ ])
328
+ );
329
+ anim.start();
330
+ return () => anim.stop();
331
+ }, [opacity]);
332
+ return /* @__PURE__ */ jsx8(
333
+ Animated.View,
334
+ {
335
+ importantForAccessibility: "no-hide-descendants",
336
+ style: [
337
+ styles6.skeleton,
338
+ { backgroundColor: colors2.colorBgSubtle, opacity },
339
+ style
340
+ ]
341
+ }
342
+ );
343
+ }
344
+
345
+ // src/components/ui/Alert/Alert.native.tsx
346
+ import { StyleSheet as StyleSheet7, View as View5, Text as Text5, Pressable } from "react-native";
347
+ import { jsx as jsx9, jsxs as jsxs2 } from "react/jsx-runtime";
348
+ var styles7 = StyleSheet7.create({
349
+ alert: {
350
+ flexDirection: "row",
351
+ alignItems: "flex-start",
352
+ padding: spacing.m,
353
+ borderRadius: border.radius.s,
354
+ gap: spacing.xs
355
+ },
356
+ icon: {
357
+ flexShrink: 0,
358
+ marginTop: 2
359
+ },
360
+ content: {
361
+ flex: 1,
362
+ gap: spacing.xxs
363
+ },
364
+ title: {
365
+ fontSize: font.size.body,
366
+ fontFamily: font.family.body,
367
+ fontWeight: font.weight.semibold,
368
+ lineHeight: lineHeight.body
369
+ },
370
+ body: {
371
+ fontSize: font.size.bodyS,
372
+ fontFamily: font.family.body,
373
+ lineHeight: lineHeight.bodyS
374
+ },
375
+ dismiss: {
376
+ padding: spacing.xxs,
377
+ flexShrink: 0
378
+ }
379
+ });
380
+ function Alert({
381
+ variant = "info",
382
+ icon,
383
+ title,
384
+ children,
385
+ onDismiss,
386
+ style
387
+ }) {
388
+ const { colors: colors2 } = useTheme();
389
+ const isUrgent = variant === "error" || variant === "warning";
390
+ const variantColors = {
391
+ info: { bg: colors2.colorBlueSubtle, text: colors2.colorOnBlueSubtle, border: colors2.colorBlue },
392
+ success: { bg: colors2.colorSuccessSubtle, text: colors2.colorOnSuccessSubtle, border: colors2.colorSuccess },
393
+ warning: { bg: colors2.colorOrangeSubtle, text: colors2.colorOnOrangeSubtle, border: colors2.colorWarning },
394
+ error: { bg: colors2.colorRedSubtle, text: colors2.colorOnBg, border: colors2.colorError }
395
+ };
396
+ const { bg, text, border: borderColor } = variantColors[variant];
397
+ return /* @__PURE__ */ jsxs2(
398
+ View5,
399
+ {
400
+ accessibilityRole: isUrgent ? "alert" : "none",
401
+ accessibilityLiveRegion: isUrgent ? "assertive" : "polite",
402
+ style: [styles7.alert, { backgroundColor: bg, borderStartWidth: spacing.s, borderStartColor: borderColor }, style],
403
+ children: [
404
+ icon && /* @__PURE__ */ jsx9(View5, { style: styles7.icon, children: icon }),
405
+ /* @__PURE__ */ jsxs2(View5, { style: styles7.content, children: [
406
+ title && /* @__PURE__ */ jsx9(Text5, { style: [styles7.title, { color: text }], children: title }),
407
+ /* @__PURE__ */ jsx9(Text5, { style: [styles7.body, { color: text }], children })
408
+ ] }),
409
+ onDismiss && /* @__PURE__ */ jsx9(
410
+ Pressable,
411
+ {
412
+ onPress: onDismiss,
413
+ style: styles7.dismiss,
414
+ accessibilityLabel: "Dismiss alert",
415
+ accessibilityRole: "button",
416
+ hitSlop: 8,
417
+ children: /* @__PURE__ */ jsx9(Text5, { style: { color: text, fontSize: 16 }, children: "\u2715" })
418
+ }
419
+ )
420
+ ]
421
+ }
422
+ );
423
+ }
424
+
425
+ // src/components/ui/NotificationBanner/NotificationBanner.native.tsx
426
+ import { StyleSheet as StyleSheet8, View as View6, Text as Text6, Pressable as Pressable2 } from "react-native";
427
+ import { jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
428
+ var styles8 = StyleSheet8.create({
429
+ banner: {
430
+ flexDirection: "row",
431
+ alignItems: "center",
432
+ paddingVertical: spacing.s,
433
+ paddingHorizontal: spacing.m,
434
+ gap: spacing.xs
435
+ },
436
+ content: {
437
+ flex: 1,
438
+ fontSize: font.size.bodyS,
439
+ fontFamily: font.family.body,
440
+ lineHeight: lineHeight.bodyS
441
+ },
442
+ dismiss: {
443
+ padding: spacing.xxs,
444
+ flexShrink: 0
445
+ }
446
+ });
447
+ function NotificationBanner({
448
+ variant = "info",
449
+ children,
450
+ action,
451
+ onDismiss,
452
+ style
453
+ }) {
454
+ const { colors: colors2 } = useTheme();
455
+ const isUrgent = variant === "error" || variant === "warning";
456
+ const variantColors = {
457
+ info: { bg: colors2.colorBlueSubtle, text: colors2.colorOnBlueSubtle, border: colors2.colorBlue },
458
+ success: { bg: colors2.colorSuccessSubtle, text: colors2.colorOnSuccessSubtle, border: colors2.colorSuccess },
459
+ warning: { bg: colors2.colorOrangeSubtle, text: colors2.colorOnOrangeSubtle, border: colors2.colorWarning },
460
+ error: { bg: colors2.colorRedSubtle, text: colors2.colorOnBg, border: colors2.colorError }
461
+ };
462
+ const { bg, text, border: borderColor } = variantColors[variant];
463
+ return /* @__PURE__ */ jsxs3(
464
+ View6,
465
+ {
466
+ accessibilityRole: isUrgent ? "alert" : "none",
467
+ accessibilityLiveRegion: isUrgent ? "assertive" : "polite",
468
+ style: [styles8.banner, { backgroundColor: bg, borderBottomWidth: 3, borderBottomColor: borderColor }, style],
469
+ children: [
470
+ /* @__PURE__ */ jsx10(Text6, { style: [styles8.content, { color: text }], children }),
471
+ action,
472
+ onDismiss && /* @__PURE__ */ jsx10(
473
+ Pressable2,
474
+ {
475
+ onPress: onDismiss,
476
+ style: styles8.dismiss,
477
+ accessibilityLabel: "Dismiss notification",
478
+ accessibilityRole: "button",
479
+ hitSlop: 8,
480
+ children: /* @__PURE__ */ jsx10(Text6, { style: { color: text, fontSize: 16 }, children: "\u2715" })
481
+ }
482
+ )
483
+ ]
484
+ }
485
+ );
486
+ }
487
+
488
+ // src/components/ui/Link/Link.native.tsx
489
+ import { StyleSheet as StyleSheet9, Text as Text7, Pressable as Pressable3, Linking } from "react-native";
490
+ import { jsx as jsx11 } from "react/jsx-runtime";
491
+ var styles9 = StyleSheet9.create({
492
+ text: {
493
+ fontSize: font.size.body,
494
+ fontFamily: font.family.body,
495
+ textDecorationLine: "underline"
496
+ },
497
+ pressed: {
498
+ opacity: 0.75
499
+ }
500
+ });
501
+ function Link({ href, children, accessibilityLabel, style, onPress }) {
502
+ const { colors: colors2 } = useTheme();
503
+ const handlePress = () => {
504
+ if (onPress) {
505
+ onPress();
506
+ } else if (href) {
507
+ Linking.openURL(href);
508
+ }
509
+ };
510
+ return /* @__PURE__ */ jsx11(
511
+ Pressable3,
512
+ {
513
+ onPress: handlePress,
514
+ accessibilityRole: "link",
515
+ accessibilityLabel,
516
+ style: ({ pressed }) => pressed && styles9.pressed,
517
+ children: /* @__PURE__ */ jsx11(Text7, { style: [styles9.text, { color: colors2.colorInteractiveOnBg }, style], children })
518
+ }
519
+ );
520
+ }
521
+
522
+ // src/components/ui/DescriptionList/DescriptionList.native.tsx
523
+ import { StyleSheet as StyleSheet10, View as View7, Text as Text8 } from "react-native";
524
+ import { jsx as jsx12, jsxs as jsxs4 } from "react/jsx-runtime";
525
+ var styles10 = StyleSheet10.create({
526
+ list: {
527
+ gap: spacing.m
528
+ },
529
+ group: {
530
+ gap: spacing.xxs
531
+ },
532
+ term: {
533
+ fontSize: font.size.bodyS,
534
+ fontFamily: font.family.body,
535
+ fontWeight: font.weight.semibold,
536
+ lineHeight: lineHeight.bodyS
537
+ },
538
+ description: {
539
+ fontSize: font.size.body,
540
+ fontFamily: font.family.body,
541
+ fontWeight: font.weight.body,
542
+ lineHeight: lineHeight.body
543
+ }
544
+ });
545
+ function DescriptionList({ items, style }) {
546
+ const { colors: colors2 } = useTheme();
547
+ return /* @__PURE__ */ jsx12(View7, { style: [styles10.list, style], accessibilityRole: "list", children: items.map((item, i) => /* @__PURE__ */ jsxs4(View7, { style: styles10.group, accessibilityRole: "listitem", children: [
548
+ /* @__PURE__ */ jsx12(Text8, { style: [styles10.term, { color: colors2.colorOnBgSubtle }], children: item.term }),
549
+ typeof item.description === "string" ? /* @__PURE__ */ jsx12(Text8, { style: [styles10.description, { color: colors2.colorOnBg }], children: item.description }) : /* @__PURE__ */ jsx12(View7, { children: item.description })
550
+ ] }, i)) });
551
+ }
552
+
553
+ // src/components/ui/Breadcrumb/Breadcrumb.native.tsx
554
+ import { StyleSheet as StyleSheet11, View as View8, Text as Text9, Pressable as Pressable4 } from "react-native";
555
+ import { Fragment, jsx as jsx13, jsxs as jsxs5 } from "react/jsx-runtime";
556
+ var styles11 = StyleSheet11.create({
557
+ container: {
558
+ flexDirection: "row",
559
+ flexWrap: "wrap",
560
+ alignItems: "center"
561
+ },
562
+ separator: {
563
+ marginHorizontal: spacing.xs,
564
+ fontSize: font.size.body,
565
+ fontFamily: font.family.body,
566
+ lineHeight: lineHeight.body
567
+ },
568
+ itemText: {
569
+ fontSize: font.size.body,
570
+ fontFamily: font.family.body,
571
+ lineHeight: lineHeight.body
572
+ },
573
+ pressed: {
574
+ opacity: 0.75
575
+ }
576
+ });
577
+ function Breadcrumb({ items, style }) {
578
+ const { colors: colors2 } = useTheme();
579
+ return /* @__PURE__ */ jsx13(
580
+ View8,
581
+ {
582
+ style: [styles11.container, style],
583
+ accessibilityRole: "navigation",
584
+ accessibilityLabel: "Breadcrumb",
585
+ children: items.map((item, index) => {
586
+ const isLast = index === items.length - 1;
587
+ return /* @__PURE__ */ jsx13(View8, { style: { flexDirection: "row", alignItems: "center", minHeight: 44 }, children: isLast ? /* @__PURE__ */ jsx13(
588
+ Text9,
589
+ {
590
+ style: [styles11.itemText, { color: colors2.colorOnBg }],
591
+ accessibilityRole: "text",
592
+ children: item.label
593
+ }
594
+ ) : /* @__PURE__ */ jsxs5(Fragment, { children: [
595
+ /* @__PURE__ */ jsx13(
596
+ Pressable4,
597
+ {
598
+ onPress: item.onPress,
599
+ accessibilityRole: "link",
600
+ style: ({ pressed }) => pressed && styles11.pressed,
601
+ children: /* @__PURE__ */ jsx13(Text9, { style: [styles11.itemText, { color: colors2.colorInteractiveOnBg }], children: item.label })
602
+ }
603
+ ),
604
+ /* @__PURE__ */ jsx13(
605
+ Text9,
606
+ {
607
+ style: [styles11.separator, { color: colors2.colorOnBgSubtle }],
608
+ importantForAccessibility: "no",
609
+ accessibilityElementsHidden: true,
610
+ children: "/"
611
+ }
612
+ )
613
+ ] }) }, index);
614
+ })
615
+ }
616
+ );
617
+ }
618
+
619
+ // src/components/ui/ProgressCircle/ProgressCircle.native.tsx
620
+ import { StyleSheet as StyleSheet12, View as View9, Text as Text10 } from "react-native";
621
+ import { jsx as jsx14, jsxs as jsxs6 } from "react/jsx-runtime";
622
+ var SIZE_PX = {
623
+ small: 40,
624
+ medium: 64,
625
+ large: 96
626
+ };
627
+ var STROKE_WIDTH = {
628
+ small: 3,
629
+ medium: 4,
630
+ large: 5
631
+ };
632
+ var FONT_SIZE = {
633
+ small: font.size.bodyS - 2,
634
+ medium: font.size.bodyS,
635
+ large: font.size.body
636
+ };
637
+ var styles12 = StyleSheet12.create({
638
+ wrapper: {
639
+ alignItems: "center",
640
+ justifyContent: "center"
641
+ },
642
+ valueText: {
643
+ position: "absolute",
644
+ fontFamily: font.family.body,
645
+ fontWeight: font.weight.semibold
646
+ }
647
+ });
648
+ function HalfCircle({
649
+ size,
650
+ stroke,
651
+ color,
652
+ rotation
653
+ }) {
654
+ return /* @__PURE__ */ jsx14(
655
+ View9,
656
+ {
657
+ style: {
658
+ width: size / 2,
659
+ height: size,
660
+ overflow: "hidden"
661
+ },
662
+ children: /* @__PURE__ */ jsx14(
663
+ View9,
664
+ {
665
+ style: {
666
+ width: size,
667
+ height: size,
668
+ borderRadius: size / 2,
669
+ borderWidth: stroke,
670
+ borderColor: color,
671
+ transform: [{ rotate: `${rotation}deg` }]
672
+ }
673
+ }
674
+ )
675
+ }
676
+ );
677
+ }
678
+ function ProgressCircle({
679
+ value,
680
+ max = 100,
681
+ size = "medium",
682
+ label,
683
+ showValue = false,
684
+ style
685
+ }) {
686
+ const { colors: colors2 } = useTheme();
687
+ const percentage = Math.min(100, Math.max(0, value / max * 100));
688
+ const px = SIZE_PX[size];
689
+ const stroke = STROKE_WIDTH[size];
690
+ const fillColor = colors2.colorInteractive;
691
+ const trackColor = colors2.colorBgSubtle;
692
+ const degrees = percentage / 100 * 360;
693
+ return /* @__PURE__ */ jsxs6(
694
+ View9,
695
+ {
696
+ style: [
697
+ styles12.wrapper,
698
+ { width: px, height: px },
699
+ style
700
+ ],
701
+ accessibilityRole: "progressbar",
702
+ accessibilityLabel: label,
703
+ accessibilityValue: { min: 0, max, now: value },
704
+ children: [
705
+ /* @__PURE__ */ jsx14(
706
+ View9,
707
+ {
708
+ style: {
709
+ position: "absolute",
710
+ width: px,
711
+ height: px,
712
+ borderRadius: px / 2,
713
+ borderWidth: stroke,
714
+ borderColor: trackColor
715
+ }
716
+ }
717
+ ),
718
+ /* @__PURE__ */ jsx14(
719
+ View9,
720
+ {
721
+ style: {
722
+ position: "absolute",
723
+ width: px / 2,
724
+ height: px,
725
+ start: px / 2,
726
+ overflow: "hidden"
727
+ },
728
+ children: /* @__PURE__ */ jsx14(
729
+ HalfCircle,
730
+ {
731
+ size: px,
732
+ stroke,
733
+ color: percentage > 0 ? fillColor : "transparent",
734
+ rotation: Math.min(degrees, 180) - 180
735
+ }
736
+ )
737
+ }
738
+ ),
739
+ degrees > 180 && /* @__PURE__ */ jsx14(
740
+ View9,
741
+ {
742
+ style: {
743
+ position: "absolute",
744
+ width: px / 2,
745
+ height: px,
746
+ start: 0,
747
+ overflow: "hidden"
748
+ },
749
+ children: /* @__PURE__ */ jsx14(
750
+ View9,
751
+ {
752
+ style: {
753
+ position: "absolute",
754
+ end: 0
755
+ },
756
+ children: /* @__PURE__ */ jsx14(
757
+ HalfCircle,
758
+ {
759
+ size: px,
760
+ stroke,
761
+ color: fillColor,
762
+ rotation: Math.min(degrees - 180, 180)
763
+ }
764
+ )
765
+ }
766
+ )
767
+ }
768
+ ),
769
+ showValue && /* @__PURE__ */ jsxs6(
770
+ Text10,
771
+ {
772
+ style: [styles12.valueText, { fontSize: FONT_SIZE[size], color: colors2.colorOnBg }],
773
+ importantForAccessibility: "no",
774
+ accessibilityElementsHidden: true,
775
+ children: [
776
+ Math.round(percentage),
777
+ "%"
778
+ ]
779
+ }
780
+ )
781
+ ]
782
+ }
783
+ );
784
+ }
785
+
786
+ // src/components/ui/Tooltip/Tooltip.native.tsx
787
+ import { useState } from "react";
788
+ import { StyleSheet as StyleSheet13, View as View10, Text as Text11, Pressable as Pressable5 } from "react-native";
789
+ import { jsx as jsx15, jsxs as jsxs7 } from "react/jsx-runtime";
790
+ var styles13 = StyleSheet13.create({
791
+ wrapper: {
792
+ position: "relative"
793
+ },
794
+ tooltip: {
795
+ position: "absolute",
796
+ bottom: "100%",
797
+ start: 0,
798
+ marginBottom: spacing.xxs,
799
+ paddingVertical: spacing.xxs,
800
+ paddingHorizontal: spacing.xs,
801
+ borderRadius: border.radius.full,
802
+ zIndex: 10,
803
+ alignSelf: "flex-start"
804
+ },
805
+ text: {
806
+ fontSize: font.size.bodyS,
807
+ fontFamily: font.family.body
808
+ }
809
+ });
810
+ function Tooltip({ content, children, style }) {
811
+ const { colors: colors2 } = useTheme();
812
+ const [visible, setVisible] = useState(false);
813
+ return /* @__PURE__ */ jsxs7(View10, { style: [styles13.wrapper, style], children: [
814
+ /* @__PURE__ */ jsx15(
815
+ Pressable5,
816
+ {
817
+ onLongPress: () => setVisible(true),
818
+ onPressOut: () => setVisible(false),
819
+ accessibilityHint: content,
820
+ children
821
+ }
822
+ ),
823
+ visible && /* @__PURE__ */ jsx15(
824
+ View10,
825
+ {
826
+ style: [styles13.tooltip, { backgroundColor: colors2.colorOnBg }],
827
+ accessibilityRole: "text",
828
+ accessibilityLabel: content,
829
+ children: /* @__PURE__ */ jsx15(Text11, { style: [styles13.text, { color: colors2.colorBg }], children: content })
830
+ }
831
+ )
832
+ ] });
833
+ }
834
+
835
+ // src/components/ui/Pagination/Pagination.native.tsx
836
+ import { StyleSheet as StyleSheet14, View as View11, Text as Text12, Pressable as Pressable6 } from "react-native";
837
+ import { jsx as jsx16, jsxs as jsxs8 } from "react/jsx-runtime";
838
+ function getPageRange(current, total) {
839
+ const delta = 1;
840
+ const range = [];
841
+ for (let i = 1; i <= total; i++) {
842
+ if (i === 1 || i === total || i >= current - delta && i <= current + delta) {
843
+ range.push(i);
844
+ } else if (range[range.length - 1] !== "...") {
845
+ range.push("...");
846
+ }
847
+ }
848
+ return range;
849
+ }
850
+ var styles14 = StyleSheet14.create({
851
+ container: {
852
+ flexDirection: "row",
853
+ alignItems: "center",
854
+ gap: spacing.xxs
855
+ },
856
+ button: {
857
+ minWidth: 44,
858
+ minHeight: 44,
859
+ alignItems: "center",
860
+ justifyContent: "center",
861
+ borderRadius: border.radius.full,
862
+ paddingHorizontal: spacing.xs,
863
+ paddingVertical: spacing.xxs
864
+ },
865
+ buttonText: {
866
+ fontSize: font.size.body,
867
+ fontFamily: font.family.body,
868
+ lineHeight: lineHeight.body,
869
+ fontWeight: font.weight.body
870
+ },
871
+ navText: {
872
+ fontSize: font.size.body,
873
+ fontFamily: font.family.body,
874
+ lineHeight: lineHeight.body,
875
+ fontWeight: font.weight.semibold
876
+ },
877
+ ellipsis: {
878
+ fontSize: font.size.body,
879
+ fontFamily: font.family.body,
880
+ lineHeight: lineHeight.body,
881
+ minWidth: 44,
882
+ minHeight: 44,
883
+ textAlign: "center",
884
+ textAlignVertical: "center"
885
+ },
886
+ pressed: {
887
+ opacity: 0.75
888
+ },
889
+ disabled: {
890
+ opacity: 0.4
891
+ }
892
+ });
893
+ function Pagination({
894
+ currentPage,
895
+ totalPages,
896
+ onPageChange,
897
+ style
898
+ }) {
899
+ const { colors: colors2 } = useTheme();
900
+ const pages = getPageRange(currentPage, totalPages);
901
+ return /* @__PURE__ */ jsxs8(
902
+ View11,
903
+ {
904
+ style: [styles14.container, style],
905
+ accessibilityRole: "navigation",
906
+ accessibilityLabel: "Pagination",
907
+ children: [
908
+ /* @__PURE__ */ jsx16(
909
+ Pressable6,
910
+ {
911
+ onPress: () => onPageChange(currentPage - 1),
912
+ disabled: currentPage <= 1,
913
+ accessibilityRole: "button",
914
+ accessibilityLabel: "Previous page",
915
+ accessibilityState: { disabled: currentPage <= 1 },
916
+ style: ({ pressed }) => [
917
+ styles14.button,
918
+ currentPage <= 1 && styles14.disabled,
919
+ pressed && !currentPage && styles14.pressed
920
+ ],
921
+ children: /* @__PURE__ */ jsx16(Text12, { style: [styles14.navText, { color: colors2.colorOnBg }], children: "\u2039" })
922
+ }
923
+ ),
924
+ pages.map(
925
+ (page, index) => page === "..." ? /* @__PURE__ */ jsx16(
926
+ Text12,
927
+ {
928
+ style: [styles14.ellipsis, { color: colors2.colorOnBgSubtle }],
929
+ importantForAccessibility: "no",
930
+ accessibilityElementsHidden: true,
931
+ children: "..."
932
+ },
933
+ `ellipsis-${index}`
934
+ ) : /* @__PURE__ */ jsx16(
935
+ Pressable6,
936
+ {
937
+ onPress: () => onPageChange(page),
938
+ accessibilityRole: "button",
939
+ accessibilityLabel: `Page ${page}`,
940
+ accessibilityState: { selected: currentPage === page },
941
+ style: ({ pressed }) => [
942
+ styles14.button,
943
+ currentPage === page && { backgroundColor: colors2.colorInteractive },
944
+ pressed && styles14.pressed
945
+ ],
946
+ children: /* @__PURE__ */ jsx16(
947
+ Text12,
948
+ {
949
+ style: [
950
+ styles14.buttonText,
951
+ {
952
+ color: currentPage === page ? colors2.colorOnInteractive : colors2.colorOnBg
953
+ },
954
+ currentPage === page && { fontWeight: font.weight.semibold }
955
+ ],
956
+ children: page
957
+ }
958
+ )
959
+ },
960
+ page
961
+ )
962
+ ),
963
+ /* @__PURE__ */ jsx16(
964
+ Pressable6,
965
+ {
966
+ onPress: () => onPageChange(currentPage + 1),
967
+ disabled: currentPage >= totalPages,
968
+ accessibilityRole: "button",
969
+ accessibilityLabel: "Next page",
970
+ accessibilityState: { disabled: currentPage >= totalPages },
971
+ style: ({ pressed }) => [
972
+ styles14.button,
973
+ currentPage >= totalPages && styles14.disabled,
974
+ pressed && styles14.pressed
975
+ ],
976
+ children: /* @__PURE__ */ jsx16(Text12, { style: [styles14.navText, { color: colors2.colorOnBg }], children: "\u203A" })
977
+ }
978
+ )
979
+ ]
980
+ }
981
+ );
982
+ }
983
+
984
+ // src/components/ui/Collapsible/Collapsible.native.tsx
985
+ import { useCallback, useRef as useRef2, useState as useState2 } from "react";
986
+ import {
987
+ StyleSheet as StyleSheet15,
988
+ View as View12,
989
+ Text as Text13,
990
+ Pressable as Pressable7,
991
+ Animated as Animated2,
992
+ LayoutAnimation,
993
+ Platform,
994
+ UIManager
995
+ } from "react-native";
996
+ import { jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
997
+ if (Platform.OS === "android" && UIManager.setLayoutAnimationEnabledExperimental) {
998
+ UIManager.setLayoutAnimationEnabledExperimental(true);
999
+ }
1000
+ var styles15 = StyleSheet15.create({
1001
+ container: {
1002
+ borderRadius: border.radius.m,
1003
+ overflow: "hidden"
1004
+ },
1005
+ header: {
1006
+ flexDirection: "row",
1007
+ alignItems: "center",
1008
+ justifyContent: "space-between",
1009
+ minHeight: 44,
1010
+ paddingVertical: spacing.s,
1011
+ paddingHorizontal: spacing.m
1012
+ },
1013
+ summaryText: {
1014
+ flex: 1,
1015
+ fontSize: font.size.body,
1016
+ fontFamily: font.family.body,
1017
+ fontWeight: font.weight.semibold,
1018
+ lineHeight: lineHeight.body
1019
+ },
1020
+ chevron: {
1021
+ fontSize: font.size.body,
1022
+ marginStart: spacing.xs
1023
+ },
1024
+ content: {
1025
+ paddingHorizontal: spacing.m,
1026
+ paddingBottom: spacing.m
1027
+ },
1028
+ pressed: {
1029
+ opacity: 0.75
1030
+ }
1031
+ });
1032
+ function Collapsible({
1033
+ summary,
1034
+ children,
1035
+ open: controlledOpen,
1036
+ defaultOpen = false,
1037
+ onToggle,
1038
+ name: _name,
1039
+ // eslint-disable-line @typescript-eslint/no-unused-vars
1040
+ style
1041
+ }) {
1042
+ const { colors: colors2 } = useTheme();
1043
+ const [internalOpen, setInternalOpen] = useState2(defaultOpen);
1044
+ const isControlled = controlledOpen !== void 0;
1045
+ const isOpen = isControlled ? controlledOpen : internalOpen;
1046
+ const rotation = useRef2(new Animated2.Value(isOpen ? 1 : 0)).current;
1047
+ const toggle = useCallback(() => {
1048
+ const next = !isOpen;
1049
+ LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
1050
+ Animated2.timing(rotation, {
1051
+ toValue: next ? 1 : 0,
1052
+ duration: 200,
1053
+ useNativeDriver: true
1054
+ }).start();
1055
+ if (!isControlled) {
1056
+ setInternalOpen(next);
1057
+ }
1058
+ onToggle?.(next);
1059
+ }, [isOpen, isControlled, onToggle, rotation]);
1060
+ const rotateZ = rotation.interpolate({
1061
+ inputRange: [0, 1],
1062
+ outputRange: ["0deg", "90deg"]
1063
+ });
1064
+ return /* @__PURE__ */ jsxs9(
1065
+ View12,
1066
+ {
1067
+ style: [styles15.container, { borderBottomWidth: 1, borderBottomColor: colors2.colorBgSubtle }, style],
1068
+ accessibilityRole: "summary",
1069
+ children: [
1070
+ /* @__PURE__ */ jsxs9(
1071
+ Pressable7,
1072
+ {
1073
+ onPress: toggle,
1074
+ accessibilityRole: "button",
1075
+ accessibilityLabel: summary,
1076
+ accessibilityState: { expanded: isOpen },
1077
+ style: ({ pressed }) => [styles15.header, pressed && styles15.pressed],
1078
+ children: [
1079
+ /* @__PURE__ */ jsx17(Text13, { style: [styles15.summaryText, { color: colors2.colorOnBg }], children: summary }),
1080
+ /* @__PURE__ */ jsx17(
1081
+ Animated2.Text,
1082
+ {
1083
+ style: [styles15.chevron, { color: colors2.colorOnBgSubtle, transform: [{ rotateZ }] }],
1084
+ importantForAccessibility: "no",
1085
+ accessibilityElementsHidden: true,
1086
+ children: "\u25B8"
1087
+ }
1088
+ )
1089
+ ]
1090
+ }
1091
+ ),
1092
+ isOpen && /* @__PURE__ */ jsx17(View12, { style: styles15.content, children })
1093
+ ]
1094
+ }
1095
+ );
1096
+ }
1097
+
1098
+ // src/components/ui/Accordion/Accordion.native.tsx
1099
+ import { useState as useState3 } from "react";
1100
+ import {
1101
+ StyleSheet as StyleSheet16,
1102
+ View as View13,
1103
+ Text as Text14,
1104
+ Pressable as Pressable8,
1105
+ LayoutAnimation as LayoutAnimation2,
1106
+ Platform as Platform2,
1107
+ UIManager as UIManager2
1108
+ } from "react-native";
1109
+ import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
1110
+ if (Platform2.OS === "android" && UIManager2.setLayoutAnimationEnabledExperimental) {
1111
+ UIManager2.setLayoutAnimationEnabledExperimental(true);
1112
+ }
1113
+ var styles16 = StyleSheet16.create({
1114
+ container: {
1115
+ overflow: "hidden",
1116
+ borderRadius: border.radius.s
1117
+ },
1118
+ item: {
1119
+ borderBottomWidth: 1
1120
+ },
1121
+ header: {
1122
+ flexDirection: "row",
1123
+ alignItems: "center",
1124
+ justifyContent: "space-between",
1125
+ minHeight: 44,
1126
+ paddingVertical: spacing.s,
1127
+ paddingHorizontal: spacing.m
1128
+ },
1129
+ titleText: {
1130
+ flex: 1,
1131
+ fontSize: font.size.body,
1132
+ fontFamily: font.family.body,
1133
+ fontWeight: font.weight.semibold,
1134
+ lineHeight: lineHeight.body
1135
+ },
1136
+ chevron: {
1137
+ fontSize: font.size.bodyS,
1138
+ marginStart: spacing.xs
1139
+ },
1140
+ panel: {
1141
+ paddingHorizontal: spacing.m,
1142
+ paddingBottom: spacing.m
1143
+ },
1144
+ pressed: {
1145
+ opacity: 0.75
1146
+ },
1147
+ disabled: {
1148
+ opacity: 0.4
1149
+ }
1150
+ });
1151
+ function Accordion({
1152
+ items,
1153
+ allowMultiple = false,
1154
+ defaultOpen = [],
1155
+ style
1156
+ }) {
1157
+ const { colors: colors2 } = useTheme();
1158
+ const [openIds, setOpenIds] = useState3(defaultOpen);
1159
+ const toggle = (id) => {
1160
+ LayoutAnimation2.configureNext(LayoutAnimation2.Presets.easeInEaseOut);
1161
+ setOpenIds((prev) => {
1162
+ const isOpen = prev.includes(id);
1163
+ if (isOpen) return prev.filter((i) => i !== id);
1164
+ return allowMultiple ? [...prev, id] : [id];
1165
+ });
1166
+ };
1167
+ return /* @__PURE__ */ jsx18(View13, { style: [styles16.container, style], children: items.map((item, index) => {
1168
+ const isOpen = openIds.includes(item.id);
1169
+ const isLast = index === items.length - 1;
1170
+ return /* @__PURE__ */ jsxs10(
1171
+ View13,
1172
+ {
1173
+ style: [
1174
+ styles16.item,
1175
+ { borderBottomColor: colors2.colorBgSubtle },
1176
+ isLast && { borderBottomWidth: 0 }
1177
+ ],
1178
+ children: [
1179
+ /* @__PURE__ */ jsxs10(
1180
+ Pressable8,
1181
+ {
1182
+ onPress: () => toggle(item.id),
1183
+ disabled: item.disabled,
1184
+ accessibilityRole: "button",
1185
+ accessibilityState: { expanded: isOpen, disabled: item.disabled },
1186
+ style: ({ pressed }) => [
1187
+ styles16.header,
1188
+ item.disabled && styles16.disabled,
1189
+ pressed && !item.disabled && styles16.pressed
1190
+ ],
1191
+ children: [
1192
+ /* @__PURE__ */ jsx18(Text14, { style: [styles16.titleText, { color: colors2.colorOnBg }], children: typeof item.title === "string" ? item.title : item.title }),
1193
+ /* @__PURE__ */ jsx18(
1194
+ Text14,
1195
+ {
1196
+ style: [styles16.chevron, { color: colors2.colorOnBgSubtle }],
1197
+ importantForAccessibility: "no",
1198
+ accessibilityElementsHidden: true,
1199
+ children: isOpen ? "\u25BE" : "\u25B8"
1200
+ }
1201
+ )
1202
+ ]
1203
+ }
1204
+ ),
1205
+ isOpen && /* @__PURE__ */ jsx18(View13, { style: styles16.panel, accessibilityRole: "summary", children: item.content })
1206
+ ]
1207
+ },
1208
+ item.id
1209
+ );
1210
+ }) });
1211
+ }
1212
+
1213
+ // src/components/ui/Tabs/Tabs.native.tsx
1214
+ import { useState as useState4 } from "react";
1215
+ import {
1216
+ StyleSheet as StyleSheet17,
1217
+ View as View14,
1218
+ Text as Text15,
1219
+ Pressable as Pressable9,
1220
+ ScrollView
1221
+ } from "react-native";
1222
+ import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
1223
+ var styles17 = StyleSheet17.create({
1224
+ container: {
1225
+ overflow: "hidden"
1226
+ },
1227
+ tabList: {
1228
+ flexDirection: "row",
1229
+ borderBottomWidth: 2
1230
+ },
1231
+ tabButton: {
1232
+ minHeight: 44,
1233
+ paddingHorizontal: spacing.m,
1234
+ paddingVertical: spacing.s,
1235
+ alignItems: "center",
1236
+ justifyContent: "center",
1237
+ borderBottomWidth: 2,
1238
+ marginBottom: -2
1239
+ },
1240
+ tabLabel: {
1241
+ fontSize: font.size.body,
1242
+ fontFamily: font.family.body,
1243
+ lineHeight: lineHeight.body
1244
+ },
1245
+ panel: {
1246
+ paddingVertical: spacing.m
1247
+ },
1248
+ pressed: {
1249
+ opacity: 0.75
1250
+ },
1251
+ disabled: {
1252
+ opacity: 0.4
1253
+ }
1254
+ });
1255
+ function Tabs({
1256
+ tabs,
1257
+ defaultTab,
1258
+ style
1259
+ }) {
1260
+ const { colors: colors2 } = useTheme();
1261
+ const [activeTab, setActiveTab] = useState4(defaultTab ?? tabs[0]?.id);
1262
+ return /* @__PURE__ */ jsxs11(View14, { style: [styles17.container, style], children: [
1263
+ /* @__PURE__ */ jsx19(
1264
+ ScrollView,
1265
+ {
1266
+ horizontal: true,
1267
+ showsHorizontalScrollIndicator: false,
1268
+ contentContainerStyle: [styles17.tabList, { borderBottomColor: colors2.colorBgSubtle }],
1269
+ accessibilityRole: "tabbar",
1270
+ children: tabs.map((tab) => {
1271
+ const isActive = activeTab === tab.id;
1272
+ return /* @__PURE__ */ jsx19(
1273
+ Pressable9,
1274
+ {
1275
+ onPress: () => setActiveTab(tab.id),
1276
+ disabled: tab.disabled,
1277
+ accessibilityRole: "tab",
1278
+ accessibilityState: {
1279
+ selected: isActive,
1280
+ disabled: tab.disabled
1281
+ },
1282
+ accessibilityLabel: typeof tab.label === "string" ? tab.label : void 0,
1283
+ style: ({ pressed }) => [
1284
+ styles17.tabButton,
1285
+ {
1286
+ borderBottomColor: isActive ? colors2.colorInteractive : "transparent"
1287
+ },
1288
+ tab.disabled && styles17.disabled,
1289
+ pressed && !tab.disabled && styles17.pressed
1290
+ ],
1291
+ children: /* @__PURE__ */ jsx19(
1292
+ Text15,
1293
+ {
1294
+ style: [
1295
+ styles17.tabLabel,
1296
+ {
1297
+ color: isActive ? colors2.colorInteractive : colors2.colorOnBgSubtle,
1298
+ fontWeight: isActive ? font.weight.semibold : font.weight.body
1299
+ }
1300
+ ],
1301
+ children: tab.label
1302
+ }
1303
+ )
1304
+ },
1305
+ tab.id
1306
+ );
1307
+ })
1308
+ }
1309
+ ),
1310
+ tabs.map((tab) => {
1311
+ const isActive = activeTab === tab.id;
1312
+ if (!isActive) return null;
1313
+ return /* @__PURE__ */ jsx19(View14, { style: styles17.panel, accessibilityRole: "tabpanel", children: tab.content }, tab.id);
1314
+ })
1315
+ ] });
1316
+ }
1317
+
1318
+ // src/components/ui/Table/Table.native.tsx
1319
+ import {
1320
+ StyleSheet as StyleSheet18,
1321
+ View as View15,
1322
+ Text as Text16,
1323
+ ScrollView as ScrollView2,
1324
+ Pressable as Pressable10
1325
+ } from "react-native";
1326
+ import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
1327
+ var styles18 = StyleSheet18.create({
1328
+ wrapper: {
1329
+ borderRadius: border.radius.s,
1330
+ overflow: "hidden"
1331
+ },
1332
+ caption: {
1333
+ fontSize: font.size.bodyS,
1334
+ fontFamily: font.family.body,
1335
+ fontWeight: font.weight.semibold,
1336
+ lineHeight: lineHeight.bodyS,
1337
+ paddingVertical: spacing.xs,
1338
+ paddingHorizontal: spacing.m
1339
+ },
1340
+ headerRow: {
1341
+ flexDirection: "row"
1342
+ },
1343
+ headerCell: {
1344
+ flex: 1,
1345
+ minWidth: 100,
1346
+ paddingVertical: spacing.s,
1347
+ paddingHorizontal: spacing.m,
1348
+ flexDirection: "row",
1349
+ alignItems: "center",
1350
+ gap: spacing.xxs
1351
+ },
1352
+ headerText: {
1353
+ fontSize: font.size.bodyS,
1354
+ fontFamily: font.family.body,
1355
+ fontWeight: font.weight.semibold,
1356
+ lineHeight: lineHeight.bodyS
1357
+ },
1358
+ sortIndicator: {
1359
+ fontSize: font.size.bodyS
1360
+ },
1361
+ row: {
1362
+ flexDirection: "row",
1363
+ borderTopWidth: 1,
1364
+ minHeight: 44
1365
+ },
1366
+ cell: {
1367
+ flex: 1,
1368
+ minWidth: 100,
1369
+ paddingVertical: spacing.s,
1370
+ paddingHorizontal: spacing.m,
1371
+ justifyContent: "center"
1372
+ },
1373
+ cellText: {
1374
+ fontSize: font.size.body,
1375
+ fontFamily: font.family.body,
1376
+ fontWeight: font.weight.body,
1377
+ lineHeight: lineHeight.body
1378
+ },
1379
+ pressed: {
1380
+ opacity: 0.75
1381
+ }
1382
+ });
1383
+ function Table({
1384
+ columns,
1385
+ rows,
1386
+ caption,
1387
+ sortKey,
1388
+ sortDirection,
1389
+ onSort,
1390
+ style
1391
+ }) {
1392
+ const { colors: colors2 } = useTheme();
1393
+ const handleSort = (key) => {
1394
+ if (!onSort) return;
1395
+ const nextDirection = sortKey === key && sortDirection === "asc" ? "desc" : "asc";
1396
+ onSort(key, nextDirection);
1397
+ };
1398
+ const getSortLabel = (col) => {
1399
+ const base = `Sort by ${String(col.header)}`;
1400
+ if (sortKey !== col.key) return base;
1401
+ return `${base}, currently ${sortDirection === "asc" ? "ascending" : "descending"}`;
1402
+ };
1403
+ return /* @__PURE__ */ jsx20(
1404
+ ScrollView2,
1405
+ {
1406
+ horizontal: true,
1407
+ showsHorizontalScrollIndicator: true,
1408
+ style: [styles18.wrapper, { backgroundColor: colors2.colorBg }, style],
1409
+ children: /* @__PURE__ */ jsxs12(View15, { children: [
1410
+ caption && /* @__PURE__ */ jsx20(Text16, { style: [styles18.caption, { color: colors2.colorOnBgSubtle }], children: caption }),
1411
+ /* @__PURE__ */ jsx20(View15, { style: [styles18.headerRow, { backgroundColor: colors2.colorBgSubtle }], children: columns.map(
1412
+ (col) => col.sortable ? /* @__PURE__ */ jsxs12(
1413
+ Pressable10,
1414
+ {
1415
+ onPress: () => handleSort(col.key),
1416
+ accessibilityRole: "button",
1417
+ accessibilityLabel: getSortLabel(col),
1418
+ style: ({ pressed }) => [styles18.headerCell, pressed && styles18.pressed],
1419
+ children: [
1420
+ /* @__PURE__ */ jsx20(Text16, { style: [styles18.headerText, { color: colors2.colorOnBg }], children: col.header }),
1421
+ /* @__PURE__ */ jsx20(
1422
+ Text16,
1423
+ {
1424
+ style: [
1425
+ styles18.sortIndicator,
1426
+ {
1427
+ color: sortKey === col.key ? colors2.colorInteractive : colors2.colorOnBgSubtle
1428
+ }
1429
+ ],
1430
+ importantForAccessibility: "no",
1431
+ accessibilityElementsHidden: true,
1432
+ children: sortKey === col.key ? sortDirection === "asc" ? "\u25B2" : "\u25BC" : "\u25BD"
1433
+ }
1434
+ )
1435
+ ]
1436
+ },
1437
+ col.key
1438
+ ) : /* @__PURE__ */ jsx20(View15, { style: styles18.headerCell, children: /* @__PURE__ */ jsx20(Text16, { style: [styles18.headerText, { color: colors2.colorOnBg }], children: col.header }) }, col.key)
1439
+ ) }),
1440
+ rows.map((row, rowIndex) => /* @__PURE__ */ jsx20(
1441
+ View15,
1442
+ {
1443
+ style: [
1444
+ styles18.row,
1445
+ { borderTopColor: colors2.colorBgSubtle },
1446
+ rowIndex % 2 === 1 && { backgroundColor: colors2.colorBgSubtle }
1447
+ ],
1448
+ accessibilityRole: "none",
1449
+ children: columns.map((col) => /* @__PURE__ */ jsx20(View15, { style: styles18.cell, children: col.render ? typeof col.render(row) === "string" ? /* @__PURE__ */ jsx20(Text16, { style: [styles18.cellText, { color: colors2.colorOnBg }], children: col.render(row) }) : col.render(row) : /* @__PURE__ */ jsx20(Text16, { style: [styles18.cellText, { color: colors2.colorOnBg }], children: String(row[col.key] ?? "") }) }, col.key))
1450
+ },
1451
+ rowIndex
1452
+ ))
1453
+ ] })
1454
+ }
1455
+ );
1456
+ }
1457
+
1458
+ // src/components/ui/Calendar/Calendar.native.tsx
1459
+ import { useState as useState5 } from "react";
1460
+ import {
1461
+ StyleSheet as StyleSheet19,
1462
+ View as View16,
1463
+ Text as Text17,
1464
+ Pressable as Pressable11
1465
+ } from "react-native";
1466
+ import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
1467
+ var DAYS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
1468
+ var DAY_LABELS = {
1469
+ Su: "Sunday",
1470
+ Mo: "Monday",
1471
+ Tu: "Tuesday",
1472
+ We: "Wednesday",
1473
+ Th: "Thursday",
1474
+ Fr: "Friday",
1475
+ Sa: "Saturday"
1476
+ };
1477
+ var MONTHS = [
1478
+ "January",
1479
+ "February",
1480
+ "March",
1481
+ "April",
1482
+ "May",
1483
+ "June",
1484
+ "July",
1485
+ "August",
1486
+ "September",
1487
+ "October",
1488
+ "November",
1489
+ "December"
1490
+ ];
1491
+ function isSameDay(a, b) {
1492
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
1493
+ }
1494
+ function toMidnight(date) {
1495
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
1496
+ }
1497
+ function isOutOfRange(date, min, max) {
1498
+ const d = toMidnight(date);
1499
+ if (min && d < toMidnight(min)) return true;
1500
+ return !!(max && d > toMidnight(max));
1501
+ }
1502
+ function getDaysInMonth(year, month) {
1503
+ return new Date(year, month + 1, 0).getDate();
1504
+ }
1505
+ function getFirstDayOfMonth(year, month) {
1506
+ return new Date(year, month, 1).getDay();
1507
+ }
1508
+ var DAY_SIZE = 44;
1509
+ var styles19 = StyleSheet19.create({
1510
+ container: {
1511
+ alignSelf: "flex-start"
1512
+ },
1513
+ header: {
1514
+ flexDirection: "row",
1515
+ alignItems: "center",
1516
+ justifyContent: "space-between",
1517
+ paddingVertical: spacing.xs,
1518
+ paddingHorizontal: spacing.xxs
1519
+ },
1520
+ navButton: {
1521
+ minWidth: DAY_SIZE,
1522
+ minHeight: DAY_SIZE,
1523
+ alignItems: "center",
1524
+ justifyContent: "center",
1525
+ borderRadius: border.radius.full
1526
+ },
1527
+ navText: {
1528
+ fontSize: font.size.heading3,
1529
+ fontWeight: font.weight.semibold
1530
+ },
1531
+ monthYear: {
1532
+ fontSize: font.size.body,
1533
+ fontFamily: font.family.body,
1534
+ fontWeight: font.weight.semibold,
1535
+ lineHeight: lineHeight.body
1536
+ },
1537
+ weekRow: {
1538
+ flexDirection: "row"
1539
+ },
1540
+ weekday: {
1541
+ width: DAY_SIZE,
1542
+ height: DAY_SIZE,
1543
+ alignItems: "center",
1544
+ justifyContent: "center"
1545
+ },
1546
+ weekdayText: {
1547
+ fontSize: font.size.bodyS,
1548
+ fontFamily: font.family.body,
1549
+ fontWeight: font.weight.semibold,
1550
+ lineHeight: lineHeight.bodyS
1551
+ },
1552
+ grid: {
1553
+ gap: spacing.xxxs
1554
+ },
1555
+ dayRow: {
1556
+ flexDirection: "row"
1557
+ },
1558
+ dayCell: {
1559
+ width: DAY_SIZE,
1560
+ height: DAY_SIZE,
1561
+ alignItems: "center",
1562
+ justifyContent: "center",
1563
+ borderRadius: border.radius.full
1564
+ },
1565
+ dayText: {
1566
+ fontSize: font.size.body,
1567
+ fontFamily: font.family.body,
1568
+ lineHeight: lineHeight.body
1569
+ },
1570
+ today: {
1571
+ borderWidth: 1
1572
+ },
1573
+ pressed: {
1574
+ opacity: 0.75
1575
+ },
1576
+ disabled: {
1577
+ opacity: 0.4
1578
+ }
1579
+ });
1580
+ function Calendar({
1581
+ value,
1582
+ defaultValue,
1583
+ min,
1584
+ max,
1585
+ onChange,
1586
+ style
1587
+ }) {
1588
+ const { colors: colors2 } = useTheme();
1589
+ const today = /* @__PURE__ */ new Date();
1590
+ const controlled = value !== void 0;
1591
+ const [internal, setInternal] = useState5(defaultValue);
1592
+ const selected = controlled ? value : internal;
1593
+ const [viewYear, setViewYear] = useState5(
1594
+ selected?.getFullYear() ?? today.getFullYear()
1595
+ );
1596
+ const [viewMonth, setViewMonth] = useState5(
1597
+ selected?.getMonth() ?? today.getMonth()
1598
+ );
1599
+ const daysInMonth = getDaysInMonth(viewYear, viewMonth);
1600
+ const firstDay = getFirstDayOfMonth(viewYear, viewMonth);
1601
+ const navigate = (delta) => {
1602
+ const d = new Date(viewYear, viewMonth + delta, 1);
1603
+ setViewYear(d.getFullYear());
1604
+ setViewMonth(d.getMonth());
1605
+ };
1606
+ const selectDay = (day) => {
1607
+ const date = new Date(viewYear, viewMonth, day);
1608
+ if (isOutOfRange(date, min, max)) return;
1609
+ if (!controlled) setInternal(date);
1610
+ onChange?.(date);
1611
+ };
1612
+ const cells = [
1613
+ ...Array.from({ length: firstDay }, () => null),
1614
+ ...Array.from({ length: daysInMonth }, (_, i) => ({ day: i + 1 }))
1615
+ ];
1616
+ while (cells.length % 7 !== 0) cells.push(null);
1617
+ const rows = Array.from(
1618
+ { length: cells.length / 7 },
1619
+ (_, i) => cells.slice(i * 7, i * 7 + 7)
1620
+ );
1621
+ return /* @__PURE__ */ jsxs13(
1622
+ View16,
1623
+ {
1624
+ style: [styles19.container, style],
1625
+ accessibilityRole: "none",
1626
+ accessibilityLabel: `${MONTHS[viewMonth]} ${viewYear} calendar`,
1627
+ children: [
1628
+ /* @__PURE__ */ jsxs13(View16, { style: styles19.header, children: [
1629
+ /* @__PURE__ */ jsx21(
1630
+ Pressable11,
1631
+ {
1632
+ onPress: () => navigate(-1),
1633
+ accessibilityRole: "button",
1634
+ accessibilityLabel: "Previous month",
1635
+ style: ({ pressed }) => [styles19.navButton, pressed && styles19.pressed],
1636
+ children: /* @__PURE__ */ jsx21(Text17, { style: [styles19.navText, { color: colors2.colorOnBg }], children: "\u2039" })
1637
+ }
1638
+ ),
1639
+ /* @__PURE__ */ jsxs13(
1640
+ Text17,
1641
+ {
1642
+ style: [styles19.monthYear, { color: colors2.colorOnBg }],
1643
+ accessibilityRole: "text",
1644
+ accessibilityLiveRegion: "polite",
1645
+ children: [
1646
+ MONTHS[viewMonth],
1647
+ " ",
1648
+ viewYear
1649
+ ]
1650
+ }
1651
+ ),
1652
+ /* @__PURE__ */ jsx21(
1653
+ Pressable11,
1654
+ {
1655
+ onPress: () => navigate(1),
1656
+ accessibilityRole: "button",
1657
+ accessibilityLabel: "Next month",
1658
+ style: ({ pressed }) => [styles19.navButton, pressed && styles19.pressed],
1659
+ children: /* @__PURE__ */ jsx21(Text17, { style: [styles19.navText, { color: colors2.colorOnBg }], children: "\u203A" })
1660
+ }
1661
+ )
1662
+ ] }),
1663
+ /* @__PURE__ */ jsx21(View16, { style: styles19.weekRow, children: DAYS.map((d) => /* @__PURE__ */ jsx21(View16, { style: styles19.weekday, children: /* @__PURE__ */ jsx21(
1664
+ Text17,
1665
+ {
1666
+ style: [styles19.weekdayText, { color: colors2.colorOnBgSubtle }],
1667
+ accessibilityLabel: DAY_LABELS[d],
1668
+ children: d
1669
+ }
1670
+ ) }, d)) }),
1671
+ /* @__PURE__ */ jsx21(View16, { style: styles19.grid, children: rows.map((row, rowIndex) => /* @__PURE__ */ jsx21(View16, { style: styles19.dayRow, children: row.map((cell, colIndex) => {
1672
+ if (!cell) {
1673
+ return /* @__PURE__ */ jsx21(View16, { style: styles19.dayCell }, colIndex);
1674
+ }
1675
+ const date = new Date(viewYear, viewMonth, cell.day);
1676
+ const isSelected = selected ? isSameDay(date, selected) : false;
1677
+ const isToday = isSameDay(date, today);
1678
+ const disabled = isOutOfRange(date, min, max);
1679
+ return /* @__PURE__ */ jsx21(
1680
+ Pressable11,
1681
+ {
1682
+ onPress: () => selectDay(cell.day),
1683
+ disabled,
1684
+ accessibilityRole: "button",
1685
+ accessibilityLabel: date.toLocaleDateString("en", {
1686
+ month: "long",
1687
+ day: "numeric",
1688
+ year: "numeric"
1689
+ }),
1690
+ accessibilityState: {
1691
+ selected: isSelected,
1692
+ disabled
1693
+ },
1694
+ style: ({ pressed }) => [
1695
+ styles19.dayCell,
1696
+ isSelected && {
1697
+ backgroundColor: colors2.colorInteractive
1698
+ },
1699
+ isToday && !isSelected && [
1700
+ styles19.today,
1701
+ { borderColor: colors2.colorInteractive }
1702
+ ],
1703
+ disabled && styles19.disabled,
1704
+ pressed && !disabled && styles19.pressed
1705
+ ],
1706
+ children: /* @__PURE__ */ jsx21(
1707
+ Text17,
1708
+ {
1709
+ style: [
1710
+ styles19.dayText,
1711
+ {
1712
+ color: isSelected ? colors2.colorOnInteractive : colors2.colorOnBg,
1713
+ fontWeight: isToday ? font.weight.semibold : font.weight.body
1714
+ }
1715
+ ],
1716
+ children: cell.day
1717
+ }
1718
+ )
1719
+ },
1720
+ colIndex
1721
+ );
1722
+ }) }, rowIndex)) })
1723
+ ]
1724
+ }
1725
+ );
1726
+ }
1727
+
1728
+ // src/components/ui/Carousel/Carousel.native.tsx
1729
+ import { useCallback as useCallback2, useRef as useRef3, useState as useState6 } from "react";
1730
+ import {
1731
+ StyleSheet as StyleSheet20,
1732
+ View as View17,
1733
+ Text as Text18,
1734
+ Pressable as Pressable12,
1735
+ ScrollView as ScrollView3,
1736
+ Dimensions
1737
+ } from "react-native";
1738
+ import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
1739
+ var DOT_SIZE = 8;
1740
+ var DOT_HIT_SIZE = 44;
1741
+ var styles20 = StyleSheet20.create({
1742
+ container: {
1743
+ width: "100%"
1744
+ },
1745
+ scrollView: {
1746
+ flexGrow: 0
1747
+ },
1748
+ slide: {
1749
+ justifyContent: "center",
1750
+ alignItems: "center"
1751
+ },
1752
+ nav: {
1753
+ flexDirection: "row",
1754
+ alignItems: "center",
1755
+ justifyContent: "center",
1756
+ gap: spacing.xs,
1757
+ paddingVertical: spacing.s
1758
+ },
1759
+ navButton: {
1760
+ minWidth: 44,
1761
+ minHeight: 44,
1762
+ alignItems: "center",
1763
+ justifyContent: "center",
1764
+ borderRadius: border.radius.s
1765
+ },
1766
+ navText: {
1767
+ fontSize: 20,
1768
+ fontWeight: "600"
1769
+ },
1770
+ dots: {
1771
+ flexDirection: "row",
1772
+ alignItems: "center",
1773
+ gap: spacing.xs
1774
+ },
1775
+ dotWrapper: {
1776
+ minWidth: DOT_HIT_SIZE,
1777
+ minHeight: DOT_HIT_SIZE,
1778
+ alignItems: "center",
1779
+ justifyContent: "center"
1780
+ },
1781
+ dot: {
1782
+ width: DOT_SIZE,
1783
+ height: DOT_SIZE,
1784
+ borderRadius: DOT_SIZE / 2
1785
+ },
1786
+ pressed: {
1787
+ opacity: 0.75
1788
+ }
1789
+ });
1790
+ function Carousel({
1791
+ items,
1792
+ label,
1793
+ style
1794
+ }) {
1795
+ const { colors: colors2 } = useTheme();
1796
+ const scrollRef = useRef3(null);
1797
+ const [activeIndex, setActiveIndex] = useState6(0);
1798
+ const [slideWidth, setSlideWidth] = useState6(Dimensions.get("window").width);
1799
+ const handleScroll = useCallback2(
1800
+ (e) => {
1801
+ const offset = e.nativeEvent.contentOffset.x;
1802
+ const width = e.nativeEvent.layoutMeasurement.width;
1803
+ if (width > 0) {
1804
+ const index = Math.round(offset / width);
1805
+ setActiveIndex(index);
1806
+ }
1807
+ },
1808
+ []
1809
+ );
1810
+ const scrollTo = (index) => {
1811
+ const clamped = Math.max(0, Math.min(index, items.length - 1));
1812
+ scrollRef.current?.scrollTo({ x: clamped * slideWidth, animated: true });
1813
+ };
1814
+ return /* @__PURE__ */ jsxs14(
1815
+ View17,
1816
+ {
1817
+ style: [styles20.container, style],
1818
+ accessibilityRole: "none",
1819
+ accessibilityLabel: label,
1820
+ children: [
1821
+ /* @__PURE__ */ jsx22(
1822
+ ScrollView3,
1823
+ {
1824
+ ref: scrollRef,
1825
+ horizontal: true,
1826
+ pagingEnabled: true,
1827
+ showsHorizontalScrollIndicator: false,
1828
+ onScroll: handleScroll,
1829
+ scrollEventThrottle: 16,
1830
+ onLayout: (e) => setSlideWidth(e.nativeEvent.layout.width),
1831
+ style: styles20.scrollView,
1832
+ children: items.map((item, index) => /* @__PURE__ */ jsx22(View17, { style: [styles20.slide, { width: slideWidth }], children: item }, index))
1833
+ }
1834
+ ),
1835
+ /* @__PURE__ */ jsxs14(View17, { style: styles20.nav, children: [
1836
+ /* @__PURE__ */ jsx22(
1837
+ Pressable12,
1838
+ {
1839
+ onPress: () => scrollTo(activeIndex - 1),
1840
+ disabled: activeIndex <= 0,
1841
+ accessibilityRole: "button",
1842
+ accessibilityLabel: "Previous",
1843
+ accessibilityState: { disabled: activeIndex <= 0 },
1844
+ style: ({ pressed }) => [
1845
+ styles20.navButton,
1846
+ activeIndex <= 0 && { opacity: 0.4 },
1847
+ pressed && styles20.pressed
1848
+ ],
1849
+ children: /* @__PURE__ */ jsx22(Text18, { style: [styles20.navText, { color: colors2.colorOnBg }], children: "\u2039" })
1850
+ }
1851
+ ),
1852
+ /* @__PURE__ */ jsx22(View17, { style: styles20.dots, children: items.map((_, index) => /* @__PURE__ */ jsx22(
1853
+ Pressable12,
1854
+ {
1855
+ onPress: () => scrollTo(index),
1856
+ accessibilityRole: "button",
1857
+ accessibilityLabel: `Go to slide ${index + 1}`,
1858
+ accessibilityState: { selected: activeIndex === index },
1859
+ style: styles20.dotWrapper,
1860
+ children: /* @__PURE__ */ jsx22(
1861
+ View17,
1862
+ {
1863
+ style: [
1864
+ styles20.dot,
1865
+ {
1866
+ backgroundColor: activeIndex === index ? colors2.colorInteractive : colors2.colorBgSubtle
1867
+ }
1868
+ ]
1869
+ }
1870
+ )
1871
+ },
1872
+ index
1873
+ )) }),
1874
+ /* @__PURE__ */ jsx22(
1875
+ Pressable12,
1876
+ {
1877
+ onPress: () => scrollTo(activeIndex + 1),
1878
+ disabled: activeIndex >= items.length - 1,
1879
+ accessibilityRole: "button",
1880
+ accessibilityLabel: "Next",
1881
+ accessibilityState: { disabled: activeIndex >= items.length - 1 },
1882
+ style: ({ pressed }) => [
1883
+ styles20.navButton,
1884
+ activeIndex >= items.length - 1 && { opacity: 0.4 },
1885
+ pressed && styles20.pressed
1886
+ ],
1887
+ children: /* @__PURE__ */ jsx22(Text18, { style: [styles20.navText, { color: colors2.colorOnBg }], children: "\u203A" })
1888
+ }
1889
+ )
1890
+ ] })
1891
+ ]
1892
+ }
1893
+ );
1894
+ }
1895
+
1896
+ // src/components/layout/Card/Card.native.tsx
1897
+ import { StyleSheet as StyleSheet21, View as View18, Pressable as Pressable13 } from "react-native";
1898
+ import { jsx as jsx23 } from "react/jsx-runtime";
1899
+ var paddingMap = {
1900
+ none: 0,
1901
+ small: spacing.s,
1902
+ medium: spacing.m,
1903
+ large: spacing.xxl
1904
+ };
1905
+ var alignMap = {
1906
+ start: "flex-start",
1907
+ center: "center",
1908
+ end: "flex-end"
1909
+ };
1910
+ var styles21 = StyleSheet21.create({
1911
+ card: {
1912
+ borderRadius: border.radius.m,
1913
+ overflow: "hidden"
1914
+ }
1915
+ });
1916
+ function Card({
1917
+ children,
1918
+ variant = "default",
1919
+ padding = "medium",
1920
+ textAlign = "start",
1921
+ style,
1922
+ onPress,
1923
+ accessibilityLabel
1924
+ }) {
1925
+ const { colors: colors2 } = useTheme();
1926
+ const variantStyle = {
1927
+ backgroundColor: colors2.colorBg,
1928
+ ...variant === "elevated" && {
1929
+ shadowColor: "#000",
1930
+ shadowOffset: { width: 0, height: 2 },
1931
+ shadowOpacity: 0.1,
1932
+ shadowRadius: 8,
1933
+ elevation: 4
1934
+ },
1935
+ ...variant === "outlined" && {
1936
+ borderWidth: 1,
1937
+ borderColor: colors2.colorBgSubtle
1938
+ }
1939
+ };
1940
+ const inner = {
1941
+ padding: paddingMap[padding],
1942
+ alignItems: alignMap[textAlign]
1943
+ };
1944
+ if (onPress) {
1945
+ return /* @__PURE__ */ jsx23(
1946
+ Pressable13,
1947
+ {
1948
+ onPress,
1949
+ accessibilityRole: "button",
1950
+ accessibilityLabel,
1951
+ style: ({ pressed }) => [styles21.card, variantStyle, inner, pressed && { opacity: 0.8 }, style],
1952
+ children
1953
+ }
1954
+ );
1955
+ }
1956
+ return /* @__PURE__ */ jsx23(View18, { style: [styles21.card, variantStyle, inner, style], children });
1957
+ }
1958
+
1959
+ // src/components/layout/SectionHeader/SectionHeader.native.tsx
1960
+ import { StyleSheet as StyleSheet22, View as View19, Text as Text19 } from "react-native";
1961
+ import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
1962
+ var alignMap2 = {
1963
+ start: "flex-start",
1964
+ center: "center",
1965
+ end: "flex-end"
1966
+ };
1967
+ var titleStyles = StyleSheet22.create({
1968
+ small: {
1969
+ fontSize: font.size.heading3,
1970
+ fontFamily: font.family.heading,
1971
+ fontWeight: font.weight.heading,
1972
+ lineHeight: lineHeight.heading3
1973
+ },
1974
+ medium: {
1975
+ fontSize: font.size.heading2,
1976
+ fontFamily: font.family.heading,
1977
+ fontWeight: font.weight.heading,
1978
+ lineHeight: lineHeight.heading2
1979
+ },
1980
+ large: {
1981
+ fontSize: font.size.heading1,
1982
+ fontFamily: font.family.heading,
1983
+ fontWeight: font.weight.heading,
1984
+ lineHeight: lineHeight.heading1
1985
+ }
1986
+ });
1987
+ var styles22 = StyleSheet22.create({
1988
+ container: {
1989
+ gap: spacing.xxs
1990
+ },
1991
+ subtitle: {
1992
+ fontSize: font.size.bodyS,
1993
+ fontFamily: font.family.body,
1994
+ lineHeight: lineHeight.bodyS
1995
+ }
1996
+ });
1997
+ function SectionHeader({
1998
+ title,
1999
+ subtitle,
2000
+ alignment = "start",
2001
+ size = "medium",
2002
+ style
2003
+ }) {
2004
+ const { colors: colors2 } = useTheme();
2005
+ const align = alignMap2[alignment];
2006
+ return /* @__PURE__ */ jsxs15(View19, { style: [styles22.container, { alignItems: align }, style], children: [
2007
+ /* @__PURE__ */ jsx24(
2008
+ Text19,
2009
+ {
2010
+ accessibilityRole: "header",
2011
+ style: [titleStyles[size], { color: colors2.colorOnBg }],
2012
+ children: title
2013
+ }
2014
+ ),
2015
+ subtitle && /* @__PURE__ */ jsx24(Text19, { style: [styles22.subtitle, { color: colors2.colorOnBgSubtle }], children: subtitle })
2016
+ ] });
2017
+ }
2018
+
2019
+ // src/components/layout/IconWrapper/IconWrapper.native.tsx
2020
+ import { View as View20 } from "react-native";
2021
+ import { jsx as jsx25 } from "react/jsx-runtime";
2022
+ function IconWrapper({ children, style, accessibilityElementsHidden }) {
2023
+ return /* @__PURE__ */ jsx25(
2024
+ View20,
2025
+ {
2026
+ style: [{ alignItems: "center", justifyContent: "center" }, style],
2027
+ importantForAccessibility: accessibilityElementsHidden ? "no-hide-descendants" : "auto",
2028
+ accessibilityElementsHidden,
2029
+ children
2030
+ }
2031
+ );
2032
+ }
2033
+
2034
+ // src/components/layout/ButtonGroup/ButtonGroup.native.tsx
2035
+ import { StyleSheet as StyleSheet23, View as View21 } from "react-native";
2036
+ import { jsx as jsx26 } from "react/jsx-runtime";
2037
+ var styles23 = StyleSheet23.create({
2038
+ group: {
2039
+ flexDirection: "row",
2040
+ flexWrap: "wrap",
2041
+ gap: spacing.xs
2042
+ },
2043
+ column: {
2044
+ flexDirection: "column",
2045
+ gap: spacing.xs
2046
+ }
2047
+ });
2048
+ function ButtonContainer({ children, variant, accessibilityLabel, style }) {
2049
+ const isColumn = variant === "card" || variant === "modal";
2050
+ return /* @__PURE__ */ jsx26(
2051
+ View21,
2052
+ {
2053
+ accessibilityLabel,
2054
+ style: [isColumn ? styles23.column : styles23.group, style],
2055
+ children
2056
+ }
2057
+ );
2058
+ }
2059
+ var ButtonGroup = ButtonContainer;
2060
+
2061
+ // src/components/interaction/Button/Button.native.tsx
2062
+ import { StyleSheet as StyleSheet24, Pressable as Pressable14, Text as Text20, View as View22 } from "react-native";
2063
+ import { jsx as jsx27, jsxs as jsxs16 } from "react/jsx-runtime";
2064
+ var sizeTokens = {
2065
+ small: { height: 36, px: spacing.m, fontSize: font.size.bodyS, radius: border.radius.full },
2066
+ medium: { height: 48, px: spacing.m, fontSize: font.size.body, radius: border.radius.full },
2067
+ large: { height: 56, px: spacing.xxl, fontSize: font.size.heading3, radius: border.radius.full }
2068
+ };
2069
+ var styles24 = StyleSheet24.create({
2070
+ pressable: {
2071
+ flexDirection: "row",
2072
+ alignItems: "center",
2073
+ justifyContent: "center",
2074
+ gap: spacing.xs,
2075
+ alignSelf: "flex-start"
2076
+ },
2077
+ label: {
2078
+ fontFamily: font.family.body,
2079
+ fontWeight: font.weight.semibold,
2080
+ includeFontPadding: false
2081
+ }
2082
+ });
2083
+ function Button({
2084
+ children,
2085
+ variant = "default",
2086
+ size = "medium",
2087
+ iconStart,
2088
+ iconEnd,
2089
+ disabled = false,
2090
+ isIconOnly = false,
2091
+ onPress,
2092
+ accessibilityLabel,
2093
+ style
2094
+ }) {
2095
+ const { colors: colors2 } = useTheme();
2096
+ const { height, px, fontSize, radius } = sizeTokens[size];
2097
+ const primaryColor = colors2.colorInteractive;
2098
+ const onPrimaryColor = colors2.colorOnInteractive;
2099
+ const outlineTextColor = colors2.colorInteractiveOnBg;
2100
+ const isOutline = variant === "outline" || variant === "ghost";
2101
+ const containerStyle = {
2102
+ height,
2103
+ paddingHorizontal: isIconOnly ? spacing.xs : px,
2104
+ borderRadius: radius,
2105
+ opacity: disabled ? 0.4 : 1,
2106
+ // Icon-only: square with equal xs padding on both axes.
2107
+ ...isIconOnly && { aspectRatio: 1, paddingVertical: spacing.xs },
2108
+ ...variant === "default" && { backgroundColor: primaryColor },
2109
+ ...isOutline && {
2110
+ backgroundColor: "transparent",
2111
+ borderWidth: 1,
2112
+ borderColor: outlineTextColor
2113
+ }
2114
+ };
2115
+ const textColor = variant === "default" ? onPrimaryColor : outlineTextColor;
2116
+ return /* @__PURE__ */ jsxs16(
2117
+ Pressable14,
2118
+ {
2119
+ onPress,
2120
+ disabled,
2121
+ accessibilityRole: "button",
2122
+ accessibilityLabel,
2123
+ accessibilityState: { disabled },
2124
+ style: ({ pressed }) => [styles24.pressable, containerStyle, pressed && { opacity: 0.75 }, style],
2125
+ children: [
2126
+ iconStart && /* @__PURE__ */ jsx27(View22, { importantForAccessibility: "no-hide-descendants", accessibilityElementsHidden: true, children: iconStart }),
2127
+ children && (isIconOnly ? children : /* @__PURE__ */ jsx27(Text20, { style: [styles24.label, { fontSize, color: textColor }], children })),
2128
+ iconEnd && /* @__PURE__ */ jsx27(View22, { importantForAccessibility: "no-hide-descendants", children: iconEnd })
2129
+ ]
2130
+ }
2131
+ );
2132
+ }
2133
+
2134
+ // src/components/interaction/Rating/Rating.native.tsx
2135
+ import { StyleSheet as StyleSheet25, View as View23, Text as Text21 } from "react-native";
2136
+ import { jsx as jsx28 } from "react/jsx-runtime";
2137
+ var STAR_SIZE = 24;
2138
+ var styles25 = StyleSheet25.create({
2139
+ container: {
2140
+ flexDirection: "row",
2141
+ alignItems: "center"
2142
+ },
2143
+ star: {
2144
+ fontSize: STAR_SIZE,
2145
+ fontFamily: font.family.body
2146
+ }
2147
+ });
2148
+ function Rating({ value, max = 5, style, accessibilityLabel }) {
2149
+ const { colors: colors2 } = useTheme();
2150
+ const label = accessibilityLabel ?? `${value} out of ${max} stars`;
2151
+ return /* @__PURE__ */ jsx28(
2152
+ View23,
2153
+ {
2154
+ style: [styles25.container, style],
2155
+ accessibilityRole: "image",
2156
+ accessibilityLabel: label,
2157
+ children: Array.from({ length: max }).map((_, i) => /* @__PURE__ */ jsx28(
2158
+ Text21,
2159
+ {
2160
+ style: [
2161
+ styles25.star,
2162
+ { color: i < value ? colors2.colorWarning : colors2.colorBgSubtle }
2163
+ ],
2164
+ importantForAccessibility: "no",
2165
+ accessibilityElementsHidden: true,
2166
+ children: "\u2605"
2167
+ },
2168
+ i
2169
+ ))
2170
+ }
2171
+ );
2172
+ }
2173
+
2174
+ // src/components/interaction/form/Switch/Switch.native.tsx
2175
+ import { Switch as RNSwitch, View as View24, StyleSheet as StyleSheet27 } from "react-native";
2176
+
2177
+ // src/components/interaction/form/atoms/Label.native.tsx
2178
+ import { Text as Text22 } from "react-native";
2179
+ import { jsx as jsx29 } from "react/jsx-runtime";
2180
+ function Label({ label, style }) {
2181
+ const { colors: colors2 } = useTheme();
2182
+ return /* @__PURE__ */ jsx29(
2183
+ Text22,
2184
+ {
2185
+ style: [
2186
+ {
2187
+ fontFamily: font.family.body,
2188
+ fontSize: font.size.body,
2189
+ lineHeight: lineHeight.body,
2190
+ fontWeight: font.weight.semibold,
2191
+ color: colors2.colorOnBg
2192
+ },
2193
+ style
2194
+ ],
2195
+ children: label
2196
+ }
2197
+ );
2198
+ }
2199
+
2200
+ // src/components/interaction/form/atoms/Message.native.tsx
2201
+ import { StyleSheet as StyleSheet26, Text as Text23 } from "react-native";
2202
+ import { jsx as jsx30 } from "react/jsx-runtime";
2203
+ var styles26 = StyleSheet26.create({
2204
+ base: {
2205
+ fontFamily: font.family.body,
2206
+ fontSize: font.size.bodyS,
2207
+ lineHeight: lineHeight.bodyS
2208
+ }
2209
+ });
2210
+ function Message({ message, type, style }) {
2211
+ const { colors: colors2 } = useTheme();
2212
+ if (!message) return null;
2213
+ const color = type === "error" ? colors2.colorError : colors2.colorOnBgSubtle;
2214
+ return /* @__PURE__ */ jsx30(
2215
+ Text23,
2216
+ {
2217
+ accessibilityRole: type === "error" ? "alert" : "none",
2218
+ accessibilityLiveRegion: type === "error" ? "assertive" : "polite",
2219
+ style: [styles26.base, { color }, style],
2220
+ children: message
2221
+ }
2222
+ );
2223
+ }
2224
+
2225
+ // src/components/interaction/form/Switch/Switch.native.tsx
2226
+ import { jsx as jsx31, jsxs as jsxs17 } from "react/jsx-runtime";
2227
+ var styles27 = StyleSheet27.create({
2228
+ container: {
2229
+ gap: spacing.xxs
2230
+ },
2231
+ row: {
2232
+ flexDirection: "row",
2233
+ alignItems: "center",
2234
+ gap: spacing.xs
2235
+ }
2236
+ });
2237
+ function Switch({
2238
+ label,
2239
+ value = false,
2240
+ onChange,
2241
+ disabled = false,
2242
+ error,
2243
+ hint,
2244
+ style
2245
+ }) {
2246
+ const { colors: colors2 } = useTheme();
2247
+ return /* @__PURE__ */ jsxs17(View24, { style: [styles27.container, style], children: [
2248
+ /* @__PURE__ */ jsxs17(View24, { style: styles27.row, children: [
2249
+ /* @__PURE__ */ jsx31(
2250
+ RNSwitch,
2251
+ {
2252
+ value,
2253
+ onValueChange: onChange,
2254
+ disabled,
2255
+ accessibilityLabel: label,
2256
+ accessibilityRole: "switch",
2257
+ accessibilityState: { checked: value, disabled },
2258
+ thumbColor: colors2.colorInteractive,
2259
+ trackColor: { false: colors2.colorBgSubtle, true: colors2.colorBlueSubtle }
2260
+ }
2261
+ ),
2262
+ /* @__PURE__ */ jsx31(Label, { label })
2263
+ ] }),
2264
+ /* @__PURE__ */ jsx31(Message, { type: "error", message: error }),
2265
+ /* @__PURE__ */ jsx31(Message, { type: "hint", message: hint })
2266
+ ] });
2267
+ }
2268
+
2269
+ // src/components/interaction/form/Checkbox/Checkbox.native.tsx
2270
+ import { StyleSheet as StyleSheet28, View as View25, Pressable as Pressable15 } from "react-native";
2271
+ import { jsx as jsx32, jsxs as jsxs18 } from "react/jsx-runtime";
2272
+ var BOX = 22;
2273
+ var styles28 = StyleSheet28.create({
2274
+ container: {
2275
+ gap: spacing.xxs
2276
+ },
2277
+ row: {
2278
+ flexDirection: "row",
2279
+ alignItems: "center",
2280
+ gap: spacing.xs,
2281
+ minHeight: 44
2282
+ },
2283
+ box: {
2284
+ width: BOX,
2285
+ height: BOX,
2286
+ borderRadius: border.radius.xs,
2287
+ borderWidth: 2,
2288
+ alignItems: "center",
2289
+ justifyContent: "center"
2290
+ },
2291
+ checkmark: {
2292
+ fontSize: 14,
2293
+ fontWeight: "700",
2294
+ lineHeight: 16
2295
+ }
2296
+ });
2297
+ function Checkbox({
2298
+ label,
2299
+ name,
2300
+ checked = false,
2301
+ onChange,
2302
+ disabled = false,
2303
+ error,
2304
+ hint,
2305
+ style
2306
+ }) {
2307
+ const { colors: colors2 } = useTheme();
2308
+ const borderColor = error ? colors2.colorError : checked ? colors2.colorInteractive : colors2.colorOnBg;
2309
+ const bgColor = checked ? colors2.colorInteractive : "transparent";
2310
+ return /* @__PURE__ */ jsxs18(View25, { style: [styles28.container, style], children: [
2311
+ /* @__PURE__ */ jsxs18(
2312
+ Pressable15,
2313
+ {
2314
+ onPress: () => !disabled && onChange?.(!checked),
2315
+ accessibilityRole: "checkbox",
2316
+ accessibilityLabel: typeof label === "string" ? label : name,
2317
+ accessibilityState: { checked, disabled },
2318
+ disabled,
2319
+ style: ({ pressed }) => [styles28.row, pressed && { opacity: 0.7 }, disabled && { opacity: 0.4 }],
2320
+ children: [
2321
+ /* @__PURE__ */ jsx32(View25, { style: [styles28.box, { borderColor, backgroundColor: bgColor }], children: checked && /* @__PURE__ */ jsx32(Label, { label: "\u2713", style: [styles28.checkmark, { color: colors2.colorOnInteractive }] }) }),
2322
+ /* @__PURE__ */ jsx32(Label, { label })
2323
+ ]
2324
+ }
2325
+ ),
2326
+ /* @__PURE__ */ jsx32(Message, { type: "error", message: error }),
2327
+ /* @__PURE__ */ jsx32(Message, { type: "hint", message: hint })
2328
+ ] });
2329
+ }
2330
+
2331
+ // src/components/interaction/form/CheckboxGroup/CheckboxGroup.native.tsx
2332
+ import { StyleSheet as StyleSheet29, View as View26, Text as Text24 } from "react-native";
2333
+ import { jsx as jsx33, jsxs as jsxs19 } from "react/jsx-runtime";
2334
+ var styles29 = StyleSheet29.create({
2335
+ container: {
2336
+ gap: spacing.xs
2337
+ },
2338
+ legend: {
2339
+ fontFamily: font.family.body,
2340
+ fontSize: font.size.body,
2341
+ lineHeight: lineHeight.body,
2342
+ fontWeight: font.weight.semibold
2343
+ },
2344
+ required: {
2345
+ fontWeight: font.weight.body
2346
+ },
2347
+ items: {
2348
+ gap: spacing.xxs
2349
+ }
2350
+ });
2351
+ function CheckboxGroup({
2352
+ legend,
2353
+ children,
2354
+ error,
2355
+ hint,
2356
+ required,
2357
+ disabled = false,
2358
+ style
2359
+ }) {
2360
+ const { colors: colors2 } = useTheme();
2361
+ return /* @__PURE__ */ jsxs19(
2362
+ View26,
2363
+ {
2364
+ style: [styles29.container, disabled && { opacity: 0.4 }, style],
2365
+ accessibilityRole: "none",
2366
+ accessibilityLabel: legend,
2367
+ children: [
2368
+ /* @__PURE__ */ jsxs19(Text24, { style: [styles29.legend, { color: colors2.colorOnBg }], children: [
2369
+ legend,
2370
+ required && /* @__PURE__ */ jsx33(Text24, { style: [styles29.required, { color: colors2.colorOnBgSubtle }], children: " *" })
2371
+ ] }),
2372
+ /* @__PURE__ */ jsx33(View26, { style: styles29.items, children }),
2373
+ /* @__PURE__ */ jsx33(Message, { type: "error", message: error }),
2374
+ /* @__PURE__ */ jsx33(Message, { type: "hint", message: hint })
2375
+ ]
2376
+ }
2377
+ );
2378
+ }
2379
+
2380
+ // src/components/interaction/form/Radio/Radio.native.tsx
2381
+ import { StyleSheet as StyleSheet30, View as View27, Pressable as Pressable16 } from "react-native";
2382
+ import { jsx as jsx34, jsxs as jsxs20 } from "react/jsx-runtime";
2383
+ var DOT = 22;
2384
+ var INNER = 10;
2385
+ var styles30 = StyleSheet30.create({
2386
+ container: {
2387
+ gap: spacing.xxs
2388
+ },
2389
+ row: {
2390
+ flexDirection: "row",
2391
+ alignItems: "center",
2392
+ gap: spacing.xs,
2393
+ minHeight: 44
2394
+ },
2395
+ outer: {
2396
+ width: DOT,
2397
+ height: DOT,
2398
+ borderRadius: DOT / 2,
2399
+ borderWidth: 2,
2400
+ alignItems: "center",
2401
+ justifyContent: "center"
2402
+ },
2403
+ inner: {
2404
+ width: INNER,
2405
+ height: INNER,
2406
+ borderRadius: INNER / 2
2407
+ }
2408
+ });
2409
+ function Radio({
2410
+ label,
2411
+ name,
2412
+ checked = false,
2413
+ onChange,
2414
+ disabled = false,
2415
+ error,
2416
+ hint,
2417
+ style
2418
+ }) {
2419
+ const { colors: colors2 } = useTheme();
2420
+ const borderColor = error ? colors2.colorError : checked ? colors2.colorInteractive : colors2.colorOnBg;
2421
+ return /* @__PURE__ */ jsxs20(View27, { style: [styles30.container, style], children: [
2422
+ /* @__PURE__ */ jsxs20(
2423
+ Pressable16,
2424
+ {
2425
+ onPress: () => !disabled && onChange?.(),
2426
+ accessibilityRole: "radio",
2427
+ accessibilityLabel: typeof label === "string" ? label : name,
2428
+ accessibilityState: { checked, disabled },
2429
+ disabled,
2430
+ style: ({ pressed }) => [styles30.row, pressed && { opacity: 0.7 }, disabled && { opacity: 0.4 }],
2431
+ children: [
2432
+ /* @__PURE__ */ jsx34(View27, { style: [styles30.outer, { borderColor }], children: checked && /* @__PURE__ */ jsx34(View27, { style: [styles30.inner, { backgroundColor: colors2.colorInteractive }] }) }),
2433
+ /* @__PURE__ */ jsx34(Label, { label })
2434
+ ]
2435
+ }
2436
+ ),
2437
+ /* @__PURE__ */ jsx34(Message, { type: "error", message: error }),
2438
+ /* @__PURE__ */ jsx34(Message, { type: "hint", message: hint })
2439
+ ] });
2440
+ }
2441
+
2442
+ // src/components/interaction/form/RadioGroup/RadioGroup.native.tsx
2443
+ import { StyleSheet as StyleSheet31, View as View28, Text as Text25 } from "react-native";
2444
+ import { jsx as jsx35, jsxs as jsxs21 } from "react/jsx-runtime";
2445
+ var styles31 = StyleSheet31.create({
2446
+ container: {
2447
+ gap: spacing.xs
2448
+ },
2449
+ legend: {
2450
+ fontFamily: font.family.body,
2451
+ fontSize: font.size.body,
2452
+ lineHeight: lineHeight.body,
2453
+ fontWeight: font.weight.semibold
2454
+ },
2455
+ required: {
2456
+ fontWeight: font.weight.body
2457
+ },
2458
+ items: {
2459
+ gap: spacing.xxs
2460
+ }
2461
+ });
2462
+ function RadioGroup({
2463
+ legend,
2464
+ children,
2465
+ error,
2466
+ hint,
2467
+ required,
2468
+ disabled = false,
2469
+ style
2470
+ }) {
2471
+ const { colors: colors2 } = useTheme();
2472
+ return /* @__PURE__ */ jsxs21(
2473
+ View28,
2474
+ {
2475
+ style: [styles31.container, disabled && { opacity: 0.4 }, style],
2476
+ accessibilityRole: "radiogroup",
2477
+ accessibilityLabel: legend,
2478
+ children: [
2479
+ /* @__PURE__ */ jsxs21(Text25, { style: [styles31.legend, { color: colors2.colorOnBg }], children: [
2480
+ legend,
2481
+ required && /* @__PURE__ */ jsx35(Text25, { style: [styles31.required, { color: colors2.colorOnBgSubtle }], children: " *" })
2482
+ ] }),
2483
+ /* @__PURE__ */ jsx35(View28, { style: styles31.items, children }),
2484
+ /* @__PURE__ */ jsx35(Message, { type: "error", message: error }),
2485
+ /* @__PURE__ */ jsx35(Message, { type: "hint", message: hint })
2486
+ ]
2487
+ }
2488
+ );
2489
+ }
2490
+
2491
+ // src/components/interaction/form/FileInput/FileInput.native.tsx
2492
+ import { StyleSheet as StyleSheet32, View as View29, Pressable as Pressable17, Text as Text26 } from "react-native";
2493
+ import { jsx as jsx36, jsxs as jsxs22 } from "react/jsx-runtime";
2494
+ var styles32 = StyleSheet32.create({
2495
+ container: {
2496
+ gap: spacing.xxs
2497
+ },
2498
+ dropZone: {
2499
+ alignItems: "center",
2500
+ justifyContent: "center",
2501
+ gap: spacing.xs,
2502
+ paddingVertical: spacing.xl,
2503
+ paddingHorizontal: spacing.m,
2504
+ borderWidth: 2,
2505
+ borderStyle: "dashed",
2506
+ borderRadius: border.radius.s,
2507
+ minHeight: 120
2508
+ },
2509
+ icon: {
2510
+ fontSize: 28,
2511
+ lineHeight: 32
2512
+ },
2513
+ prompt: {
2514
+ fontFamily: font.family.body,
2515
+ fontSize: font.size.body,
2516
+ lineHeight: lineHeight.body,
2517
+ textAlign: "center"
2518
+ },
2519
+ acceptHint: {
2520
+ fontFamily: font.family.body,
2521
+ fontSize: font.size.bodyS,
2522
+ lineHeight: lineHeight.bodyS,
2523
+ textAlign: "center"
2524
+ },
2525
+ fileList: {
2526
+ gap: spacing.xxs,
2527
+ alignItems: "center"
2528
+ },
2529
+ fileName: {
2530
+ fontFamily: font.family.body,
2531
+ fontSize: font.size.bodyS,
2532
+ lineHeight: lineHeight.bodyS
2533
+ }
2534
+ });
2535
+ function FileInput({
2536
+ label,
2537
+ name,
2538
+ accept,
2539
+ disabled = false,
2540
+ required,
2541
+ error,
2542
+ hint,
2543
+ onSelect,
2544
+ fileNames = [],
2545
+ style
2546
+ }) {
2547
+ const { colors: colors2 } = useTheme();
2548
+ const borderColor = error ? colors2.colorError : colors2.colorBgSubtle;
2549
+ return /* @__PURE__ */ jsxs22(View29, { style: [styles32.container, style], testID: name, children: [
2550
+ /* @__PURE__ */ jsx36(
2551
+ Label,
2552
+ {
2553
+ label: required ? `${label} *` : label
2554
+ }
2555
+ ),
2556
+ /* @__PURE__ */ jsxs22(
2557
+ Pressable17,
2558
+ {
2559
+ onPress: () => !disabled && onSelect?.(),
2560
+ disabled,
2561
+ accessibilityRole: "button",
2562
+ accessibilityLabel: `${label}, tap to select file`,
2563
+ accessibilityState: { disabled },
2564
+ style: ({ pressed }) => [
2565
+ styles32.dropZone,
2566
+ {
2567
+ borderColor,
2568
+ backgroundColor: "transparent"
2569
+ },
2570
+ pressed && { opacity: 0.7 },
2571
+ disabled && { opacity: 0.4 }
2572
+ ],
2573
+ children: [
2574
+ /* @__PURE__ */ jsx36(Text26, { style: [styles32.icon, { color: colors2.colorInteractive }], children: "\u2191" }),
2575
+ /* @__PURE__ */ jsx36(Text26, { style: [styles32.prompt, { color: colors2.colorOnBgSubtle }], children: fileNames.length > 0 ? "Selected files:" : "Tap to select file" }),
2576
+ fileNames.length > 0 && /* @__PURE__ */ jsx36(View29, { style: styles32.fileList, children: fileNames.map((fileName) => /* @__PURE__ */ jsx36(Text26, { style: [styles32.fileName, { color: colors2.colorOnBg }], children: fileName }, fileName)) }),
2577
+ accept && /* @__PURE__ */ jsx36(Text26, { style: [styles32.acceptHint, { color: colors2.colorOnBgSubtle }], children: accept })
2578
+ ]
2579
+ }
2580
+ ),
2581
+ /* @__PURE__ */ jsx36(Message, { type: "error", message: error }),
2582
+ /* @__PURE__ */ jsx36(Message, { type: "hint", message: hint })
2583
+ ] });
2584
+ }
2585
+
2586
+ // src/components/interaction/form/Combobox/Combobox.native.tsx
2587
+ import { useState as useState7, useMemo as useMemo2 } from "react";
2588
+ import {
2589
+ StyleSheet as StyleSheet33,
2590
+ View as View30,
2591
+ TextInput,
2592
+ Pressable as Pressable18,
2593
+ Text as Text27,
2594
+ ScrollView as ScrollView4
2595
+ } from "react-native";
2596
+ import { jsx as jsx37, jsxs as jsxs23 } from "react/jsx-runtime";
2597
+ var MAX_DROPDOWN_HEIGHT = 200;
2598
+ var styles33 = StyleSheet33.create({
2599
+ container: {
2600
+ gap: spacing.xxs
2601
+ },
2602
+ inputWrapper: {
2603
+ position: "relative"
2604
+ },
2605
+ input: {
2606
+ fontFamily: font.family.body,
2607
+ fontSize: font.size.body,
2608
+ lineHeight: lineHeight.body,
2609
+ paddingVertical: spacing.xs,
2610
+ paddingHorizontal: spacing.s,
2611
+ borderWidth: 1,
2612
+ borderRadius: border.radius.full,
2613
+ minHeight: 44
2614
+ },
2615
+ dropdown: {
2616
+ position: "absolute",
2617
+ top: "100%",
2618
+ start: 0,
2619
+ end: 0,
2620
+ maxHeight: MAX_DROPDOWN_HEIGHT,
2621
+ borderWidth: 1,
2622
+ borderTopWidth: 0,
2623
+ borderBottomStartRadius: border.radius.xs,
2624
+ borderBottomEndRadius: border.radius.xs,
2625
+ zIndex: 10
2626
+ },
2627
+ option: {
2628
+ paddingVertical: spacing.xs,
2629
+ paddingHorizontal: spacing.s,
2630
+ minHeight: 44,
2631
+ justifyContent: "center"
2632
+ },
2633
+ optionText: {
2634
+ fontFamily: font.family.body,
2635
+ fontSize: font.size.body,
2636
+ lineHeight: lineHeight.body
2637
+ }
2638
+ });
2639
+ function Combobox({
2640
+ label,
2641
+ name,
2642
+ options,
2643
+ placeholder,
2644
+ value,
2645
+ onChange,
2646
+ disabled = false,
2647
+ error,
2648
+ hint,
2649
+ style
2650
+ }) {
2651
+ const { colors: colors2 } = useTheme();
2652
+ const selectedOption = useMemo2(
2653
+ () => options.find((o) => o.value === value),
2654
+ [options, value]
2655
+ );
2656
+ const [inputValue, setInputValue] = useState7(selectedOption?.label ?? "");
2657
+ const [isOpen, setIsOpen] = useState7(false);
2658
+ const filtered = useMemo2(
2659
+ () => options.filter(
2660
+ (o) => o.label.toLowerCase().includes(inputValue.toLowerCase())
2661
+ ),
2662
+ [options, inputValue]
2663
+ );
2664
+ const selectOption = (option) => {
2665
+ setInputValue(option.label);
2666
+ setIsOpen(false);
2667
+ onChange?.(option.value);
2668
+ };
2669
+ const handleChangeText = (text) => {
2670
+ setInputValue(text);
2671
+ setIsOpen(true);
2672
+ };
2673
+ const handleFocus = () => {
2674
+ setIsOpen(true);
2675
+ };
2676
+ const handleBlur = () => {
2677
+ setTimeout(() => setIsOpen(false), 150);
2678
+ };
2679
+ const borderColor = error ? colors2.colorError : colors2.colorOnBg;
2680
+ return /* @__PURE__ */ jsxs23(View30, { style: [styles33.container, style], children: [
2681
+ /* @__PURE__ */ jsx37(Label, { label }),
2682
+ /* @__PURE__ */ jsxs23(View30, { style: styles33.inputWrapper, children: [
2683
+ /* @__PURE__ */ jsx37(
2684
+ TextInput,
2685
+ {
2686
+ value: inputValue,
2687
+ onChangeText: handleChangeText,
2688
+ onFocus: handleFocus,
2689
+ onBlur: handleBlur,
2690
+ placeholder,
2691
+ placeholderTextColor: colors2.colorOnBgSubtle,
2692
+ editable: !disabled,
2693
+ accessibilityRole: "combobox",
2694
+ accessibilityLabel: typeof label === "string" ? label : name,
2695
+ accessibilityState: { disabled, expanded: isOpen },
2696
+ style: [
2697
+ styles33.input,
2698
+ {
2699
+ borderColor,
2700
+ color: colors2.colorOnBg,
2701
+ backgroundColor: colors2.colorBg
2702
+ },
2703
+ disabled && { opacity: 0.4 }
2704
+ ]
2705
+ }
2706
+ ),
2707
+ isOpen && filtered.length > 0 && /* @__PURE__ */ jsx37(
2708
+ ScrollView4,
2709
+ {
2710
+ style: [
2711
+ styles33.dropdown,
2712
+ {
2713
+ borderColor: colors2.colorBgSubtle,
2714
+ backgroundColor: colors2.colorBg
2715
+ }
2716
+ ],
2717
+ keyboardShouldPersistTaps: "handled",
2718
+ nestedScrollEnabled: true,
2719
+ children: filtered.map((option) => {
2720
+ const isSelected = option.value === value;
2721
+ const isDisabled = option.disabled;
2722
+ return /* @__PURE__ */ jsx37(
2723
+ Pressable18,
2724
+ {
2725
+ onPress: () => !isDisabled && selectOption(option),
2726
+ disabled: isDisabled,
2727
+ accessibilityRole: "menuitem",
2728
+ accessibilityLabel: option.label,
2729
+ accessibilityState: { selected: isSelected, disabled: isDisabled },
2730
+ style: ({ pressed }) => [
2731
+ styles33.option,
2732
+ isSelected && { backgroundColor: colors2.colorBlueSubtle },
2733
+ pressed && !isDisabled && { backgroundColor: colors2.colorBgSubtle },
2734
+ isDisabled && { opacity: 0.4 }
2735
+ ],
2736
+ children: /* @__PURE__ */ jsx37(
2737
+ Text27,
2738
+ {
2739
+ style: [
2740
+ styles33.optionText,
2741
+ {
2742
+ color: isSelected ? colors2.colorInteractive : colors2.colorOnBg
2743
+ },
2744
+ isSelected && { fontWeight: font.weight.semibold }
2745
+ ],
2746
+ children: option.label
2747
+ }
2748
+ )
2749
+ },
2750
+ option.value
2751
+ );
2752
+ })
2753
+ }
2754
+ )
2755
+ ] }),
2756
+ /* @__PURE__ */ jsx37(Message, { type: "error", message: error }),
2757
+ /* @__PURE__ */ jsx37(Message, { type: "hint", message: hint })
2758
+ ] });
2759
+ }
2760
+
2761
+ // src/components/interaction/form/SegmentedControl/SegmentedControl.native.tsx
2762
+ import { Children } from "react";
2763
+ import { StyleSheet as StyleSheet34, View as View31, Pressable as Pressable19, Text as Text28 } from "react-native";
2764
+ import { jsx as jsx38 } from "react/jsx-runtime";
2765
+ var sizeTokens2 = {
2766
+ small: { height: 32, fontSize: font.size.bodyS, px: spacing.s },
2767
+ medium: { height: 40, fontSize: font.size.body, px: spacing.m },
2768
+ large: { height: 48, fontSize: font.size.body, px: spacing.l }
2769
+ };
2770
+ var styles34 = StyleSheet34.create({
2771
+ track: {
2772
+ flexDirection: "row",
2773
+ borderRadius: border.radius.full,
2774
+ overflow: "hidden"
2775
+ },
2776
+ item: {
2777
+ flex: 1,
2778
+ alignItems: "center",
2779
+ justifyContent: "center",
2780
+ minHeight: 44
2781
+ },
2782
+ label: {
2783
+ fontFamily: font.family.body,
2784
+ fontWeight: font.weight.semibold,
2785
+ textAlign: "center"
2786
+ }
2787
+ });
2788
+ function SegmentedControl({
2789
+ selectedIndex = 0,
2790
+ disabled = false,
2791
+ size = "medium",
2792
+ variant = "outline",
2793
+ children,
2794
+ accessibilityLabel,
2795
+ onValueChange,
2796
+ style
2797
+ }) {
2798
+ const { colors: colors2 } = useTheme();
2799
+ const { height, fontSize, px } = sizeTokens2[size];
2800
+ const items = Children.toArray(children);
2801
+ const trackStyle = variant === "filled" ? { backgroundColor: colors2.colorBgSubtle } : { backgroundColor: "transparent", borderWidth: 1, borderColor: colors2.colorBgSubtle };
2802
+ return /* @__PURE__ */ jsx38(
2803
+ View31,
2804
+ {
2805
+ style: [styles34.track, trackStyle, { borderRadius: border.radius.full }, style],
2806
+ accessibilityRole: "tablist",
2807
+ accessibilityLabel,
2808
+ children: items.map((child, index) => {
2809
+ const isActive = index === selectedIndex;
2810
+ const activeStyle = variant === "filled" ? { backgroundColor: colors2.colorInteractive } : { borderWidth: 2, borderColor: colors2.colorInteractive };
2811
+ const inactiveStyle = variant === "filled" ? {} : {};
2812
+ const textColor = variant === "filled" && isActive ? colors2.colorOnInteractive : isActive ? colors2.colorInteractive : colors2.colorOnBgSubtle;
2813
+ const label = typeof child === "string" || typeof child === "number" ? String(child) : null;
2814
+ return /* @__PURE__ */ jsx38(
2815
+ Pressable19,
2816
+ {
2817
+ onPress: () => !disabled && onValueChange?.(index),
2818
+ disabled,
2819
+ accessibilityRole: "tab",
2820
+ accessibilityLabel: label ?? void 0,
2821
+ accessibilityState: { selected: isActive, disabled },
2822
+ style: ({ pressed }) => [
2823
+ styles34.item,
2824
+ { height, paddingHorizontal: px },
2825
+ isActive ? activeStyle : inactiveStyle,
2826
+ variant === "filled" && isActive && { borderRadius: border.radius.full },
2827
+ pressed && !disabled && { opacity: 0.7 },
2828
+ disabled && { opacity: 0.4 }
2829
+ ],
2830
+ children: label !== null ? /* @__PURE__ */ jsx38(Text28, { style: [styles34.label, { fontSize, color: textColor }], children: label }) : child
2831
+ },
2832
+ index
2833
+ );
2834
+ })
2835
+ }
2836
+ );
2837
+ }
2838
+
2839
+ // src/components/interaction/form/FormInput/FormInput.native.tsx
2840
+ import { useState as useState8 } from "react";
2841
+ import {
2842
+ StyleSheet as StyleSheet35,
2843
+ View as View32,
2844
+ TextInput as TextInput2
2845
+ } from "react-native";
2846
+ import { jsx as jsx39, jsxs as jsxs24 } from "react/jsx-runtime";
2847
+ var keyboardTypeMap = {
2848
+ text: "default",
2849
+ email: "email-address",
2850
+ password: "default",
2851
+ tel: "phone-pad",
2852
+ url: "url",
2853
+ number: "numeric",
2854
+ search: "default"
2855
+ };
2856
+ var styles35 = StyleSheet35.create({
2857
+ container: {
2858
+ gap: spacing.xxs
2859
+ },
2860
+ input: {
2861
+ fontFamily: font.family.body,
2862
+ fontSize: font.size.body,
2863
+ lineHeight: lineHeight.body,
2864
+ paddingHorizontal: spacing.s,
2865
+ paddingVertical: spacing.xs,
2866
+ borderWidth: 1,
2867
+ borderRadius: border.radius.full,
2868
+ minHeight: 44
2869
+ }
2870
+ });
2871
+ function FormInput({
2872
+ label,
2873
+ name,
2874
+ type = "text",
2875
+ value,
2876
+ defaultValue,
2877
+ placeholder,
2878
+ error,
2879
+ hint,
2880
+ disabled = false,
2881
+ onChange,
2882
+ onBlur,
2883
+ onFocus,
2884
+ style
2885
+ }) {
2886
+ const { colors: colors2 } = useTheme();
2887
+ const [focused, setFocused] = useState8(false);
2888
+ const borderColor = error ? colors2.colorError : focused ? colors2.colorInteractive : colors2.colorOnBg;
2889
+ return /* @__PURE__ */ jsxs24(View32, { style: [styles35.container, style], children: [
2890
+ /* @__PURE__ */ jsx39(Label, { label }),
2891
+ /* @__PURE__ */ jsx39(
2892
+ TextInput2,
2893
+ {
2894
+ accessibilityLabel: typeof label === "string" ? label : name,
2895
+ accessibilityState: { disabled },
2896
+ accessibilityHint: hint,
2897
+ value,
2898
+ defaultValue,
2899
+ placeholder,
2900
+ placeholderTextColor: colors2.colorOnBgSubtle,
2901
+ keyboardType: keyboardTypeMap[type],
2902
+ secureTextEntry: type === "password",
2903
+ autoCapitalize: type === "email" || type === "url" ? "none" : "sentences",
2904
+ autoComplete: type === "email" ? "email" : type === "tel" ? "tel" : void 0,
2905
+ editable: !disabled,
2906
+ onChangeText: onChange,
2907
+ onFocus: () => {
2908
+ setFocused(true);
2909
+ onFocus?.();
2910
+ },
2911
+ onBlur: () => {
2912
+ setFocused(false);
2913
+ onBlur?.();
2914
+ },
2915
+ style: [
2916
+ styles35.input,
2917
+ {
2918
+ borderColor,
2919
+ color: colors2.colorOnBg,
2920
+ backgroundColor: colors2.colorBg
2921
+ },
2922
+ disabled && { opacity: 0.4 }
2923
+ ]
2924
+ }
2925
+ ),
2926
+ /* @__PURE__ */ jsx39(Message, { type: "error", message: error }),
2927
+ /* @__PURE__ */ jsx39(Message, { type: "hint", message: hint })
2928
+ ] });
2929
+ }
2930
+
2931
+ // src/components/interaction/form/Textarea/Textarea.native.tsx
2932
+ import { useState as useState9 } from "react";
2933
+ import {
2934
+ StyleSheet as StyleSheet36,
2935
+ View as View33,
2936
+ TextInput as TextInput3
2937
+ } from "react-native";
2938
+ import { jsx as jsx40, jsxs as jsxs25 } from "react/jsx-runtime";
2939
+ var styles36 = StyleSheet36.create({
2940
+ container: {
2941
+ gap: spacing.xxs
2942
+ },
2943
+ textarea: {
2944
+ fontFamily: font.family.body,
2945
+ fontSize: font.size.body,
2946
+ lineHeight: lineHeight.body,
2947
+ paddingHorizontal: spacing.s,
2948
+ paddingVertical: spacing.xs,
2949
+ borderWidth: 1,
2950
+ borderRadius: border.radius.xs,
2951
+ minHeight: 100,
2952
+ textAlignVertical: "top"
2953
+ }
2954
+ });
2955
+ function Textarea({
2956
+ label,
2957
+ name,
2958
+ value,
2959
+ defaultValue,
2960
+ placeholder,
2961
+ error,
2962
+ hint,
2963
+ disabled = false,
2964
+ numberOfLines = 4,
2965
+ onChange,
2966
+ onBlur,
2967
+ onFocus,
2968
+ style
2969
+ }) {
2970
+ const { colors: colors2 } = useTheme();
2971
+ const [focused, setFocused] = useState9(false);
2972
+ const borderColor = error ? colors2.colorError : focused ? colors2.colorInteractive : colors2.colorOnBg;
2973
+ return /* @__PURE__ */ jsxs25(View33, { style: [styles36.container, style], children: [
2974
+ /* @__PURE__ */ jsx40(Label, { label }),
2975
+ /* @__PURE__ */ jsx40(
2976
+ TextInput3,
2977
+ {
2978
+ accessibilityLabel: typeof label === "string" ? label : name,
2979
+ accessibilityState: { disabled },
2980
+ accessibilityHint: hint,
2981
+ multiline: true,
2982
+ numberOfLines,
2983
+ value,
2984
+ defaultValue,
2985
+ placeholder,
2986
+ placeholderTextColor: colors2.colorOnBgSubtle,
2987
+ editable: !disabled,
2988
+ onChangeText: onChange,
2989
+ onFocus: () => {
2990
+ setFocused(true);
2991
+ onFocus?.();
2992
+ },
2993
+ onBlur: () => {
2994
+ setFocused(false);
2995
+ onBlur?.();
2996
+ },
2997
+ style: [
2998
+ styles36.textarea,
2999
+ {
3000
+ borderColor,
3001
+ color: colors2.colorOnBg,
3002
+ backgroundColor: colors2.colorBg
3003
+ },
3004
+ disabled && { opacity: 0.4 }
3005
+ ]
3006
+ }
3007
+ ),
3008
+ /* @__PURE__ */ jsx40(Message, { type: "error", message: error }),
3009
+ /* @__PURE__ */ jsx40(Message, { type: "hint", message: hint })
3010
+ ] });
3011
+ }
3012
+
3013
+ // src/components/interaction/form/Select/Select.native.tsx
3014
+ import { useState as useState10 } from "react";
3015
+ import {
3016
+ StyleSheet as StyleSheet37,
3017
+ View as View34,
3018
+ Text as Text29,
3019
+ Pressable as Pressable20,
3020
+ Modal,
3021
+ FlatList,
3022
+ SafeAreaView
3023
+ } from "react-native";
3024
+ import { jsx as jsx41, jsxs as jsxs26 } from "react/jsx-runtime";
3025
+ var styles37 = StyleSheet37.create({
3026
+ container: {
3027
+ gap: spacing.xxs
3028
+ },
3029
+ trigger: {
3030
+ flexDirection: "row",
3031
+ alignItems: "center",
3032
+ justifyContent: "space-between",
3033
+ paddingHorizontal: spacing.s,
3034
+ paddingVertical: spacing.xs,
3035
+ borderWidth: 1,
3036
+ borderRadius: border.radius.full,
3037
+ minHeight: 44
3038
+ },
3039
+ triggerText: {
3040
+ fontFamily: font.family.body,
3041
+ fontSize: font.size.body,
3042
+ lineHeight: lineHeight.body,
3043
+ flex: 1
3044
+ },
3045
+ chevron: {
3046
+ fontFamily: font.family.body,
3047
+ fontSize: font.size.body,
3048
+ marginStart: spacing.xs
3049
+ },
3050
+ overlay: {
3051
+ flex: 1,
3052
+ justifyContent: "flex-end",
3053
+ backgroundColor: "rgba(0, 0, 0, 0.5)"
3054
+ },
3055
+ sheet: {
3056
+ maxHeight: "60%",
3057
+ borderTopStartRadius: border.radius.m,
3058
+ borderTopEndRadius: border.radius.m,
3059
+ paddingTop: spacing.m,
3060
+ paddingBottom: spacing.xxxl
3061
+ },
3062
+ sheetHeader: {
3063
+ flexDirection: "row",
3064
+ justifyContent: "space-between",
3065
+ alignItems: "center",
3066
+ paddingHorizontal: spacing.m,
3067
+ paddingBottom: spacing.s
3068
+ },
3069
+ sheetTitle: {
3070
+ fontFamily: font.family.body,
3071
+ fontSize: font.size.heading3,
3072
+ fontWeight: font.weight.semibold
3073
+ },
3074
+ closeText: {
3075
+ fontFamily: font.family.body,
3076
+ fontSize: font.size.body,
3077
+ fontWeight: font.weight.semibold
3078
+ },
3079
+ optionItem: {
3080
+ paddingHorizontal: spacing.m,
3081
+ paddingVertical: spacing.s,
3082
+ minHeight: 44,
3083
+ justifyContent: "center"
3084
+ },
3085
+ optionText: {
3086
+ fontFamily: font.family.body,
3087
+ fontSize: font.size.body,
3088
+ lineHeight: lineHeight.body
3089
+ }
3090
+ });
3091
+ function Select({
3092
+ label,
3093
+ name,
3094
+ options,
3095
+ placeholder = "Select an option",
3096
+ value,
3097
+ error,
3098
+ hint,
3099
+ disabled = false,
3100
+ onChange,
3101
+ style
3102
+ }) {
3103
+ const { colors: colors2 } = useTheme();
3104
+ const [open, setOpen] = useState10(false);
3105
+ const selectedOption = options.find((o) => o.value === value);
3106
+ const displayText = selectedOption?.label ?? placeholder;
3107
+ const isPlaceholder = !selectedOption;
3108
+ const borderColor = error ? colors2.colorError : open ? colors2.colorInteractive : colors2.colorOnBg;
3109
+ const handleSelect = (optionValue) => {
3110
+ onChange?.(optionValue);
3111
+ setOpen(false);
3112
+ };
3113
+ return /* @__PURE__ */ jsxs26(View34, { style: [styles37.container, style], children: [
3114
+ /* @__PURE__ */ jsx41(Label, { label }),
3115
+ /* @__PURE__ */ jsxs26(
3116
+ Pressable20,
3117
+ {
3118
+ accessibilityRole: "button",
3119
+ accessibilityLabel: typeof label === "string" ? `${label}, ${displayText}` : name,
3120
+ accessibilityState: { disabled, expanded: open },
3121
+ accessibilityHint: "Double tap to open options",
3122
+ disabled,
3123
+ onPress: () => setOpen(true),
3124
+ style: [
3125
+ styles37.trigger,
3126
+ {
3127
+ borderColor,
3128
+ backgroundColor: colors2.colorBg
3129
+ },
3130
+ disabled && { opacity: 0.4 }
3131
+ ],
3132
+ children: [
3133
+ /* @__PURE__ */ jsx41(
3134
+ Text29,
3135
+ {
3136
+ style: [
3137
+ styles37.triggerText,
3138
+ {
3139
+ color: isPlaceholder ? colors2.colorOnBgSubtle : colors2.colorOnBg
3140
+ }
3141
+ ],
3142
+ children: displayText
3143
+ }
3144
+ ),
3145
+ /* @__PURE__ */ jsx41(Text29, { style: [styles37.chevron, { color: colors2.colorOnBgSubtle }], "aria-hidden": true, children: "\u25BE" })
3146
+ ]
3147
+ }
3148
+ ),
3149
+ /* @__PURE__ */ jsx41(
3150
+ Modal,
3151
+ {
3152
+ visible: open,
3153
+ transparent: true,
3154
+ animationType: "slide",
3155
+ onRequestClose: () => setOpen(false),
3156
+ children: /* @__PURE__ */ jsx41(
3157
+ Pressable20,
3158
+ {
3159
+ style: styles37.overlay,
3160
+ onPress: () => setOpen(false),
3161
+ accessibilityRole: "button",
3162
+ accessibilityLabel: "Close options",
3163
+ children: /* @__PURE__ */ jsx41(
3164
+ Pressable20,
3165
+ {
3166
+ style: [styles37.sheet, { backgroundColor: colors2.colorBg }],
3167
+ onPress: () => {
3168
+ },
3169
+ children: /* @__PURE__ */ jsxs26(SafeAreaView, { children: [
3170
+ /* @__PURE__ */ jsxs26(View34, { style: styles37.sheetHeader, children: [
3171
+ /* @__PURE__ */ jsx41(Text29, { style: [styles37.sheetTitle, { color: colors2.colorOnBg }], children: typeof label === "string" ? label : "Select" }),
3172
+ /* @__PURE__ */ jsx41(
3173
+ Pressable20,
3174
+ {
3175
+ accessibilityRole: "button",
3176
+ accessibilityLabel: "Close",
3177
+ onPress: () => setOpen(false),
3178
+ hitSlop: 8,
3179
+ children: /* @__PURE__ */ jsx41(Text29, { style: [styles37.closeText, { color: colors2.colorInteractive }], children: "Done" })
3180
+ }
3181
+ )
3182
+ ] }),
3183
+ /* @__PURE__ */ jsx41(
3184
+ FlatList,
3185
+ {
3186
+ data: options,
3187
+ keyExtractor: (item) => item.value,
3188
+ renderItem: ({ item }) => {
3189
+ const isSelected = item.value === value;
3190
+ return /* @__PURE__ */ jsx41(
3191
+ Pressable20,
3192
+ {
3193
+ accessibilityRole: "button",
3194
+ accessibilityLabel: item.label,
3195
+ accessibilityState: {
3196
+ selected: isSelected,
3197
+ disabled: item.disabled
3198
+ },
3199
+ disabled: item.disabled,
3200
+ onPress: () => handleSelect(item.value),
3201
+ style: ({ pressed }) => [
3202
+ styles37.optionItem,
3203
+ isSelected && { backgroundColor: colors2.colorBgSubtle },
3204
+ pressed && { opacity: 0.7 },
3205
+ item.disabled && { opacity: 0.4 }
3206
+ ],
3207
+ children: /* @__PURE__ */ jsx41(
3208
+ Text29,
3209
+ {
3210
+ style: [
3211
+ styles37.optionText,
3212
+ {
3213
+ color: isSelected ? colors2.colorInteractive : colors2.colorOnBg,
3214
+ fontWeight: isSelected ? font.weight.semibold : font.weight.body
3215
+ }
3216
+ ],
3217
+ children: item.label
3218
+ }
3219
+ )
3220
+ }
3221
+ );
3222
+ }
3223
+ }
3224
+ )
3225
+ ] })
3226
+ }
3227
+ )
3228
+ }
3229
+ )
3230
+ }
3231
+ ),
3232
+ /* @__PURE__ */ jsx41(Message, { type: "error", message: error }),
3233
+ /* @__PURE__ */ jsx41(Message, { type: "hint", message: hint })
3234
+ ] });
3235
+ }
3236
+
3237
+ // src/components/interaction/form/Slider/Slider.native.tsx
3238
+ import { useState as useState11 } from "react";
3239
+ import {
3240
+ StyleSheet as StyleSheet38,
3241
+ View as View35,
3242
+ Text as Text30
3243
+ } from "react-native";
3244
+ import { jsx as jsx42, jsxs as jsxs27 } from "react/jsx-runtime";
3245
+ var TRACK_HEIGHT = 6;
3246
+ var THUMB_SIZE = 24;
3247
+ var styles38 = StyleSheet38.create({
3248
+ container: {
3249
+ gap: spacing.xxs
3250
+ },
3251
+ labelRow: {
3252
+ flexDirection: "row",
3253
+ justifyContent: "space-between",
3254
+ alignItems: "center"
3255
+ },
3256
+ valueText: {
3257
+ fontFamily: font.family.body,
3258
+ fontSize: font.size.bodyS,
3259
+ lineHeight: lineHeight.bodyS,
3260
+ fontWeight: font.weight.semibold
3261
+ },
3262
+ trackContainer: {
3263
+ height: THUMB_SIZE + spacing.xs * 2,
3264
+ justifyContent: "center",
3265
+ paddingHorizontal: THUMB_SIZE / 2
3266
+ },
3267
+ track: {
3268
+ height: TRACK_HEIGHT,
3269
+ borderRadius: TRACK_HEIGHT / 2,
3270
+ overflow: "hidden"
3271
+ },
3272
+ fill: {
3273
+ height: TRACK_HEIGHT,
3274
+ borderRadius: TRACK_HEIGHT / 2
3275
+ },
3276
+ thumb: {
3277
+ position: "absolute",
3278
+ width: THUMB_SIZE,
3279
+ height: THUMB_SIZE,
3280
+ borderRadius: THUMB_SIZE / 2,
3281
+ top: "50%",
3282
+ marginTop: -(THUMB_SIZE / 2),
3283
+ borderWidth: 2
3284
+ }
3285
+ });
3286
+ function clampValue(v, min, max) {
3287
+ return Math.min(max, Math.max(min, v));
3288
+ }
3289
+ function snapToStep(v, min, step) {
3290
+ return Math.round((v - min) / step) * step + min;
3291
+ }
3292
+ function Slider({
3293
+ label,
3294
+ name: _name,
3295
+ // eslint-disable-line @typescript-eslint/no-unused-vars
3296
+ value,
3297
+ defaultValue,
3298
+ min = 0,
3299
+ max = 100,
3300
+ step = 1,
3301
+ showValue = false,
3302
+ disabled = false,
3303
+ error,
3304
+ hint,
3305
+ onChange,
3306
+ style
3307
+ }) {
3308
+ const { colors: colors2 } = useTheme();
3309
+ const isControlled = value !== void 0;
3310
+ const [internalValue, setInternalValue] = useState11(defaultValue ?? min);
3311
+ const [trackWidth, setTrackWidth] = useState11(0);
3312
+ const currentValue = isControlled ? value : internalValue;
3313
+ const fillPct = max > min ? (currentValue - min) / (max - min) * 100 : 0;
3314
+ const updateValue = (v) => {
3315
+ const clamped = clampValue(v, min, max);
3316
+ const snapped = snapToStep(clamped, min, step);
3317
+ if (!isControlled) setInternalValue(snapped);
3318
+ onChange?.(snapped);
3319
+ };
3320
+ const handleTrackLayout = (e) => {
3321
+ setTrackWidth(e.nativeEvent.layout.width);
3322
+ };
3323
+ const valueFromTouch = (pageX, layoutX) => {
3324
+ const x = pageX - layoutX;
3325
+ const pct = clampValue(x / trackWidth, 0, 1);
3326
+ return pct * (max - min) + min;
3327
+ };
3328
+ const handleStartShouldSetResponder = () => !disabled;
3329
+ const handleResponderGrant = (e) => {
3330
+ const target = e.currentTarget;
3331
+ target.measure((_x, _y, _w, _h, pageX) => {
3332
+ updateValue(valueFromTouch(e.nativeEvent.pageX, pageX));
3333
+ });
3334
+ };
3335
+ const handleResponderMove = (e) => {
3336
+ const target = e.currentTarget;
3337
+ target.measure((_x, _y, _w, _h, pageX) => {
3338
+ updateValue(valueFromTouch(e.nativeEvent.pageX, pageX));
3339
+ });
3340
+ };
3341
+ return /* @__PURE__ */ jsxs27(
3342
+ View35,
3343
+ {
3344
+ style: [styles38.container, style],
3345
+ accessibilityRole: "adjustable",
3346
+ accessibilityLabel: label,
3347
+ accessibilityValue: { min, max, now: currentValue, text: String(currentValue) },
3348
+ accessibilityState: { disabled },
3349
+ children: [
3350
+ /* @__PURE__ */ jsxs27(View35, { style: styles38.labelRow, children: [
3351
+ /* @__PURE__ */ jsx42(Label, { label }),
3352
+ showValue && /* @__PURE__ */ jsx42(Text30, { style: [styles38.valueText, { color: colors2.colorOnBg }], children: currentValue })
3353
+ ] }),
3354
+ /* @__PURE__ */ jsxs27(
3355
+ View35,
3356
+ {
3357
+ style: [styles38.trackContainer, disabled && { opacity: 0.4 }],
3358
+ onLayout: handleTrackLayout,
3359
+ onStartShouldSetResponder: handleStartShouldSetResponder,
3360
+ onMoveShouldSetResponder: handleStartShouldSetResponder,
3361
+ onResponderGrant: handleResponderGrant,
3362
+ onResponderMove: handleResponderMove,
3363
+ children: [
3364
+ /* @__PURE__ */ jsx42(View35, { style: [styles38.track, { backgroundColor: colors2.colorBgSubtle }], children: /* @__PURE__ */ jsx42(
3365
+ View35,
3366
+ {
3367
+ style: [
3368
+ styles38.fill,
3369
+ {
3370
+ width: `${fillPct}%`,
3371
+ backgroundColor: error ? colors2.colorError : colors2.colorInteractive
3372
+ }
3373
+ ]
3374
+ }
3375
+ ) }),
3376
+ /* @__PURE__ */ jsx42(
3377
+ View35,
3378
+ {
3379
+ style: [
3380
+ styles38.thumb,
3381
+ {
3382
+ start: `${fillPct}%`,
3383
+ marginStart: -(THUMB_SIZE / 2),
3384
+ backgroundColor: colors2.colorBg,
3385
+ borderColor: error ? colors2.colorError : colors2.colorInteractive
3386
+ }
3387
+ ]
3388
+ }
3389
+ )
3390
+ ]
3391
+ }
3392
+ ),
3393
+ /* @__PURE__ */ jsx42(Message, { type: "error", message: error }),
3394
+ /* @__PURE__ */ jsx42(Message, { type: "hint", message: hint })
3395
+ ]
3396
+ }
3397
+ );
3398
+ }
3399
+
3400
+ // src/components/interaction/form/NumberInput/NumberInput.native.tsx
3401
+ import { useState as useState12 } from "react";
3402
+ import {
3403
+ StyleSheet as StyleSheet39,
3404
+ View as View36,
3405
+ TextInput as TextInput4,
3406
+ Text as Text31,
3407
+ Pressable as Pressable21
3408
+ } from "react-native";
3409
+ import { jsx as jsx43, jsxs as jsxs28 } from "react/jsx-runtime";
3410
+ var STEPPER_SIZE = 44;
3411
+ var styles39 = StyleSheet39.create({
3412
+ container: {
3413
+ gap: spacing.xxs
3414
+ },
3415
+ inputRow: {
3416
+ flexDirection: "row",
3417
+ alignItems: "center"
3418
+ },
3419
+ stepper: {
3420
+ width: STEPPER_SIZE,
3421
+ height: STEPPER_SIZE,
3422
+ alignItems: "center",
3423
+ justifyContent: "center",
3424
+ borderWidth: 1
3425
+ },
3426
+ stepperStart: {
3427
+ borderTopStartRadius: border.radius.full,
3428
+ borderBottomStartRadius: border.radius.full,
3429
+ borderEndWidth: 0
3430
+ },
3431
+ stepperEnd: {
3432
+ borderTopEndRadius: border.radius.full,
3433
+ borderBottomEndRadius: border.radius.full,
3434
+ borderStartWidth: 0
3435
+ },
3436
+ stepperText: {
3437
+ fontSize: 20,
3438
+ fontWeight: font.weight.semibold,
3439
+ lineHeight: 24
3440
+ },
3441
+ input: {
3442
+ flex: 1,
3443
+ fontFamily: font.family.body,
3444
+ fontSize: font.size.body,
3445
+ lineHeight: lineHeight.body,
3446
+ textAlign: "center",
3447
+ paddingHorizontal: spacing.xs,
3448
+ paddingVertical: spacing.xs,
3449
+ borderTopWidth: 1,
3450
+ borderBottomWidth: 1,
3451
+ minHeight: STEPPER_SIZE
3452
+ }
3453
+ });
3454
+ function NumberInput({
3455
+ label,
3456
+ name: _name,
3457
+ // eslint-disable-line @typescript-eslint/no-unused-vars
3458
+ value,
3459
+ defaultValue,
3460
+ min,
3461
+ max,
3462
+ step = 1,
3463
+ disabled = false,
3464
+ error,
3465
+ hint,
3466
+ onChange,
3467
+ style
3468
+ }) {
3469
+ const { colors: colors2 } = useTheme();
3470
+ const isControlled = value !== void 0;
3471
+ const [internalValue, setInternalValue] = useState12(defaultValue ?? 0);
3472
+ const currentValue = isControlled ? value : internalValue;
3473
+ const clamp = (v) => {
3474
+ const withMin = min !== void 0 ? Math.max(min, v) : v;
3475
+ return max !== void 0 ? Math.min(max, withMin) : withMin;
3476
+ };
3477
+ const update = (next) => {
3478
+ const clamped = clamp(next);
3479
+ if (!isControlled) setInternalValue(clamped);
3480
+ onChange?.(clamped);
3481
+ };
3482
+ const canDecrease = min === void 0 || currentValue > min;
3483
+ const canIncrease = max === void 0 || currentValue < max;
3484
+ const borderColor = error ? colors2.colorError : colors2.colorOnBg;
3485
+ return /* @__PURE__ */ jsxs28(View36, { style: [styles39.container, style], children: [
3486
+ /* @__PURE__ */ jsx43(Label, { label }),
3487
+ /* @__PURE__ */ jsxs28(View36, { style: [styles39.inputRow, disabled && { opacity: 0.4 }], children: [
3488
+ /* @__PURE__ */ jsx43(
3489
+ Pressable21,
3490
+ {
3491
+ accessibilityRole: "button",
3492
+ accessibilityLabel: "Decrease",
3493
+ accessibilityState: { disabled: disabled || !canDecrease },
3494
+ disabled: disabled || !canDecrease,
3495
+ onPress: () => update(currentValue - step),
3496
+ style: ({ pressed }) => [
3497
+ styles39.stepper,
3498
+ styles39.stepperStart,
3499
+ {
3500
+ borderColor,
3501
+ backgroundColor: colors2.colorBgSubtle
3502
+ },
3503
+ pressed && { opacity: 0.7 },
3504
+ (disabled || !canDecrease) && { opacity: 0.4 }
3505
+ ],
3506
+ children: /* @__PURE__ */ jsx43(
3507
+ Text31,
3508
+ {
3509
+ style: [styles39.stepperText, { color: colors2.colorOnBg }],
3510
+ "aria-hidden": true,
3511
+ children: "\u2212"
3512
+ }
3513
+ )
3514
+ }
3515
+ ),
3516
+ /* @__PURE__ */ jsx43(
3517
+ TextInput4,
3518
+ {
3519
+ accessibilityLabel: label,
3520
+ accessibilityState: { disabled },
3521
+ accessibilityValue: {
3522
+ min,
3523
+ max,
3524
+ now: currentValue,
3525
+ text: String(currentValue)
3526
+ },
3527
+ keyboardType: "numeric",
3528
+ value: String(currentValue),
3529
+ editable: !disabled,
3530
+ onChangeText: (text) => {
3531
+ const parsed = parseFloat(text);
3532
+ const safe = isNaN(parsed) ? 0 : parsed;
3533
+ update(safe);
3534
+ },
3535
+ style: [
3536
+ styles39.input,
3537
+ {
3538
+ borderColor,
3539
+ color: colors2.colorOnBg,
3540
+ backgroundColor: colors2.colorBg
3541
+ }
3542
+ ]
3543
+ }
3544
+ ),
3545
+ /* @__PURE__ */ jsx43(
3546
+ Pressable21,
3547
+ {
3548
+ accessibilityRole: "button",
3549
+ accessibilityLabel: "Increase",
3550
+ accessibilityState: { disabled: disabled || !canIncrease },
3551
+ disabled: disabled || !canIncrease,
3552
+ onPress: () => update(currentValue + step),
3553
+ style: ({ pressed }) => [
3554
+ styles39.stepper,
3555
+ styles39.stepperEnd,
3556
+ {
3557
+ borderColor,
3558
+ backgroundColor: colors2.colorBgSubtle
3559
+ },
3560
+ pressed && { opacity: 0.7 },
3561
+ (disabled || !canIncrease) && { opacity: 0.4 }
3562
+ ],
3563
+ children: /* @__PURE__ */ jsx43(
3564
+ Text31,
3565
+ {
3566
+ style: [styles39.stepperText, { color: colors2.colorOnBg }],
3567
+ "aria-hidden": true,
3568
+ children: "+"
3569
+ }
3570
+ )
3571
+ }
3572
+ )
3573
+ ] }),
3574
+ /* @__PURE__ */ jsx43(Message, { type: "error", message: error }),
3575
+ /* @__PURE__ */ jsx43(Message, { type: "hint", message: hint })
3576
+ ] });
3577
+ }
3578
+
3579
+ // src/components/interaction/Dialog/Dialog.native.tsx
3580
+ import {
3581
+ Modal as Modal2,
3582
+ View as View37,
3583
+ Pressable as Pressable22,
3584
+ Text as Text32,
3585
+ StyleSheet as StyleSheet40
3586
+ } from "react-native";
3587
+ import { jsx as jsx44, jsxs as jsxs29 } from "react/jsx-runtime";
3588
+ var styles40 = StyleSheet40.create({
3589
+ overlay: {
3590
+ flex: 1,
3591
+ justifyContent: "center",
3592
+ alignItems: "center",
3593
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
3594
+ padding: spacing.m
3595
+ },
3596
+ panel: {
3597
+ width: "100%",
3598
+ maxWidth: 480,
3599
+ borderRadius: border.radius.m,
3600
+ padding: spacing.l,
3601
+ paddingTop: spacing.xl,
3602
+ shadowColor: "#000",
3603
+ shadowOffset: { width: 0, height: 4 },
3604
+ shadowOpacity: 0.15,
3605
+ shadowRadius: 12,
3606
+ elevation: 8
3607
+ },
3608
+ header: {
3609
+ flexDirection: "row",
3610
+ justifyContent: "space-between",
3611
+ alignItems: "center",
3612
+ marginBottom: spacing.m
3613
+ },
3614
+ title: {
3615
+ fontFamily: font.family.body,
3616
+ fontSize: font.size.heading3,
3617
+ fontWeight: font.weight.semibold,
3618
+ flex: 1
3619
+ },
3620
+ closeButton: {
3621
+ position: "absolute",
3622
+ top: spacing.s,
3623
+ end: spacing.s,
3624
+ width: 44,
3625
+ height: 44,
3626
+ alignItems: "center",
3627
+ justifyContent: "center",
3628
+ zIndex: 1
3629
+ },
3630
+ closeText: {
3631
+ fontFamily: font.family.body,
3632
+ fontSize: 20,
3633
+ lineHeight: 24
3634
+ }
3635
+ });
3636
+ function Dialog({
3637
+ isOpen = false,
3638
+ onClose,
3639
+ title,
3640
+ children,
3641
+ style
3642
+ }) {
3643
+ const { colors: colors2 } = useTheme();
3644
+ return /* @__PURE__ */ jsx44(
3645
+ Modal2,
3646
+ {
3647
+ visible: isOpen,
3648
+ transparent: true,
3649
+ animationType: "fade",
3650
+ onRequestClose: onClose,
3651
+ children: /* @__PURE__ */ jsx44(
3652
+ Pressable22,
3653
+ {
3654
+ style: styles40.overlay,
3655
+ onPress: onClose,
3656
+ accessibilityRole: "button",
3657
+ accessibilityLabel: "Close dialog",
3658
+ children: /* @__PURE__ */ jsxs29(
3659
+ Pressable22,
3660
+ {
3661
+ style: [styles40.panel, { backgroundColor: colors2.colorGreySubtle }, style],
3662
+ onPress: () => {
3663
+ },
3664
+ accessibilityRole: "none",
3665
+ children: [
3666
+ /* @__PURE__ */ jsx44(
3667
+ Pressable22,
3668
+ {
3669
+ style: styles40.closeButton,
3670
+ onPress: onClose,
3671
+ accessibilityRole: "button",
3672
+ accessibilityLabel: "Close dialog",
3673
+ hitSlop: 8,
3674
+ children: /* @__PURE__ */ jsx44(
3675
+ Text32,
3676
+ {
3677
+ style: [styles40.closeText, { color: colors2.colorOnBgSubtle }],
3678
+ "aria-hidden": true,
3679
+ children: "\u2715"
3680
+ }
3681
+ )
3682
+ }
3683
+ ),
3684
+ !!title && /* @__PURE__ */ jsx44(View37, { style: styles40.header, children: /* @__PURE__ */ jsx44(Text32, { style: [styles40.title, { color: colors2.colorOnGreySubtle }], children: title }) }),
3685
+ children
3686
+ ]
3687
+ }
3688
+ )
3689
+ }
3690
+ )
3691
+ }
3692
+ );
3693
+ }
3694
+
3695
+ // src/components/interaction/Drawer/Drawer.native.tsx
3696
+ import { useEffect as useEffect2, useRef as useRef4 } from "react";
3697
+ import {
3698
+ Modal as Modal3,
3699
+ View as View38,
3700
+ Pressable as Pressable23,
3701
+ Text as Text33,
3702
+ Animated as Animated3,
3703
+ StyleSheet as StyleSheet41,
3704
+ Dimensions as Dimensions2
3705
+ } from "react-native";
3706
+ import { jsx as jsx45, jsxs as jsxs30 } from "react/jsx-runtime";
3707
+ var styles41 = StyleSheet41.create({
3708
+ overlay: {
3709
+ flex: 1,
3710
+ justifyContent: "flex-end"
3711
+ },
3712
+ panel: {
3713
+ maxHeight: "90%",
3714
+ borderTopStartRadius: border.radius.m,
3715
+ borderTopEndRadius: border.radius.m,
3716
+ paddingTop: spacing.m,
3717
+ paddingHorizontal: spacing.m,
3718
+ paddingBottom: spacing.m,
3719
+ shadowColor: "#000",
3720
+ shadowOffset: { width: 0, height: -4 },
3721
+ shadowOpacity: 0.15,
3722
+ shadowRadius: 16,
3723
+ elevation: 16
3724
+ },
3725
+ header: {
3726
+ flexDirection: "row",
3727
+ justifyContent: "space-between",
3728
+ alignItems: "center",
3729
+ paddingBottom: spacing.m,
3730
+ borderBottomWidth: 1,
3731
+ marginBottom: spacing.m
3732
+ },
3733
+ title: {
3734
+ fontFamily: font.family.body,
3735
+ fontSize: font.size.heading3,
3736
+ fontWeight: font.weight.semibold,
3737
+ flex: 1
3738
+ },
3739
+ closeButton: {
3740
+ width: 44,
3741
+ height: 44,
3742
+ alignItems: "center",
3743
+ justifyContent: "center"
3744
+ },
3745
+ closeText: {
3746
+ fontFamily: font.family.body,
3747
+ fontSize: 20,
3748
+ lineHeight: 24
3749
+ },
3750
+ body: {
3751
+ flex: 1
3752
+ }
3753
+ });
3754
+ function Drawer({
3755
+ isOpen,
3756
+ onClose,
3757
+ title,
3758
+ children,
3759
+ style
3760
+ }) {
3761
+ const { colors: colors2 } = useTheme();
3762
+ const screenHeight = Dimensions2.get("window").height;
3763
+ const slideAnim = useRef4(new Animated3.Value(screenHeight)).current;
3764
+ const backdropAnim = useRef4(new Animated3.Value(0)).current;
3765
+ useEffect2(() => {
3766
+ if (isOpen) {
3767
+ Animated3.parallel([
3768
+ Animated3.timing(slideAnim, {
3769
+ toValue: 0,
3770
+ duration: 250,
3771
+ useNativeDriver: true
3772
+ }),
3773
+ Animated3.timing(backdropAnim, {
3774
+ toValue: 1,
3775
+ duration: 250,
3776
+ useNativeDriver: true
3777
+ })
3778
+ ]).start();
3779
+ } else {
3780
+ Animated3.parallel([
3781
+ Animated3.timing(slideAnim, {
3782
+ toValue: screenHeight,
3783
+ duration: 200,
3784
+ useNativeDriver: true
3785
+ }),
3786
+ Animated3.timing(backdropAnim, {
3787
+ toValue: 0,
3788
+ duration: 200,
3789
+ useNativeDriver: true
3790
+ })
3791
+ ]).start();
3792
+ }
3793
+ }, [isOpen, slideAnim, backdropAnim, screenHeight]);
3794
+ return /* @__PURE__ */ jsx45(
3795
+ Modal3,
3796
+ {
3797
+ visible: isOpen,
3798
+ transparent: true,
3799
+ animationType: "none",
3800
+ onRequestClose: onClose,
3801
+ children: /* @__PURE__ */ jsxs30(View38, { style: styles41.overlay, children: [
3802
+ /* @__PURE__ */ jsx45(
3803
+ Animated3.View,
3804
+ {
3805
+ style: [
3806
+ StyleSheet41.absoluteFill,
3807
+ { backgroundColor: "rgba(0, 0, 0, 0.5)", opacity: backdropAnim }
3808
+ ],
3809
+ children: /* @__PURE__ */ jsx45(
3810
+ Pressable23,
3811
+ {
3812
+ style: StyleSheet41.absoluteFill,
3813
+ onPress: onClose,
3814
+ accessibilityRole: "button",
3815
+ accessibilityLabel: "Close drawer"
3816
+ }
3817
+ )
3818
+ }
3819
+ ),
3820
+ /* @__PURE__ */ jsxs30(
3821
+ Animated3.View,
3822
+ {
3823
+ style: [
3824
+ styles41.panel,
3825
+ {
3826
+ backgroundColor: colors2.colorBg,
3827
+ transform: [{ translateY: slideAnim }]
3828
+ },
3829
+ style
3830
+ ],
3831
+ accessibilityRole: "none",
3832
+ children: [
3833
+ /* @__PURE__ */ jsxs30(
3834
+ View38,
3835
+ {
3836
+ style: [styles41.header, { borderBottomColor: colors2.colorBgSubtle }],
3837
+ children: [
3838
+ !!title && /* @__PURE__ */ jsx45(Text33, { style: [styles41.title, { color: colors2.colorOnBg }], children: title }),
3839
+ /* @__PURE__ */ jsx45(
3840
+ Pressable23,
3841
+ {
3842
+ style: styles41.closeButton,
3843
+ onPress: onClose,
3844
+ accessibilityRole: "button",
3845
+ accessibilityLabel: "Close drawer",
3846
+ hitSlop: 8,
3847
+ children: /* @__PURE__ */ jsx45(
3848
+ Text33,
3849
+ {
3850
+ style: [styles41.closeText, { color: colors2.colorOnBgSubtle }],
3851
+ "aria-hidden": true,
3852
+ children: "\u2715"
3853
+ }
3854
+ )
3855
+ }
3856
+ )
3857
+ ]
3858
+ }
3859
+ ),
3860
+ /* @__PURE__ */ jsx45(View38, { style: styles41.body, children })
3861
+ ]
3862
+ }
3863
+ )
3864
+ ] })
3865
+ }
3866
+ );
3867
+ }
3868
+
3869
+ // src/components/interaction/Toast/Toast.native.tsx
3870
+ import {
3871
+ useState as useState13,
3872
+ useEffect as useEffect3,
3873
+ useRef as useRef5,
3874
+ useCallback as useCallback3,
3875
+ useMemo as useMemo3,
3876
+ createContext as createContext2,
3877
+ useContext as useContext2
3878
+ } from "react";
3879
+ import {
3880
+ View as View39,
3881
+ Text as Text34,
3882
+ Pressable as Pressable24,
3883
+ Animated as Animated4,
3884
+ StyleSheet as StyleSheet42
3885
+ } from "react-native";
3886
+ import { jsx as jsx46, jsxs as jsxs31 } from "react/jsx-runtime";
3887
+ var ToastContext = createContext2(void 0);
3888
+ var styles42 = StyleSheet42.create({
3889
+ container: {
3890
+ position: "absolute",
3891
+ top: 0,
3892
+ start: 0,
3893
+ end: 0,
3894
+ paddingTop: spacing.xxxl,
3895
+ paddingHorizontal: spacing.m,
3896
+ zIndex: 9999,
3897
+ pointerEvents: "box-none"
3898
+ },
3899
+ toast: {
3900
+ flexDirection: "row",
3901
+ alignItems: "center",
3902
+ justifyContent: "space-between",
3903
+ paddingVertical: spacing.s,
3904
+ paddingHorizontal: spacing.m,
3905
+ borderRadius: border.radius.s,
3906
+ marginBottom: spacing.xs,
3907
+ minHeight: 48
3908
+ },
3909
+ message: {
3910
+ fontFamily: font.family.body,
3911
+ fontSize: font.size.body,
3912
+ fontWeight: font.weight.semibold,
3913
+ flex: 1
3914
+ },
3915
+ closeButton: {
3916
+ width: 44,
3917
+ height: 44,
3918
+ alignItems: "center",
3919
+ justifyContent: "center",
3920
+ marginStart: spacing.xs
3921
+ },
3922
+ closeText: {
3923
+ fontFamily: font.family.body,
3924
+ fontSize: 16,
3925
+ lineHeight: 20
3926
+ }
3927
+ });
3928
+ function ToastItem({
3929
+ toast,
3930
+ onRemove
3931
+ }) {
3932
+ const { colors: colors2 } = useTheme();
3933
+ const slideAnim = useRef5(new Animated4.Value(-100)).current;
3934
+ const opacityAnim = useRef5(new Animated4.Value(0)).current;
3935
+ const variantColors = useMemo3(
3936
+ () => ({
3937
+ success: { bg: colors2.colorSuccess, text: colors2.colorOnSuccess },
3938
+ error: { bg: colors2.colorError, text: colors2.colorOnError },
3939
+ info: { bg: colors2.colorBgSubtle, text: colors2.colorOnBgSubtle }
3940
+ }),
3941
+ [colors2]
3942
+ );
3943
+ useEffect3(() => {
3944
+ Animated4.parallel([
3945
+ Animated4.timing(slideAnim, {
3946
+ toValue: 0,
3947
+ duration: 200,
3948
+ useNativeDriver: true
3949
+ }),
3950
+ Animated4.timing(opacityAnim, {
3951
+ toValue: 1,
3952
+ duration: 200,
3953
+ useNativeDriver: true
3954
+ })
3955
+ ]).start();
3956
+ }, [slideAnim, opacityAnim]);
3957
+ useEffect3(() => {
3958
+ const timer = setTimeout(onRemove, 5e3);
3959
+ return () => clearTimeout(timer);
3960
+ }, [onRemove]);
3961
+ const { bg, text } = variantColors[toast.variant];
3962
+ return /* @__PURE__ */ jsxs31(
3963
+ Animated4.View,
3964
+ {
3965
+ style: [
3966
+ styles42.toast,
3967
+ {
3968
+ backgroundColor: bg,
3969
+ transform: [{ translateY: slideAnim }],
3970
+ opacity: opacityAnim
3971
+ }
3972
+ ],
3973
+ accessibilityRole: "alert",
3974
+ accessibilityLiveRegion: "polite",
3975
+ children: [
3976
+ /* @__PURE__ */ jsx46(Text34, { style: [styles42.message, { color: text }], children: toast.message }),
3977
+ /* @__PURE__ */ jsx46(
3978
+ Pressable24,
3979
+ {
3980
+ style: styles42.closeButton,
3981
+ onPress: onRemove,
3982
+ accessibilityRole: "button",
3983
+ accessibilityLabel: "Dismiss",
3984
+ hitSlop: 8,
3985
+ children: /* @__PURE__ */ jsx46(Text34, { style: [styles42.closeText, { color: text }], "aria-hidden": true, children: "\u2715" })
3986
+ }
3987
+ )
3988
+ ]
3989
+ }
3990
+ );
3991
+ }
3992
+ function ToastProvider({
3993
+ children,
3994
+ style
3995
+ }) {
3996
+ const [toasts, setToasts] = useState13([]);
3997
+ const showToast = useCallback3((message, variant) => {
3998
+ const id = Math.random().toString(36).substring(2, 9);
3999
+ setToasts((prev) => [...prev, { id, message, variant }]);
4000
+ }, []);
4001
+ const removeToast = useCallback3((id) => {
4002
+ setToasts((prev) => prev.filter((t) => t.id !== id));
4003
+ }, []);
4004
+ const value = useMemo3(() => ({ showToast }), [showToast]);
4005
+ return /* @__PURE__ */ jsx46(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs31(View39, { style: [{ flex: 1 }, style], children: [
4006
+ children,
4007
+ toasts.length > 0 && /* @__PURE__ */ jsx46(
4008
+ View39,
4009
+ {
4010
+ style: styles42.container,
4011
+ accessibilityRole: "summary",
4012
+ accessibilityLabel: "Notifications",
4013
+ children: toasts.map((toast) => /* @__PURE__ */ jsx46(
4014
+ ToastItem,
4015
+ {
4016
+ toast,
4017
+ onRemove: () => removeToast(toast.id)
4018
+ },
4019
+ toast.id
4020
+ ))
4021
+ }
4022
+ )
4023
+ ] }) });
4024
+ }
4025
+ function useToast() {
4026
+ const context = useContext2(ToastContext);
4027
+ if (!context) {
4028
+ throw new Error("useToast must be used within a ToastProvider");
4029
+ }
4030
+ return context;
4031
+ }
4032
+
4033
+ // src/components/interaction/DropdownMenu/DropdownMenu.native.tsx
4034
+ import React, { useState as useState14, useEffect as useEffect4, useRef as useRef6 } from "react";
4035
+ import {
4036
+ Modal as Modal4,
4037
+ View as View40,
4038
+ Pressable as Pressable25,
4039
+ Text as Text35,
4040
+ FlatList as FlatList2,
4041
+ Animated as Animated5,
4042
+ StyleSheet as StyleSheet43,
4043
+ Dimensions as Dimensions3,
4044
+ SafeAreaView as SafeAreaView2
4045
+ } from "react-native";
4046
+ import { Fragment as Fragment2, jsx as jsx47, jsxs as jsxs32 } from "react/jsx-runtime";
4047
+ var styles43 = StyleSheet43.create({
4048
+ overlay: {
4049
+ flex: 1,
4050
+ justifyContent: "flex-end"
4051
+ },
4052
+ sheet: {
4053
+ maxHeight: "60%",
4054
+ borderTopStartRadius: border.radius.m,
4055
+ borderTopEndRadius: border.radius.m,
4056
+ paddingTop: spacing.m,
4057
+ paddingBottom: spacing.xxxl
4058
+ },
4059
+ sheetHeader: {
4060
+ flexDirection: "row",
4061
+ justifyContent: "space-between",
4062
+ alignItems: "center",
4063
+ paddingHorizontal: spacing.m,
4064
+ paddingBottom: spacing.s,
4065
+ borderBottomWidth: 1,
4066
+ marginBottom: spacing.xxs
4067
+ },
4068
+ sheetTitle: {
4069
+ fontFamily: font.family.body,
4070
+ fontSize: font.size.heading3,
4071
+ fontWeight: font.weight.semibold
4072
+ },
4073
+ closeText: {
4074
+ fontFamily: font.family.body,
4075
+ fontSize: font.size.body,
4076
+ fontWeight: font.weight.semibold
4077
+ },
4078
+ separator: {
4079
+ height: 1,
4080
+ marginHorizontal: spacing.m,
4081
+ marginVertical: spacing.xxs
4082
+ },
4083
+ item: {
4084
+ flexDirection: "row",
4085
+ alignItems: "center",
4086
+ paddingHorizontal: spacing.m,
4087
+ paddingVertical: spacing.s,
4088
+ minHeight: 48,
4089
+ gap: spacing.s
4090
+ },
4091
+ itemText: {
4092
+ fontFamily: font.family.body,
4093
+ fontSize: font.size.body,
4094
+ lineHeight: lineHeight.body
4095
+ }
4096
+ });
4097
+ function DropdownMenu({
4098
+ trigger,
4099
+ items,
4100
+ title = "Menu",
4101
+ style
4102
+ }) {
4103
+ const { colors: colors2 } = useTheme();
4104
+ const [open, setOpen] = useState14(false);
4105
+ const screenHeight = Dimensions3.get("window").height;
4106
+ const slideAnim = useRef6(new Animated5.Value(screenHeight)).current;
4107
+ const backdropAnim = useRef6(new Animated5.Value(0)).current;
4108
+ useEffect4(() => {
4109
+ if (open) {
4110
+ Animated5.parallel([
4111
+ Animated5.timing(slideAnim, {
4112
+ toValue: 0,
4113
+ duration: 250,
4114
+ useNativeDriver: true
4115
+ }),
4116
+ Animated5.timing(backdropAnim, {
4117
+ toValue: 1,
4118
+ duration: 250,
4119
+ useNativeDriver: true
4120
+ })
4121
+ ]).start();
4122
+ } else {
4123
+ Animated5.parallel([
4124
+ Animated5.timing(slideAnim, {
4125
+ toValue: screenHeight,
4126
+ duration: 200,
4127
+ useNativeDriver: true
4128
+ }),
4129
+ Animated5.timing(backdropAnim, {
4130
+ toValue: 0,
4131
+ duration: 200,
4132
+ useNativeDriver: true
4133
+ })
4134
+ ]).start();
4135
+ }
4136
+ }, [open, slideAnim, backdropAnim, screenHeight]);
4137
+ const handleItemPress = (item) => {
4138
+ item.onPress?.();
4139
+ setOpen(false);
4140
+ };
4141
+ return /* @__PURE__ */ jsxs32(View40, { style, children: [
4142
+ React.cloneElement(trigger, {
4143
+ onPress: () => setOpen(true),
4144
+ accessibilityRole: "button",
4145
+ accessibilityLabel: title
4146
+ }),
4147
+ /* @__PURE__ */ jsx47(
4148
+ Modal4,
4149
+ {
4150
+ visible: open,
4151
+ transparent: true,
4152
+ animationType: "none",
4153
+ onRequestClose: () => setOpen(false),
4154
+ children: /* @__PURE__ */ jsxs32(View40, { style: styles43.overlay, children: [
4155
+ /* @__PURE__ */ jsx47(
4156
+ Animated5.View,
4157
+ {
4158
+ style: [
4159
+ StyleSheet43.absoluteFill,
4160
+ { backgroundColor: "rgba(0, 0, 0, 0.5)", opacity: backdropAnim }
4161
+ ],
4162
+ children: /* @__PURE__ */ jsx47(
4163
+ Pressable25,
4164
+ {
4165
+ style: StyleSheet43.absoluteFill,
4166
+ onPress: () => setOpen(false),
4167
+ accessibilityRole: "button",
4168
+ accessibilityLabel: "Close menu"
4169
+ }
4170
+ )
4171
+ }
4172
+ ),
4173
+ /* @__PURE__ */ jsx47(
4174
+ Animated5.View,
4175
+ {
4176
+ style: [
4177
+ styles43.sheet,
4178
+ {
4179
+ backgroundColor: colors2.colorBg,
4180
+ transform: [{ translateY: slideAnim }]
4181
+ }
4182
+ ],
4183
+ children: /* @__PURE__ */ jsx47(
4184
+ Pressable25,
4185
+ {
4186
+ onPress: () => {
4187
+ },
4188
+ children: /* @__PURE__ */ jsxs32(SafeAreaView2, { children: [
4189
+ /* @__PURE__ */ jsxs32(
4190
+ View40,
4191
+ {
4192
+ style: [
4193
+ styles43.sheetHeader,
4194
+ { borderBottomColor: colors2.colorBgSubtle }
4195
+ ],
4196
+ children: [
4197
+ /* @__PURE__ */ jsx47(Text35, { style: [styles43.sheetTitle, { color: colors2.colorOnBg }], children: title }),
4198
+ /* @__PURE__ */ jsx47(
4199
+ Pressable25,
4200
+ {
4201
+ accessibilityRole: "button",
4202
+ accessibilityLabel: "Close",
4203
+ onPress: () => setOpen(false),
4204
+ hitSlop: 8,
4205
+ children: /* @__PURE__ */ jsx47(
4206
+ Text35,
4207
+ {
4208
+ style: [
4209
+ styles43.closeText,
4210
+ { color: colors2.colorInteractive }
4211
+ ],
4212
+ children: "Done"
4213
+ }
4214
+ )
4215
+ }
4216
+ )
4217
+ ]
4218
+ }
4219
+ ),
4220
+ /* @__PURE__ */ jsx47(
4221
+ FlatList2,
4222
+ {
4223
+ data: items,
4224
+ keyExtractor: (item) => item.id,
4225
+ renderItem: ({ item }) => /* @__PURE__ */ jsxs32(Fragment2, { children: [
4226
+ item.separator && /* @__PURE__ */ jsx47(
4227
+ View40,
4228
+ {
4229
+ style: [
4230
+ styles43.separator,
4231
+ { backgroundColor: colors2.colorBgSubtle }
4232
+ ],
4233
+ accessibilityRole: "none"
4234
+ }
4235
+ ),
4236
+ /* @__PURE__ */ jsxs32(
4237
+ Pressable25,
4238
+ {
4239
+ accessibilityRole: "menuitem",
4240
+ accessibilityLabel: item.label,
4241
+ accessibilityState: { disabled: item.disabled },
4242
+ disabled: item.disabled,
4243
+ onPress: () => handleItemPress(item),
4244
+ style: ({ pressed }) => [
4245
+ styles43.item,
4246
+ pressed && { backgroundColor: colors2.colorBgSubtle },
4247
+ item.disabled && { opacity: 0.4 }
4248
+ ],
4249
+ children: [
4250
+ !!item.icon && /* @__PURE__ */ jsx47(
4251
+ View40,
4252
+ {
4253
+ importantForAccessibility: "no-hide-descendants",
4254
+ accessibilityElementsHidden: true,
4255
+ children: item.icon
4256
+ }
4257
+ ),
4258
+ /* @__PURE__ */ jsx47(
4259
+ Text35,
4260
+ {
4261
+ style: [
4262
+ styles43.itemText,
4263
+ { color: colors2.colorOnBg }
4264
+ ],
4265
+ children: item.label
4266
+ }
4267
+ )
4268
+ ]
4269
+ }
4270
+ )
4271
+ ] })
4272
+ }
4273
+ )
4274
+ ] })
4275
+ }
4276
+ )
4277
+ }
4278
+ )
4279
+ ] })
4280
+ }
4281
+ )
4282
+ ] });
4283
+ }
4284
+
4285
+ // src/components/interaction/Popover/Popover.native.tsx
4286
+ import React2, { useState as useState15 } from "react";
4287
+ import {
4288
+ Modal as Modal5,
4289
+ View as View41,
4290
+ Pressable as Pressable26,
4291
+ StyleSheet as StyleSheet44
4292
+ } from "react-native";
4293
+ import { jsx as jsx48, jsxs as jsxs33 } from "react/jsx-runtime";
4294
+ var styles44 = StyleSheet44.create({
4295
+ wrapper: {
4296
+ alignSelf: "flex-start"
4297
+ },
4298
+ overlay: {
4299
+ flex: 1,
4300
+ justifyContent: "center",
4301
+ alignItems: "center",
4302
+ backgroundColor: "rgba(0, 0, 0, 0.25)",
4303
+ padding: spacing.m
4304
+ },
4305
+ panel: {
4306
+ width: "100%",
4307
+ maxWidth: 360,
4308
+ borderRadius: border.radius.s,
4309
+ padding: spacing.m,
4310
+ shadowColor: "#000",
4311
+ shadowOffset: { width: 0, height: 2 },
4312
+ shadowOpacity: 0.15,
4313
+ shadowRadius: 8,
4314
+ elevation: 4
4315
+ }
4316
+ });
4317
+ function Popover({
4318
+ children,
4319
+ content,
4320
+ accessibilityLabel,
4321
+ style
4322
+ }) {
4323
+ const { colors: colors2 } = useTheme();
4324
+ const [isOpen, setIsOpen] = useState15(false);
4325
+ return /* @__PURE__ */ jsxs33(View41, { style: [styles44.wrapper, style], children: [
4326
+ React2.cloneElement(children, {
4327
+ onPress: () => setIsOpen(true),
4328
+ accessibilityRole: "button",
4329
+ accessibilityLabel: accessibilityLabel ?? "Open popover"
4330
+ }),
4331
+ /* @__PURE__ */ jsx48(
4332
+ Modal5,
4333
+ {
4334
+ visible: isOpen,
4335
+ transparent: true,
4336
+ animationType: "fade",
4337
+ onRequestClose: () => setIsOpen(false),
4338
+ children: /* @__PURE__ */ jsx48(
4339
+ Pressable26,
4340
+ {
4341
+ style: styles44.overlay,
4342
+ onPress: () => setIsOpen(false),
4343
+ accessibilityRole: "button",
4344
+ accessibilityLabel: "Close popover",
4345
+ children: /* @__PURE__ */ jsx48(
4346
+ Pressable26,
4347
+ {
4348
+ style: [styles44.panel, { backgroundColor: colors2.colorBg }],
4349
+ onPress: () => {
4350
+ },
4351
+ accessibilityRole: "none",
4352
+ accessibilityLabel,
4353
+ children: content
4354
+ }
4355
+ )
4356
+ }
4357
+ )
4358
+ }
4359
+ )
4360
+ ] });
4361
+ }
4362
+ export {
4363
+ Accordion,
4364
+ Alert,
4365
+ Avatar,
4366
+ Badge,
4367
+ Breadcrumb,
4368
+ Button,
4369
+ ButtonContainer,
4370
+ ButtonGroup,
4371
+ Calendar,
4372
+ Card,
4373
+ Carousel,
4374
+ Checkbox,
4375
+ CheckboxGroup,
4376
+ Collapsible,
4377
+ Combobox,
4378
+ DescriptionList,
4379
+ Dialog,
4380
+ Drawer,
4381
+ DropdownMenu,
4382
+ FileInput,
4383
+ FormInput,
4384
+ IconWrapper,
4385
+ Label,
4386
+ Link,
4387
+ Loading,
4388
+ Message,
4389
+ NotificationBanner,
4390
+ NumberInput,
4391
+ Pagination,
4392
+ Popover,
4393
+ Progress,
4394
+ ProgressCircle,
4395
+ Radio,
4396
+ RadioGroup,
4397
+ Rating,
4398
+ SectionHeader,
4399
+ SegmentedControl,
4400
+ Select,
4401
+ Separator,
4402
+ Skeleton,
4403
+ Slider,
4404
+ Switch,
4405
+ Table,
4406
+ Tabs,
4407
+ Textarea,
4408
+ ThemeProvider,
4409
+ ToastProvider,
4410
+ Tooltip,
4411
+ Typography,
4412
+ animation,
4413
+ border,
4414
+ colors,
4415
+ font,
4416
+ lineHeight,
4417
+ spacing,
4418
+ useTheme,
4419
+ useToast,
4420
+ zIndex
4421
+ };