@entropix/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.cjs ADDED
@@ -0,0 +1,1246 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var native = require('@entropix/tokens/native');
5
+ var light = require('@entropix/tokens/native/light');
6
+ var dark = require('@entropix/tokens/native/dark');
7
+ var jsxRuntime = require('react/jsx-runtime');
8
+ var reactNative = require('react-native');
9
+ var core = require('@entropix/core');
10
+
11
+ // src/theme/theme-context.tsx
12
+ var ThemeContext = react.createContext({
13
+ mode: "light",
14
+ tokens: light.tokens,
15
+ baseTokens: native.tokens
16
+ });
17
+ function EntropixProvider({
18
+ mode = "light",
19
+ children
20
+ }) {
21
+ const value = react.useMemo(
22
+ () => ({
23
+ mode,
24
+ tokens: mode === "dark" ? dark.tokens : light.tokens,
25
+ baseTokens: native.tokens
26
+ }),
27
+ [mode]
28
+ );
29
+ return /* @__PURE__ */ jsxRuntime.jsx(ThemeContext.Provider, { value, children });
30
+ }
31
+ function useTheme() {
32
+ return react.useContext(ThemeContext);
33
+ }
34
+
35
+ // src/utils/map-accessibility-to-rn.ts
36
+ var RN_ROLE_MAP = {
37
+ button: "button",
38
+ checkbox: "checkbox",
39
+ switch: "switch",
40
+ dialog: "none",
41
+ // Modal component handles dialog semantics
42
+ alertdialog: "alert",
43
+ link: "link",
44
+ tab: "tab",
45
+ tablist: "tablist",
46
+ menu: "menu",
47
+ menuitem: "menuitem",
48
+ radio: "radio",
49
+ radiogroup: "radiogroup",
50
+ slider: "adjustable",
51
+ spinbutton: "spinbutton",
52
+ textbox: "text",
53
+ combobox: "combobox",
54
+ progressbar: "progressbar",
55
+ alert: "alert",
56
+ status: "text",
57
+ tooltip: "text",
58
+ none: "none",
59
+ presentation: "none"
60
+ };
61
+ function mapAccessibilityToRN(props) {
62
+ const result = { accessible: true };
63
+ if (props.role) {
64
+ result.accessibilityRole = RN_ROLE_MAP[props.role] ?? props.role;
65
+ }
66
+ if (props.label) {
67
+ result.accessibilityLabel = props.label;
68
+ }
69
+ if (props.describedBy) {
70
+ result.accessibilityHint = props.describedBy;
71
+ }
72
+ if (props.labelledBy) {
73
+ result.accessibilityLabelledBy = props.labelledBy;
74
+ }
75
+ const state = {};
76
+ let hasState = false;
77
+ if (props.disabled !== void 0) {
78
+ state.disabled = props.disabled;
79
+ hasState = true;
80
+ }
81
+ if (props.expanded !== void 0) {
82
+ state.expanded = props.expanded;
83
+ hasState = true;
84
+ }
85
+ if (props.selected !== void 0) {
86
+ state.selected = props.selected;
87
+ hasState = true;
88
+ }
89
+ if (props.checked !== void 0) {
90
+ state.checked = props.checked;
91
+ hasState = true;
92
+ }
93
+ if (props.busy !== void 0) {
94
+ state.busy = props.busy;
95
+ hasState = true;
96
+ }
97
+ if (hasState) {
98
+ result.accessibilityState = state;
99
+ }
100
+ if (props.valueNow !== void 0 || props.valueMin !== void 0 || props.valueMax !== void 0 || props.valueText !== void 0) {
101
+ result.accessibilityValue = {};
102
+ if (props.valueNow !== void 0)
103
+ result.accessibilityValue.now = props.valueNow;
104
+ if (props.valueMin !== void 0)
105
+ result.accessibilityValue.min = props.valueMin;
106
+ if (props.valueMax !== void 0)
107
+ result.accessibilityValue.max = props.valueMax;
108
+ if (props.valueText !== void 0)
109
+ result.accessibilityValue.text = props.valueText;
110
+ }
111
+ if (props.live) {
112
+ result.accessibilityLiveRegion = props.live === "off" ? "none" : props.live;
113
+ }
114
+ if (props.hidden) {
115
+ result.accessibilityElementsHidden = true;
116
+ result.importantForAccessibility = "no-hide-descendants";
117
+ }
118
+ return result;
119
+ }
120
+ function Button({
121
+ onPress,
122
+ disabled,
123
+ loading,
124
+ variant = "primary",
125
+ size = "md",
126
+ style,
127
+ textStyle,
128
+ children,
129
+ ...rest
130
+ }) {
131
+ const { tokens: t, baseTokens: bt } = useTheme();
132
+ const { isDisabled, isLoading, getButtonProps } = core.useButton({
133
+ disabled,
134
+ loading,
135
+ onPress,
136
+ elementType: "div"
137
+ });
138
+ const propGetterReturn = getButtonProps();
139
+ const rnAccessibility = mapAccessibilityToRN(propGetterReturn.accessibility);
140
+ const handlePress = react.useCallback(() => {
141
+ propGetterReturn.onAction?.();
142
+ }, [propGetterReturn.onAction]);
143
+ const sizeStyles = getSizeStyle(size, bt);
144
+ const variantStyles = getVariantStyle(variant, t);
145
+ const labelColor = getVariantTextColor(variant, t);
146
+ const isInactive = isDisabled || isLoading;
147
+ return /* @__PURE__ */ jsxRuntime.jsx(
148
+ reactNative.Pressable,
149
+ {
150
+ ...rnAccessibility,
151
+ ...rest,
152
+ disabled: isInactive,
153
+ onPress: isInactive ? void 0 : handlePress,
154
+ style: [
155
+ baseStyle,
156
+ sizeStyles.container,
157
+ variantStyles,
158
+ isInactive && { opacity: 0.5 },
159
+ style
160
+ ],
161
+ children: typeof children === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
162
+ reactNative.Text,
163
+ {
164
+ style: [
165
+ { color: labelColor, fontSize: sizeStyles.fontSize, fontWeight: "500" },
166
+ textStyle
167
+ ],
168
+ children
169
+ }
170
+ ) : children
171
+ }
172
+ );
173
+ }
174
+ var baseStyle = {
175
+ flexDirection: "row",
176
+ alignItems: "center",
177
+ justifyContent: "center"
178
+ };
179
+ function getSizeStyle(size, bt) {
180
+ switch (size) {
181
+ case "sm":
182
+ return {
183
+ container: {
184
+ paddingVertical: bt.entropixSpacing1,
185
+ paddingHorizontal: bt.entropixSpacing3,
186
+ borderRadius: bt.entropixRadiusSm,
187
+ gap: bt.entropixButtonGap
188
+ },
189
+ fontSize: bt.entropixFontSizeXs
190
+ };
191
+ case "lg":
192
+ return {
193
+ container: {
194
+ paddingVertical: bt.entropixSpacing3,
195
+ paddingHorizontal: bt.entropixSpacing6,
196
+ borderRadius: bt.entropixRadiusLg,
197
+ gap: bt.entropixButtonGap
198
+ },
199
+ fontSize: bt.entropixFontSizeBase
200
+ };
201
+ default:
202
+ return {
203
+ container: {
204
+ paddingVertical: bt.entropixButtonPaddingY,
205
+ paddingHorizontal: bt.entropixButtonPaddingX,
206
+ borderRadius: bt.entropixButtonBorderRadius,
207
+ gap: bt.entropixButtonGap
208
+ },
209
+ fontSize: bt.entropixButtonFontSize
210
+ };
211
+ }
212
+ }
213
+ function getVariantStyle(variant, t) {
214
+ switch (variant) {
215
+ case "primary":
216
+ return { backgroundColor: t.entropixButtonPrimaryBg, borderWidth: 1, borderColor: t.entropixButtonPrimaryBorder };
217
+ case "secondary":
218
+ return { backgroundColor: t.entropixButtonSecondaryBg, borderWidth: 1, borderColor: t.entropixButtonSecondaryBorder };
219
+ case "outline":
220
+ return { backgroundColor: "transparent", borderWidth: 1, borderColor: t.entropixColorBorderDefault };
221
+ case "ghost":
222
+ return { backgroundColor: "transparent", borderWidth: 1, borderColor: "transparent" };
223
+ case "danger":
224
+ return { backgroundColor: t.entropixButtonDangerBg, borderWidth: 1, borderColor: t.entropixButtonDangerBorder };
225
+ }
226
+ }
227
+ function getVariantTextColor(variant, t) {
228
+ switch (variant) {
229
+ case "primary":
230
+ return t.entropixButtonPrimaryText;
231
+ case "secondary":
232
+ return t.entropixButtonSecondaryText;
233
+ case "outline":
234
+ case "ghost":
235
+ return t.entropixColorTextPrimary;
236
+ case "danger":
237
+ return t.entropixButtonDangerText;
238
+ }
239
+ }
240
+ function Toggle(props) {
241
+ return /* @__PURE__ */ jsxRuntime.jsx(ToggleInner, { ...props, role: "checkbox" });
242
+ }
243
+ function ToggleInner({
244
+ checked,
245
+ defaultChecked,
246
+ onChange,
247
+ disabled,
248
+ label,
249
+ role = "checkbox",
250
+ style,
251
+ textStyle,
252
+ children,
253
+ ...rest
254
+ }) {
255
+ const { tokens: t, baseTokens: bt } = useTheme();
256
+ const { isDisabled, getToggleProps } = core.useToggle({
257
+ checked,
258
+ defaultChecked,
259
+ onChange,
260
+ disabled,
261
+ role
262
+ });
263
+ const propGetterReturn = getToggleProps();
264
+ const rnAccessibility = mapAccessibilityToRN(propGetterReturn.accessibility);
265
+ const isChecked = propGetterReturn.accessibility.checked === true;
266
+ if (label) {
267
+ rnAccessibility.accessibilityLabel = label;
268
+ }
269
+ const handlePress = react.useCallback(() => {
270
+ propGetterReturn.onAction?.();
271
+ }, [propGetterReturn.onAction]);
272
+ return /* @__PURE__ */ jsxRuntime.jsx(
273
+ reactNative.Pressable,
274
+ {
275
+ ...rnAccessibility,
276
+ ...rest,
277
+ disabled: isDisabled,
278
+ onPress: isDisabled ? void 0 : handlePress,
279
+ style: [
280
+ {
281
+ flexDirection: "row",
282
+ alignItems: "center",
283
+ justifyContent: "center",
284
+ paddingVertical: bt.entropixSpacing2,
285
+ paddingHorizontal: bt.entropixSpacing3,
286
+ borderWidth: 1,
287
+ borderColor: isChecked ? "transparent" : t.entropixColorBorderDefault,
288
+ borderRadius: bt.entropixRadiusMd,
289
+ backgroundColor: isChecked ? t.entropixColorActionPrimaryDefault : t.entropixColorBgPrimary
290
+ },
291
+ isDisabled && { opacity: 0.5 },
292
+ style
293
+ ],
294
+ children: typeof children === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
295
+ reactNative.Text,
296
+ {
297
+ style: [
298
+ {
299
+ fontSize: bt.entropixFontSizeSm,
300
+ fontWeight: "500",
301
+ color: isChecked ? t.entropixColorTextInverse : t.entropixColorTextPrimary
302
+ },
303
+ textStyle
304
+ ],
305
+ children
306
+ }
307
+ ) : children != null ? children : /* @__PURE__ */ jsxRuntime.jsx(
308
+ reactNative.Text,
309
+ {
310
+ style: {
311
+ fontSize: bt.entropixFontSizeSm,
312
+ fontWeight: "500",
313
+ color: isChecked ? t.entropixColorTextInverse : t.entropixColorTextPrimary
314
+ },
315
+ children: isChecked ? "On" : "Off"
316
+ }
317
+ )
318
+ }
319
+ );
320
+ }
321
+ var TRACK_WIDTH = 44;
322
+ var TRACK_HEIGHT = 24;
323
+ var TRACK_PADDING = 2;
324
+ var THUMB_SIZE = TRACK_HEIGHT - TRACK_PADDING * 2;
325
+ var THUMB_TRAVEL = TRACK_WIDTH - TRACK_PADDING * 2 - THUMB_SIZE;
326
+ function Switch({
327
+ checked,
328
+ defaultChecked,
329
+ onChange,
330
+ disabled,
331
+ label,
332
+ style,
333
+ ...rest
334
+ }) {
335
+ const { tokens: t, baseTokens: bt } = useTheme();
336
+ const { isDisabled, getToggleProps } = core.useToggle({
337
+ checked,
338
+ defaultChecked,
339
+ onChange,
340
+ disabled,
341
+ role: "switch"
342
+ });
343
+ const propGetterReturn = getToggleProps();
344
+ const rnAccessibility = mapAccessibilityToRN(propGetterReturn.accessibility);
345
+ const isChecked = propGetterReturn.accessibility.checked === true;
346
+ if (label) {
347
+ rnAccessibility.accessibilityLabel = label;
348
+ }
349
+ const handlePress = react.useCallback(() => {
350
+ propGetterReturn.onAction?.();
351
+ }, [propGetterReturn.onAction]);
352
+ const thumbAnim = react.useRef(
353
+ new reactNative.Animated.Value(defaultChecked || checked ? THUMB_TRAVEL : 0)
354
+ ).current;
355
+ react.useEffect(() => {
356
+ reactNative.Animated.timing(thumbAnim, {
357
+ toValue: isChecked ? THUMB_TRAVEL : 0,
358
+ duration: 150,
359
+ useNativeDriver: false
360
+ }).start();
361
+ }, [isChecked, thumbAnim]);
362
+ return /* @__PURE__ */ jsxRuntime.jsx(
363
+ reactNative.Pressable,
364
+ {
365
+ ...rnAccessibility,
366
+ ...rest,
367
+ disabled: isDisabled,
368
+ onPress: isDisabled ? void 0 : handlePress,
369
+ style: [
370
+ {
371
+ width: TRACK_WIDTH,
372
+ height: TRACK_HEIGHT,
373
+ borderRadius: bt.entropixRadiusFull,
374
+ backgroundColor: isChecked ? t.entropixColorActionPrimaryDefault : t.entropixColorGray300,
375
+ padding: TRACK_PADDING,
376
+ justifyContent: "center"
377
+ },
378
+ isDisabled && { opacity: 0.5 },
379
+ style
380
+ ],
381
+ children: /* @__PURE__ */ jsxRuntime.jsx(
382
+ reactNative.Animated.View,
383
+ {
384
+ style: {
385
+ width: THUMB_SIZE,
386
+ height: THUMB_SIZE,
387
+ borderRadius: bt.entropixRadiusFull,
388
+ backgroundColor: t.entropixColorWhite,
389
+ transform: [{ translateX: thumbAnim }]
390
+ }
391
+ }
392
+ )
393
+ }
394
+ );
395
+ }
396
+ var DialogContext = react.createContext(null);
397
+ function useDialogContext() {
398
+ const context = react.useContext(DialogContext);
399
+ if (!context) {
400
+ throw new Error(
401
+ "Dialog compound components must be used within a <Dialog> provider."
402
+ );
403
+ }
404
+ return context;
405
+ }
406
+ function Dialog({
407
+ children,
408
+ isOpen,
409
+ defaultOpen,
410
+ onOpenChange,
411
+ closeOnOverlayPress,
412
+ closeOnEscape,
413
+ modal,
414
+ role
415
+ }) {
416
+ const dialog = core.useDialog({
417
+ isOpen,
418
+ defaultOpen,
419
+ onOpenChange,
420
+ closeOnOverlayPress,
421
+ closeOnEscape,
422
+ modal,
423
+ role
424
+ });
425
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogContext.Provider, { value: dialog, children });
426
+ }
427
+ function DialogTrigger({
428
+ children,
429
+ style,
430
+ ...rest
431
+ }) {
432
+ const { getTriggerProps } = useDialogContext();
433
+ const propGetterReturn = getTriggerProps();
434
+ const rnAccessibility = mapAccessibilityToRN(propGetterReturn.accessibility);
435
+ const handlePress = react.useCallback(() => {
436
+ propGetterReturn.onAction?.();
437
+ }, [propGetterReturn.onAction]);
438
+ return /* @__PURE__ */ jsxRuntime.jsx(
439
+ reactNative.Pressable,
440
+ {
441
+ ...rnAccessibility,
442
+ ...rest,
443
+ onPress: handlePress,
444
+ style,
445
+ children
446
+ }
447
+ );
448
+ }
449
+ function DialogContent({
450
+ children,
451
+ style,
452
+ cardStyle,
453
+ animationType = "fade",
454
+ transparent = true,
455
+ ...rest
456
+ }) {
457
+ const { tokens: t, baseTokens: bt } = useTheme();
458
+ const { isOpen, close, ids, getContentProps } = useDialogContext();
459
+ const propGetterReturn = getContentProps();
460
+ const rnAccessibility = mapAccessibilityToRN(propGetterReturn.accessibility);
461
+ return /* @__PURE__ */ jsxRuntime.jsx(
462
+ reactNative.Modal,
463
+ {
464
+ visible: isOpen,
465
+ transparent,
466
+ animationType,
467
+ onRequestClose: close,
468
+ supportedOrientations: ["portrait", "landscape"],
469
+ children: /* @__PURE__ */ jsxRuntime.jsx(
470
+ reactNative.View,
471
+ {
472
+ ...rest,
473
+ style: [
474
+ {
475
+ flex: 1,
476
+ justifyContent: "center",
477
+ alignItems: "center",
478
+ backgroundColor: "rgba(0, 0, 0, 0.5)"
479
+ },
480
+ style
481
+ ],
482
+ children: /* @__PURE__ */ jsxRuntime.jsx(
483
+ reactNative.View,
484
+ {
485
+ ...rnAccessibility,
486
+ nativeID: ids.content,
487
+ style: [
488
+ {
489
+ backgroundColor: t.entropixColorBgPrimary,
490
+ borderRadius: bt.entropixRadiusLg,
491
+ padding: bt.entropixSpacing6,
492
+ width: "90%",
493
+ maxWidth: 480,
494
+ shadowColor: "#000",
495
+ shadowOffset: { width: 0, height: 4 },
496
+ shadowOpacity: 0.15,
497
+ shadowRadius: 12,
498
+ elevation: 8
499
+ },
500
+ cardStyle
501
+ ],
502
+ children
503
+ }
504
+ )
505
+ }
506
+ )
507
+ }
508
+ );
509
+ }
510
+ function DialogTitle({ children, style, ...rest }) {
511
+ const { tokens: t, baseTokens: bt } = useTheme();
512
+ const { ids } = useDialogContext();
513
+ return /* @__PURE__ */ jsxRuntime.jsx(
514
+ reactNative.Text,
515
+ {
516
+ ...rest,
517
+ nativeID: ids.title,
518
+ style: [
519
+ {
520
+ fontSize: 18,
521
+ fontWeight: "600",
522
+ color: t.entropixColorTextPrimary,
523
+ marginBottom: bt.entropixSpacing2
524
+ },
525
+ style
526
+ ],
527
+ accessibilityRole: "header",
528
+ children
529
+ }
530
+ );
531
+ }
532
+ function DialogDescription({
533
+ children,
534
+ style,
535
+ ...rest
536
+ }) {
537
+ const { tokens: t, baseTokens: bt } = useTheme();
538
+ const { ids } = useDialogContext();
539
+ return /* @__PURE__ */ jsxRuntime.jsx(
540
+ reactNative.Text,
541
+ {
542
+ ...rest,
543
+ nativeID: ids.description,
544
+ style: [
545
+ {
546
+ fontSize: bt.entropixFontSizeSm,
547
+ color: t.entropixColorTextSecondary,
548
+ lineHeight: 20,
549
+ marginBottom: bt.entropixSpacing4
550
+ },
551
+ style
552
+ ],
553
+ children
554
+ }
555
+ );
556
+ }
557
+ function DialogClose({ children, style, ...rest }) {
558
+ const { tokens: t, baseTokens: bt } = useTheme();
559
+ const { getCloseProps } = useDialogContext();
560
+ const propGetterReturn = getCloseProps();
561
+ const rnAccessibility = mapAccessibilityToRN(propGetterReturn.accessibility);
562
+ const handlePress = react.useCallback(() => {
563
+ propGetterReturn.onAction?.();
564
+ }, [propGetterReturn.onAction]);
565
+ return /* @__PURE__ */ jsxRuntime.jsx(
566
+ reactNative.Pressable,
567
+ {
568
+ ...rnAccessibility,
569
+ ...rest,
570
+ onPress: handlePress,
571
+ style: [
572
+ {
573
+ position: "absolute",
574
+ top: bt.entropixSpacing3,
575
+ right: bt.entropixSpacing3,
576
+ width: 32,
577
+ height: 32,
578
+ alignItems: "center",
579
+ justifyContent: "center",
580
+ borderRadius: bt.entropixRadiusSm
581
+ },
582
+ style
583
+ ],
584
+ accessibilityRole: "button",
585
+ children: children ?? /* @__PURE__ */ jsxRuntime.jsx(
586
+ reactNative.Text,
587
+ {
588
+ style: {
589
+ fontSize: 16,
590
+ color: t.entropixColorTextSecondary
591
+ },
592
+ children: "\u2715"
593
+ }
594
+ )
595
+ }
596
+ );
597
+ }
598
+ function DialogOverlay({ style, testID }) {
599
+ const { isOpen, getOverlayProps } = useDialogContext();
600
+ const propGetterReturn = getOverlayProps();
601
+ const handlePress = react.useCallback(() => {
602
+ propGetterReturn.onAction?.();
603
+ }, [propGetterReturn.onAction]);
604
+ if (!isOpen) return null;
605
+ return /* @__PURE__ */ jsxRuntime.jsx(
606
+ reactNative.Pressable,
607
+ {
608
+ testID,
609
+ accessible: false,
610
+ importantForAccessibility: "no",
611
+ onPress: propGetterReturn.onAction ? handlePress : void 0,
612
+ style: [
613
+ {
614
+ ...reactNative.StyleSheet.absoluteFillObject,
615
+ backgroundColor: "rgba(0, 0, 0, 0.5)"
616
+ },
617
+ style
618
+ ]
619
+ }
620
+ );
621
+ }
622
+ var TabsContext = react.createContext(null);
623
+ function useTabsContext() {
624
+ const context = react.useContext(TabsContext);
625
+ if (!context) {
626
+ throw new Error(
627
+ "Tabs compound components must be used within a <Tabs> provider."
628
+ );
629
+ }
630
+ return context;
631
+ }
632
+ function Tabs({ children, style, ...options }) {
633
+ const tabs = core.useTabs(options);
634
+ return /* @__PURE__ */ jsxRuntime.jsx(TabsContext.Provider, { value: tabs, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style, children }) });
635
+ }
636
+ function TabList({ children, style }) {
637
+ const { tokens: t, baseTokens: bt } = useTheme();
638
+ const { getTabListProps } = useTabsContext();
639
+ const propGetterReturn = getTabListProps();
640
+ const rnAccessibility = mapAccessibilityToRN(propGetterReturn.accessibility);
641
+ return /* @__PURE__ */ jsxRuntime.jsx(
642
+ reactNative.View,
643
+ {
644
+ ...rnAccessibility,
645
+ style: [
646
+ {
647
+ flexDirection: "row",
648
+ gap: bt.entropixSpacing1,
649
+ borderBottomWidth: 1,
650
+ borderBottomColor: t.entropixColorBorderDefault
651
+ },
652
+ style
653
+ ],
654
+ children
655
+ }
656
+ );
657
+ }
658
+ function Tab({ value, children, style, textStyle, ...rest }) {
659
+ const { tokens: t, baseTokens: bt } = useTheme();
660
+ const { getTabProps, selectedKey } = useTabsContext();
661
+ const propGetterReturn = getTabProps(value);
662
+ const rnAccessibility = mapAccessibilityToRN(propGetterReturn.accessibility);
663
+ const isActive = selectedKey === value;
664
+ const isDisabled = propGetterReturn.accessibility.disabled === true;
665
+ const handlePress = react.useCallback(() => {
666
+ propGetterReturn.onAction?.();
667
+ }, [propGetterReturn.onAction]);
668
+ return /* @__PURE__ */ jsxRuntime.jsx(
669
+ reactNative.Pressable,
670
+ {
671
+ ...rnAccessibility,
672
+ ...rest,
673
+ onPress: propGetterReturn.onAction ? handlePress : void 0,
674
+ style: [
675
+ {
676
+ paddingVertical: bt.entropixSpacing2,
677
+ paddingHorizontal: bt.entropixSpacing4,
678
+ borderBottomWidth: 2,
679
+ borderBottomColor: isActive ? t.entropixColorActionPrimaryDefault : "transparent"
680
+ },
681
+ isDisabled && { opacity: 0.5 },
682
+ style
683
+ ],
684
+ children: typeof children === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
685
+ reactNative.Text,
686
+ {
687
+ style: [
688
+ {
689
+ fontSize: bt.entropixFontSizeSm,
690
+ fontWeight: "500",
691
+ color: isActive ? t.entropixColorActionPrimaryDefault : t.entropixColorTextSecondary
692
+ },
693
+ textStyle
694
+ ],
695
+ children
696
+ }
697
+ ) : children
698
+ }
699
+ );
700
+ }
701
+ function TabPanel({ value, children, style }) {
702
+ const { baseTokens: bt } = useTheme();
703
+ const { getTabPanelProps, selectedKey } = useTabsContext();
704
+ const propGetterReturn = getTabPanelProps(value);
705
+ const rnAccessibility = mapAccessibilityToRN(propGetterReturn.accessibility);
706
+ if (selectedKey !== value) return null;
707
+ return /* @__PURE__ */ jsxRuntime.jsx(
708
+ reactNative.View,
709
+ {
710
+ ...rnAccessibility,
711
+ style: [{ padding: bt.entropixSpacing4 }, style],
712
+ children
713
+ }
714
+ );
715
+ }
716
+ var AccordionContext = react.createContext(null);
717
+ function useAccordionContext() {
718
+ const context = react.useContext(AccordionContext);
719
+ if (!context) {
720
+ throw new Error(
721
+ "Accordion compound components must be used within an <Accordion> provider."
722
+ );
723
+ }
724
+ return context;
725
+ }
726
+ var AccordionItemContext = react.createContext(null);
727
+ function useAccordionItemContext() {
728
+ const context = react.useContext(AccordionItemContext);
729
+ if (context === null) {
730
+ throw new Error(
731
+ "AccordionTrigger and AccordionPanel must be used within an <AccordionItem>."
732
+ );
733
+ }
734
+ return context;
735
+ }
736
+ function Accordion({ children, style, ...options }) {
737
+ const { tokens: t, baseTokens: bt } = useTheme();
738
+ const accordion = core.useAccordion(options);
739
+ return /* @__PURE__ */ jsxRuntime.jsx(AccordionContext.Provider, { value: accordion, children: /* @__PURE__ */ jsxRuntime.jsx(
740
+ reactNative.View,
741
+ {
742
+ style: [
743
+ {
744
+ borderWidth: 1,
745
+ borderColor: t.entropixColorBorderDefault,
746
+ borderRadius: bt.entropixRadiusLg,
747
+ overflow: "hidden"
748
+ },
749
+ style
750
+ ],
751
+ children
752
+ }
753
+ ) });
754
+ }
755
+ function AccordionItem({
756
+ value,
757
+ isLast = false,
758
+ children,
759
+ style
760
+ }) {
761
+ const { tokens: t } = useTheme();
762
+ return /* @__PURE__ */ jsxRuntime.jsx(AccordionItemContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx(
763
+ reactNative.View,
764
+ {
765
+ style: [
766
+ {
767
+ borderBottomWidth: isLast ? 0 : 1,
768
+ borderBottomColor: t.entropixColorBorderDefault
769
+ },
770
+ style
771
+ ],
772
+ children
773
+ }
774
+ ) });
775
+ }
776
+ function AccordionTrigger({
777
+ children,
778
+ style,
779
+ textStyle,
780
+ ...rest
781
+ }) {
782
+ const { tokens: t, baseTokens: bt } = useTheme();
783
+ const itemKey = useAccordionItemContext();
784
+ const { getItemTriggerProps, isExpanded } = useAccordionContext();
785
+ const propGetterReturn = getItemTriggerProps(itemKey);
786
+ const rnAccessibility = mapAccessibilityToRN(propGetterReturn.accessibility);
787
+ const expanded = isExpanded(itemKey);
788
+ const handlePress = react.useCallback(() => {
789
+ propGetterReturn.onAction?.();
790
+ }, [propGetterReturn.onAction]);
791
+ return /* @__PURE__ */ jsxRuntime.jsxs(
792
+ reactNative.Pressable,
793
+ {
794
+ ...rnAccessibility,
795
+ ...rest,
796
+ onPress: propGetterReturn.onAction ? handlePress : void 0,
797
+ style: [
798
+ {
799
+ flexDirection: "row",
800
+ alignItems: "center",
801
+ justifyContent: "space-between",
802
+ paddingVertical: bt.entropixSpacing4,
803
+ paddingHorizontal: bt.entropixSpacing4
804
+ },
805
+ style
806
+ ],
807
+ children: [
808
+ typeof children === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
809
+ reactNative.Text,
810
+ {
811
+ style: [
812
+ {
813
+ fontSize: bt.entropixFontSizeSm,
814
+ fontWeight: "500",
815
+ color: t.entropixColorTextPrimary,
816
+ flex: 1
817
+ },
818
+ textStyle
819
+ ],
820
+ children
821
+ }
822
+ ) : children,
823
+ /* @__PURE__ */ jsxRuntime.jsx(
824
+ reactNative.Text,
825
+ {
826
+ style: {
827
+ fontSize: 12,
828
+ color: t.entropixColorTextSecondary,
829
+ marginLeft: bt.entropixSpacing2
830
+ },
831
+ children: expanded ? "\u2212" : "+"
832
+ }
833
+ )
834
+ ]
835
+ }
836
+ );
837
+ }
838
+ function AccordionPanel({ children, style }) {
839
+ const { baseTokens: bt } = useTheme();
840
+ const itemKey = useAccordionItemContext();
841
+ const { getItemPanelProps, isExpanded } = useAccordionContext();
842
+ const propGetterReturn = getItemPanelProps(itemKey);
843
+ const rnAccessibility = mapAccessibilityToRN(propGetterReturn.accessibility);
844
+ if (!isExpanded(itemKey)) return null;
845
+ return /* @__PURE__ */ jsxRuntime.jsx(
846
+ reactNative.View,
847
+ {
848
+ ...rnAccessibility,
849
+ style: [
850
+ {
851
+ paddingHorizontal: bt.entropixSpacing4,
852
+ paddingBottom: bt.entropixSpacing4
853
+ },
854
+ style
855
+ ],
856
+ children
857
+ }
858
+ );
859
+ }
860
+ var MenuContext = react.createContext(null);
861
+ function useMenuContext() {
862
+ const context = react.useContext(MenuContext);
863
+ if (!context) {
864
+ throw new Error(
865
+ "Menu compound components must be used within a <Menu> provider."
866
+ );
867
+ }
868
+ return context;
869
+ }
870
+ function Menu({ children, ...options }) {
871
+ const menu = core.useMenu(options);
872
+ return /* @__PURE__ */ jsxRuntime.jsx(MenuContext.Provider, { value: menu, children });
873
+ }
874
+ function MenuTrigger({ children, style, ...rest }) {
875
+ const { getTriggerProps } = useMenuContext();
876
+ const propGetterReturn = getTriggerProps();
877
+ const rnAccessibility = mapAccessibilityToRN(propGetterReturn.accessibility);
878
+ const handlePress = react.useCallback(() => {
879
+ propGetterReturn.onAction?.();
880
+ }, [propGetterReturn.onAction]);
881
+ return /* @__PURE__ */ jsxRuntime.jsx(
882
+ reactNative.Pressable,
883
+ {
884
+ ...rnAccessibility,
885
+ ...rest,
886
+ onPress: handlePress,
887
+ style,
888
+ children
889
+ }
890
+ );
891
+ }
892
+ function MenuContent({ children, style, testID }) {
893
+ const { tokens: t, baseTokens: bt } = useTheme();
894
+ const { isOpen, getMenuProps } = useMenuContext();
895
+ const propGetterReturn = getMenuProps();
896
+ const rnAccessibility = mapAccessibilityToRN(propGetterReturn.accessibility);
897
+ if (!isOpen) return null;
898
+ return /* @__PURE__ */ jsxRuntime.jsx(
899
+ reactNative.View,
900
+ {
901
+ ...rnAccessibility,
902
+ testID,
903
+ style: [
904
+ {
905
+ minWidth: 160,
906
+ padding: bt.entropixSpacing1,
907
+ backgroundColor: t.entropixColorBgPrimary,
908
+ borderWidth: 1,
909
+ borderColor: t.entropixColorBorderDefault,
910
+ borderRadius: bt.entropixRadiusMd,
911
+ shadowColor: "#000",
912
+ shadowOffset: { width: 0, height: 2 },
913
+ shadowOpacity: 0.1,
914
+ shadowRadius: 8,
915
+ elevation: 4
916
+ },
917
+ style
918
+ ],
919
+ children
920
+ }
921
+ );
922
+ }
923
+ function wrapStringChildren(children, style) {
924
+ if (typeof children === "string" || typeof children === "number") {
925
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style, children });
926
+ }
927
+ return children;
928
+ }
929
+ function MenuItem({
930
+ index,
931
+ onSelect,
932
+ disabled,
933
+ children,
934
+ style,
935
+ textStyle,
936
+ ...rest
937
+ }) {
938
+ const { tokens: t, baseTokens: bt } = useTheme();
939
+ const { getItemProps } = useMenuContext();
940
+ const propGetterReturn = getItemProps(index, { onSelect, disabled });
941
+ const rnAccessibility = mapAccessibilityToRN(propGetterReturn.accessibility);
942
+ const handlePress = react.useCallback(() => {
943
+ propGetterReturn.onAction?.();
944
+ }, [propGetterReturn.onAction]);
945
+ return /* @__PURE__ */ jsxRuntime.jsx(
946
+ reactNative.Pressable,
947
+ {
948
+ ...rnAccessibility,
949
+ ...rest,
950
+ disabled,
951
+ onPress: propGetterReturn.onAction ? handlePress : void 0,
952
+ style: [
953
+ {
954
+ flexDirection: "row",
955
+ alignItems: "center",
956
+ paddingVertical: bt.entropixSpacing2,
957
+ paddingHorizontal: bt.entropixSpacing3,
958
+ borderRadius: bt.entropixRadiusSm,
959
+ opacity: disabled ? 0.5 : 1
960
+ },
961
+ style
962
+ ],
963
+ children: wrapStringChildren(children, {
964
+ fontSize: bt.entropixFontSizeSm,
965
+ color: t.entropixColorTextPrimary,
966
+ ...textStyle
967
+ })
968
+ }
969
+ );
970
+ }
971
+ var BREAKPOINTS = {
972
+ sm: 640,
973
+ md: 768,
974
+ lg: 1024,
975
+ xl: 1280,
976
+ "2xl": 1536
977
+ };
978
+ var BREAKPOINT_ORDER = ["base", "sm", "md", "lg", "xl", "2xl"];
979
+ function useBreakpoint() {
980
+ const getBreakpoint = react.useCallback(() => {
981
+ const { width } = reactNative.Dimensions.get("window");
982
+ if (width >= BREAKPOINTS["2xl"]) return "2xl";
983
+ if (width >= BREAKPOINTS.xl) return "xl";
984
+ if (width >= BREAKPOINTS.lg) return "lg";
985
+ if (width >= BREAKPOINTS.md) return "md";
986
+ if (width >= BREAKPOINTS.sm) return "sm";
987
+ return "base";
988
+ }, []);
989
+ const [breakpoint, setBreakpoint] = react.useState(getBreakpoint);
990
+ react.useEffect(() => {
991
+ const subscription = reactNative.Dimensions.addEventListener("change", ({ window }) => {
992
+ const width = window.width;
993
+ let next = "base";
994
+ if (width >= BREAKPOINTS["2xl"]) next = "2xl";
995
+ else if (width >= BREAKPOINTS.xl) next = "xl";
996
+ else if (width >= BREAKPOINTS.lg) next = "lg";
997
+ else if (width >= BREAKPOINTS.md) next = "md";
998
+ else if (width >= BREAKPOINTS.sm) next = "sm";
999
+ setBreakpoint((prev) => prev !== next ? next : prev);
1000
+ });
1001
+ return () => subscription.remove();
1002
+ }, []);
1003
+ return breakpoint;
1004
+ }
1005
+ function useBreakpointValue(breakpoint) {
1006
+ const current = useBreakpoint();
1007
+ const currentIndex = BREAKPOINT_ORDER.indexOf(current);
1008
+ const targetIndex = BREAKPOINT_ORDER.indexOf(breakpoint);
1009
+ return currentIndex >= targetIndex;
1010
+ }
1011
+ function useScreenDimensions() {
1012
+ const [dimensions, setDimensions] = react.useState(() => reactNative.Dimensions.get("window"));
1013
+ react.useEffect(() => {
1014
+ const subscription = reactNative.Dimensions.addEventListener("change", ({ window }) => {
1015
+ setDimensions(window);
1016
+ });
1017
+ return () => subscription.remove();
1018
+ }, []);
1019
+ return { width: dimensions.width, height: dimensions.height };
1020
+ }
1021
+ function Stack({
1022
+ gap,
1023
+ align,
1024
+ fullWidth,
1025
+ style,
1026
+ children,
1027
+ ...rest
1028
+ }) {
1029
+ const { baseTokens: bt } = useTheme();
1030
+ const gapValue = getGapValue(gap, bt);
1031
+ const alignMap = {
1032
+ start: "flex-start",
1033
+ center: "center",
1034
+ end: "flex-end",
1035
+ stretch: "stretch"
1036
+ };
1037
+ return /* @__PURE__ */ jsxRuntime.jsx(
1038
+ reactNative.View,
1039
+ {
1040
+ style: [
1041
+ { flexDirection: "column" },
1042
+ gapValue !== void 0 && { gap: gapValue },
1043
+ gapValue === void 0 && { gap: bt.entropixSpaceLayoutStack },
1044
+ align && { alignItems: alignMap[align] },
1045
+ fullWidth && { width: "100%" },
1046
+ style
1047
+ ],
1048
+ ...rest,
1049
+ children
1050
+ }
1051
+ );
1052
+ }
1053
+ function getGapValue(gap, bt) {
1054
+ if (!gap) return void 0;
1055
+ switch (gap) {
1056
+ case "none":
1057
+ return 0;
1058
+ case "xs":
1059
+ return bt.entropixSpacing1;
1060
+ case "sm":
1061
+ return bt.entropixSpacing2;
1062
+ case "md":
1063
+ return bt.entropixSpacing4;
1064
+ case "lg":
1065
+ return bt.entropixSpacing6;
1066
+ case "xl":
1067
+ return bt.entropixSpacing8;
1068
+ case "2xl":
1069
+ return bt.entropixSpacing12;
1070
+ }
1071
+ }
1072
+ function Inline({
1073
+ gap,
1074
+ align,
1075
+ justify,
1076
+ wrap,
1077
+ style,
1078
+ children,
1079
+ ...rest
1080
+ }) {
1081
+ const { baseTokens: bt } = useTheme();
1082
+ const gapValue = getGapValue2(gap, bt);
1083
+ const alignMap = {
1084
+ start: "flex-start",
1085
+ center: "center",
1086
+ end: "flex-end",
1087
+ stretch: "stretch",
1088
+ baseline: "baseline"
1089
+ };
1090
+ const justifyMap = {
1091
+ start: "flex-start",
1092
+ center: "center",
1093
+ end: "flex-end",
1094
+ between: "space-between",
1095
+ around: "space-around"
1096
+ };
1097
+ return /* @__PURE__ */ jsxRuntime.jsx(
1098
+ reactNative.View,
1099
+ {
1100
+ style: [
1101
+ {
1102
+ flexDirection: "row",
1103
+ alignItems: "center"
1104
+ },
1105
+ gapValue !== void 0 && { gap: gapValue },
1106
+ gapValue === void 0 && { gap: bt.entropixSpaceLayoutInline },
1107
+ align && { alignItems: alignMap[align] },
1108
+ justify && { justifyContent: justifyMap[justify] },
1109
+ wrap && { flexWrap: "wrap" },
1110
+ style
1111
+ ],
1112
+ ...rest,
1113
+ children
1114
+ }
1115
+ );
1116
+ }
1117
+ function getGapValue2(gap, bt) {
1118
+ if (!gap) return void 0;
1119
+ switch (gap) {
1120
+ case "none":
1121
+ return 0;
1122
+ case "xs":
1123
+ return bt.entropixSpacing1;
1124
+ case "sm":
1125
+ return bt.entropixSpacing2;
1126
+ case "md":
1127
+ return bt.entropixSpacing4;
1128
+ case "lg":
1129
+ return bt.entropixSpacing6;
1130
+ case "xl":
1131
+ return bt.entropixSpacing8;
1132
+ case "2xl":
1133
+ return bt.entropixSpacing12;
1134
+ }
1135
+ }
1136
+ var maxWidthMap = {
1137
+ xs: 480,
1138
+ sm: 640,
1139
+ md: 768,
1140
+ lg: 1024,
1141
+ xl: 1280,
1142
+ full: void 0
1143
+ };
1144
+ function Container({
1145
+ maxWidth = "lg",
1146
+ center,
1147
+ style,
1148
+ children,
1149
+ ...rest
1150
+ }) {
1151
+ const { baseTokens: bt } = useTheme();
1152
+ const breakpoint = useBreakpoint();
1153
+ const maxW = maxWidthMap[maxWidth];
1154
+ let pageMargin = bt.entropixSpaceLayoutPageMargin;
1155
+ if (breakpoint === "lg" || breakpoint === "xl" || breakpoint === "2xl") {
1156
+ pageMargin = bt.entropixSpaceLayoutPageMarginLg;
1157
+ } else if (breakpoint === "md") {
1158
+ pageMargin = bt.entropixSpaceLayoutPageMarginMd;
1159
+ }
1160
+ return /* @__PURE__ */ jsxRuntime.jsx(
1161
+ reactNative.View,
1162
+ {
1163
+ style: [
1164
+ {
1165
+ width: "100%",
1166
+ paddingHorizontal: pageMargin
1167
+ },
1168
+ maxW !== void 0 && { maxWidth: maxW, alignSelf: "center" },
1169
+ center && { alignItems: "center" },
1170
+ style
1171
+ ],
1172
+ ...rest,
1173
+ children
1174
+ }
1175
+ );
1176
+ }
1177
+ function Divider({
1178
+ orientation = "horizontal",
1179
+ spacing,
1180
+ style,
1181
+ ...rest
1182
+ }) {
1183
+ const { tokens: t, baseTokens: bt } = useTheme();
1184
+ const spacingMap = {
1185
+ sm: bt.entropixSpacing2,
1186
+ md: bt.entropixSpacing4,
1187
+ lg: bt.entropixSpacing6
1188
+ };
1189
+ const spacingValue = spacing ? spacingMap[spacing] : 0;
1190
+ const isVertical = orientation === "vertical";
1191
+ const dividerStyle = isVertical ? {
1192
+ width: 1,
1193
+ alignSelf: "stretch",
1194
+ backgroundColor: t.entropixColorBorderDefault,
1195
+ marginHorizontal: spacingValue
1196
+ } : {
1197
+ height: 1,
1198
+ width: "100%",
1199
+ backgroundColor: t.entropixColorBorderDefault,
1200
+ marginVertical: spacingValue
1201
+ };
1202
+ return /* @__PURE__ */ jsxRuntime.jsx(
1203
+ reactNative.View,
1204
+ {
1205
+ accessibilityRole: isVertical ? "none" : void 0,
1206
+ style: [dividerStyle, style],
1207
+ ...rest
1208
+ }
1209
+ );
1210
+ }
1211
+
1212
+ exports.Accordion = Accordion;
1213
+ exports.AccordionItem = AccordionItem;
1214
+ exports.AccordionPanel = AccordionPanel;
1215
+ exports.AccordionTrigger = AccordionTrigger;
1216
+ exports.BREAKPOINTS = BREAKPOINTS;
1217
+ exports.Button = Button;
1218
+ exports.Container = Container;
1219
+ exports.Dialog = Dialog;
1220
+ exports.DialogClose = DialogClose;
1221
+ exports.DialogContent = DialogContent;
1222
+ exports.DialogDescription = DialogDescription;
1223
+ exports.DialogOverlay = DialogOverlay;
1224
+ exports.DialogTitle = DialogTitle;
1225
+ exports.DialogTrigger = DialogTrigger;
1226
+ exports.Divider = Divider;
1227
+ exports.EntropixProvider = EntropixProvider;
1228
+ exports.Inline = Inline;
1229
+ exports.Menu = Menu;
1230
+ exports.MenuContent = MenuContent;
1231
+ exports.MenuItem = MenuItem;
1232
+ exports.MenuTrigger = MenuTrigger;
1233
+ exports.Stack = Stack;
1234
+ exports.Switch = Switch;
1235
+ exports.Tab = Tab;
1236
+ exports.TabList = TabList;
1237
+ exports.TabPanel = TabPanel;
1238
+ exports.Tabs = Tabs;
1239
+ exports.Toggle = Toggle;
1240
+ exports.mapAccessibilityToRN = mapAccessibilityToRN;
1241
+ exports.useBreakpoint = useBreakpoint;
1242
+ exports.useBreakpointValue = useBreakpointValue;
1243
+ exports.useScreenDimensions = useScreenDimensions;
1244
+ exports.useTheme = useTheme;
1245
+ //# sourceMappingURL=index.cjs.map
1246
+ //# sourceMappingURL=index.cjs.map