@sincpro/mobile-ui 0.5.0 → 0.6.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.
Files changed (82) hide show
  1. package/dist/Actions/Actions.Button.d.ts +151 -0
  2. package/dist/Actions/Actions.Button.js +217 -0
  3. package/dist/Actions/Actions.FAB.d.ts +10 -0
  4. package/dist/Actions/Actions.FAB.js +17 -0
  5. package/dist/Actions/Actions.FilterButton.d.ts +10 -0
  6. package/dist/Actions/Actions.FilterButton.js +28 -0
  7. package/dist/Actions/Actions.IconButton.d.ts +67 -0
  8. package/dist/Actions/Actions.IconButton.js +38 -0
  9. package/dist/Actions/index.d.ts +22 -0
  10. package/dist/Actions/index.js +17 -0
  11. package/dist/Dialog/BottomSheet/BottomSheet.Root.js +1 -0
  12. package/dist/Dialog/Dialog.Sheet.js +6 -4
  13. package/dist/Display/Display.CircleButton.d.ts +15 -0
  14. package/dist/Display/Display.CircleButton.js +39 -0
  15. package/dist/Display/Display.MenuButton.d.ts +51 -8
  16. package/dist/Display/Display.MenuButton.js +79 -13
  17. package/dist/Display/Display.MenuCard.d.ts +15 -0
  18. package/dist/Display/Display.MenuCard.js +24 -0
  19. package/dist/Display/Display.MenuGrid.d.ts +19 -0
  20. package/dist/Display/Display.MenuGrid.js +7 -0
  21. package/dist/Display/Display.SwipeableRow.js +2 -1
  22. package/dist/Display/Display.Tooltip.d.ts +1 -1
  23. package/dist/Display/Display.Tooltip.js +16 -5
  24. package/dist/Display/index.d.ts +9 -0
  25. package/dist/Display/index.js +6 -0
  26. package/dist/Feedback/Feedback.Empty.js +2 -2
  27. package/dist/Feedback/Feedback.Error.js +2 -2
  28. package/dist/Feedback/Feedback.Progress.js +2 -2
  29. package/dist/Feedback/Feedback.Skeleton.js +2 -2
  30. package/dist/Feedback/Feedback.Splash.js +1 -0
  31. package/dist/Form/Form.Button.d.ts +3 -151
  32. package/dist/Form/Form.Button.js +1 -283
  33. package/dist/Form/Form.FAB.d.ts +3 -10
  34. package/dist/Form/Form.FAB.js +1 -17
  35. package/dist/Form/Form.FilterButton.d.ts +3 -12
  36. package/dist/Form/Form.FilterButton.js +1 -34
  37. package/dist/Form/Form.IconButton.d.ts +3 -67
  38. package/dist/Form/Form.IconButton.js +1 -64
  39. package/dist/Navigation/Navigation.AppBar.d.ts +56 -1
  40. package/dist/Navigation/Navigation.AppBar.js +43 -12
  41. package/dist/Navigation/Navigation.BottomNav.js +2 -1
  42. package/dist/Navigation/Navigation.Header.js +3 -2
  43. package/dist/Navigation/Navigation.Menu.js +6 -3
  44. package/dist/Navigation/Navigation.MenuSection.d.ts +19 -0
  45. package/dist/Navigation/Navigation.MenuSection.js +25 -0
  46. package/dist/Navigation/Navigation.SegmentedControl.d.ts +15 -1
  47. package/dist/Navigation/Navigation.SegmentedControl.js +22 -4
  48. package/dist/Navigation/Navigation.TabIcon.js +1 -2
  49. package/dist/Navigation/Navigation.TabItem.js +2 -2
  50. package/dist/Navigation/Navigation.Tabs.d.ts +8 -3
  51. package/dist/Navigation/Navigation.Tabs.js +19 -6
  52. package/dist/Navigation/index.d.ts +7 -6
  53. package/dist/Navigation/index.js +2 -0
  54. package/dist/index.d.ts +2 -0
  55. package/dist/index.js +2 -0
  56. package/dist/layouts/BottomInset.d.ts +16 -0
  57. package/dist/layouts/BottomInset.js +17 -0
  58. package/dist/layouts/TabNavigatorLayout.js +2 -2
  59. package/dist/primitives/BaseButton.js +3 -3
  60. package/dist/theme/default.js +1 -1
  61. package/dist/views/FormViewV2.d.ts +18 -6
  62. package/dist/views/FormViewV2.js +14 -11
  63. package/dist/views/ListViewV2.d.ts +12 -1
  64. package/dist/views/ListViewV2.js +16 -10
  65. package/dist/widgets/CircleButton.d.ts +3 -19
  66. package/dist/widgets/CircleButton.js +1 -41
  67. package/dist/widgets/JSONViewer.js +7 -7
  68. package/dist/widgets/MenuCard.d.ts +3 -13
  69. package/dist/widgets/MenuCard.js +1 -8
  70. package/dist/widgets/MenuGrid.d.ts +5 -17
  71. package/dist/widgets/MenuGrid.js +1 -6
  72. package/dist/widgets/MenuSection.d.ts +3 -0
  73. package/dist/widgets/MenuSection.js +1 -0
  74. package/dist/widgets/PromoBanner.d.ts +38 -0
  75. package/dist/widgets/PromoBanner.js +61 -0
  76. package/dist/widgets/PromoModal.d.ts +41 -0
  77. package/dist/widgets/PromoModal.js +75 -0
  78. package/dist/widgets/QuickActions.d.ts +26 -0
  79. package/dist/widgets/QuickActions.js +41 -0
  80. package/dist/widgets/index.d.ts +11 -1
  81. package/dist/widgets/index.js +4 -0
  82. package/package.json +2 -1
@@ -0,0 +1,151 @@
1
+ import { type VariantProps } from "../theme/tw";
2
+ import type React from "react";
3
+ declare const button: import("tailwind-variants").TVReturnType<{
4
+ variant: {
5
+ primary: string;
6
+ accent: string;
7
+ cta: string;
8
+ secondary: string;
9
+ outline: string;
10
+ outlineDanger: string;
11
+ outlineBlack: string;
12
+ flat: string;
13
+ link: string;
14
+ transparent: string;
15
+ };
16
+ size: {
17
+ small: string;
18
+ medium: string;
19
+ large: string;
20
+ };
21
+ disabled: {
22
+ true: string;
23
+ };
24
+ }, undefined, "rounded-[13px] items-center justify-center flex-row min-h-[44px]", {
25
+ variant: {
26
+ primary: string;
27
+ accent: string;
28
+ cta: string;
29
+ secondary: string;
30
+ outline: string;
31
+ outlineDanger: string;
32
+ outlineBlack: string;
33
+ flat: string;
34
+ link: string;
35
+ transparent: string;
36
+ };
37
+ size: {
38
+ small: string;
39
+ medium: string;
40
+ large: string;
41
+ };
42
+ disabled: {
43
+ true: string;
44
+ };
45
+ }, undefined, import("tailwind-variants").TVReturnType<{
46
+ variant: {
47
+ primary: string;
48
+ accent: string;
49
+ cta: string;
50
+ secondary: string;
51
+ outline: string;
52
+ outlineDanger: string;
53
+ outlineBlack: string;
54
+ flat: string;
55
+ link: string;
56
+ transparent: string;
57
+ };
58
+ size: {
59
+ small: string;
60
+ medium: string;
61
+ large: string;
62
+ };
63
+ disabled: {
64
+ true: string;
65
+ };
66
+ }, undefined, "rounded-[13px] items-center justify-center flex-row min-h-[44px]", unknown, unknown, undefined>>;
67
+ declare const buttonIcon: import("tailwind-variants").TVReturnType<{
68
+ variant: {
69
+ primary: string;
70
+ accent: string;
71
+ cta: string;
72
+ secondary: string;
73
+ outline: string;
74
+ outlineDanger: string;
75
+ outlineBlack: string;
76
+ flat: string;
77
+ link: string;
78
+ transparent: string;
79
+ };
80
+ size: {
81
+ small: string;
82
+ medium: string;
83
+ large: string;
84
+ };
85
+ disabled: {
86
+ true: string;
87
+ };
88
+ }, undefined, "rounded-[13px] items-center justify-center aspect-square", {
89
+ variant: {
90
+ primary: string;
91
+ accent: string;
92
+ cta: string;
93
+ secondary: string;
94
+ outline: string;
95
+ outlineDanger: string;
96
+ outlineBlack: string;
97
+ flat: string;
98
+ link: string;
99
+ transparent: string;
100
+ };
101
+ size: {
102
+ small: string;
103
+ medium: string;
104
+ large: string;
105
+ };
106
+ disabled: {
107
+ true: string;
108
+ };
109
+ }, undefined, import("tailwind-variants").TVReturnType<{
110
+ variant: {
111
+ primary: string;
112
+ accent: string;
113
+ cta: string;
114
+ secondary: string;
115
+ outline: string;
116
+ outlineDanger: string;
117
+ outlineBlack: string;
118
+ flat: string;
119
+ link: string;
120
+ transparent: string;
121
+ };
122
+ size: {
123
+ small: string;
124
+ medium: string;
125
+ large: string;
126
+ };
127
+ disabled: {
128
+ true: string;
129
+ };
130
+ }, undefined, "rounded-[13px] items-center justify-center aspect-square", unknown, unknown, undefined>>;
131
+ export interface ButtonProps extends VariantProps<typeof button> {
132
+ title: string;
133
+ onPress?: () => void;
134
+ confirm?: string;
135
+ loading?: boolean;
136
+ disabled?: boolean;
137
+ className?: string;
138
+ icon?: React.ReactNode;
139
+ }
140
+ export interface ButtonIconProps extends VariantProps<typeof buttonIcon> {
141
+ icon: string;
142
+ onPress?: () => void;
143
+ confirm?: string;
144
+ loading?: boolean;
145
+ disabled?: boolean;
146
+ className?: string;
147
+ }
148
+ declare const ButtonWithIcon: React.FC<ButtonProps> & {
149
+ Icon: React.FC<ButtonIconProps>;
150
+ };
151
+ export default ButtonWithIcon;
@@ -0,0 +1,217 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "nativewind/jsx-runtime";
2
+ import { useConfirmationContext } from "../Dialog/Confirmation.context";
3
+ import Icon from "../Display/Display.Icon";
4
+ import { theme } from "../theme";
5
+ import { tv } from "../theme/tw";
6
+ import { Typography } from "../Typography";
7
+ import { LinearGradient } from "expo-linear-gradient";
8
+ import { useCallback } from "react";
9
+ import { ActivityIndicator, TouchableOpacity, View } from "react-native";
10
+ import { runOnJS } from "react-native-reanimated";
11
+ // ─── Style variants ───────────────────────────────────────────────────────────
12
+ const button = tv({
13
+ base: "rounded-[13px] items-center justify-center flex-row min-h-[44px]",
14
+ variants: {
15
+ variant: {
16
+ primary: "shadow-sm",
17
+ accent: "shadow-sm",
18
+ cta: "shadow-sm",
19
+ secondary: "bg-bg-muted",
20
+ outline: "bg-transparent border border-primary",
21
+ outlineDanger: "bg-transparent border border-danger",
22
+ outlineBlack: "bg-transparent border border-border-strong",
23
+ flat: "bg-text-primary/10",
24
+ link: "bg-transparent min-h-0",
25
+ transparent: "bg-transparent border border-border-light",
26
+ },
27
+ size: {
28
+ small: "py-1.5 px-3 min-h-[36px]",
29
+ medium: "py-2.5 px-4 min-h-[44px]",
30
+ large: "py-3 px-5 min-h-[48px]",
31
+ },
32
+ disabled: {
33
+ true: "opacity-70",
34
+ },
35
+ },
36
+ defaultVariants: {
37
+ variant: "primary",
38
+ size: "medium",
39
+ },
40
+ });
41
+ const buttonIcon = tv({
42
+ base: "rounded-[13px] items-center justify-center aspect-square",
43
+ variants: {
44
+ variant: {
45
+ primary: "shadow-sm",
46
+ accent: "shadow-sm",
47
+ cta: "shadow-sm",
48
+ secondary: "bg-bg-muted",
49
+ outline: "bg-transparent border border-primary",
50
+ outlineDanger: "bg-transparent border border-danger",
51
+ outlineBlack: "bg-transparent border border-border-strong",
52
+ flat: "bg-text-primary/10",
53
+ link: "bg-transparent",
54
+ transparent: "bg-transparent border border-border-light",
55
+ },
56
+ size: {
57
+ small: "w-9 h-9",
58
+ medium: "w-11 h-11",
59
+ large: "w-[52px] h-[52px]",
60
+ },
61
+ disabled: {
62
+ true: "opacity-70",
63
+ },
64
+ },
65
+ defaultVariants: {
66
+ variant: "primary",
67
+ size: "medium",
68
+ },
69
+ });
70
+ const textColor = tv({
71
+ variants: {
72
+ variant: {
73
+ primary: "text-white",
74
+ accent: "text-text-on-accent",
75
+ cta: "text-text-on-accent",
76
+ secondary: "text-text-primary",
77
+ outline: "text-primary",
78
+ outlineDanger: "text-danger",
79
+ outlineBlack: "text-text-primary",
80
+ flat: "text-text-primary",
81
+ link: "text-primary",
82
+ transparent: "text-white",
83
+ },
84
+ disabled: {
85
+ true: "opacity-50",
86
+ },
87
+ },
88
+ compoundVariants: [
89
+ { variant: "primary", disabled: true, className: "text-white/70" },
90
+ { variant: "accent", disabled: true, className: "text-text-on-accent" },
91
+ { variant: "cta", disabled: true, className: "text-text-on-accent" },
92
+ { variant: "transparent", disabled: true, className: "text-white/70" },
93
+ {
94
+ variant: ["secondary", "outline", "link"],
95
+ disabled: true,
96
+ className: "text-text-secondary",
97
+ },
98
+ { variant: "outlineDanger", disabled: true, className: "text-danger/50" },
99
+ { variant: "outlineBlack", disabled: true, className: "text-text-primary/50" },
100
+ { variant: "flat", disabled: true, className: "text-text-primary/50" },
101
+ ],
102
+ defaultVariants: { variant: "primary", disabled: false },
103
+ });
104
+ // ─── Color / size helpers ─────────────────────────────────────────────────────
105
+ function getLoadingColor(variant) {
106
+ const map = {
107
+ primary: theme.text.inverse,
108
+ accent: theme.text.inverse,
109
+ cta: theme.text.inverse,
110
+ secondary: theme.text.primary,
111
+ outline: theme.primary,
112
+ outlineDanger: theme.danger,
113
+ outlineBlack: theme.text.primary,
114
+ flat: theme.text.primary,
115
+ link: theme.primary,
116
+ transparent: theme.text.inverse,
117
+ };
118
+ return map[variant] ?? theme.text.inverse;
119
+ }
120
+ function getIconColor(variant, disabled) {
121
+ if (disabled) {
122
+ const map = {
123
+ primary: theme.icon.inverse + "70",
124
+ accent: theme.text.onAccent + "70",
125
+ cta: theme.text.onAccent + "70",
126
+ secondary: theme.text.disabled,
127
+ outline: theme.icon.disabled,
128
+ outlineDanger: theme.danger + "7f",
129
+ outlineBlack: theme.text.primary + "7f",
130
+ flat: theme.text.primary + "7f",
131
+ link: theme.icon.disabled,
132
+ transparent: theme.icon.inverse + "70",
133
+ };
134
+ return map[variant] ?? theme.icon.disabled;
135
+ }
136
+ const map = {
137
+ primary: theme.icon.inverse,
138
+ accent: theme.text.onAccent,
139
+ cta: theme.text.onAccent,
140
+ secondary: theme.text.primary,
141
+ outline: theme.primary,
142
+ outlineDanger: theme.danger,
143
+ outlineBlack: theme.text.primary,
144
+ flat: theme.text.primary,
145
+ link: theme.primary,
146
+ transparent: theme.icon.inverse,
147
+ };
148
+ return map[variant] ?? theme.icon.inverse;
149
+ }
150
+ const iconSizeMap = { small: 16, medium: 20, large: 28 };
151
+ const textVariantMap = {
152
+ small: "buttonSmall",
153
+ medium: "button",
154
+ large: "buttonLarge",
155
+ };
156
+ const Button = ({ title, onPress, confirm, variant = "primary", size = "medium", loading = false, disabled = false, className, icon, }) => {
157
+ const { show, hide } = useConfirmationContext();
158
+ const textColorClass = textColor({ variant: variant, disabled });
159
+ const loadingColorValue = getLoadingColor(variant);
160
+ const textVariantValue = textVariantMap[size] ?? "button";
161
+ const handlePress = useCallback(() => {
162
+ if (confirm && onPress) {
163
+ show({
164
+ title: "Confirmar acción",
165
+ message: confirm,
166
+ confirmText: "Confirmar",
167
+ cancelText: "Cancelar",
168
+ onConfirm: () => {
169
+ hide();
170
+ runOnJS(onPress)();
171
+ },
172
+ onCancel: () => hide(),
173
+ });
174
+ }
175
+ else if (onPress) {
176
+ runOnJS(onPress)();
177
+ }
178
+ }, [onPress, confirm, show, hide]);
179
+ if (variant === "link") {
180
+ return (_jsx(TouchableOpacity, { activeOpacity: 0.7, className: className, disabled: disabled || loading, onPress: handlePress, children: loading ? (_jsx(ActivityIndicator, { color: loadingColorValue, size: "small" })) : (_jsx(Typography.Text, { className: textColorClass, variant: textVariantValue, children: title })) }));
181
+ }
182
+ if (variant === "primary" || variant === "accent" || variant === "cta") {
183
+ const gradientColors = variant === "primary" ? theme.gradient.primary : theme.gradient.accent;
184
+ return (_jsx(LinearGradient, { colors: gradientColors, end: { x: 1, y: 1 }, start: { x: 0, y: 0 }, style: { borderRadius: 13, opacity: disabled ? 0.7 : 1 }, children: _jsx(TouchableOpacity, { activeOpacity: 0.8, disabled: disabled || loading, onPress: handlePress, children: _jsx(View, { className: button({ size, disabled }), style: { backgroundColor: "transparent" }, children: loading ? (_jsx(ActivityIndicator, { color: loadingColorValue, size: "small" })) : (_jsxs(_Fragment, { children: [icon ? _jsx(View, { className: "mr-2", children: icon }) : null, _jsx(Typography.Text, { allowFontScaling: false, bold: true, className: textColorClass, ellipsizeMode: "tail", numberOfLines: 1, variant: textVariantValue, children: title })] })) }) }) }));
185
+ }
186
+ return (_jsx(TouchableOpacity, { activeOpacity: 0.8, className: button({ variant, size, disabled, className }), disabled: disabled || loading, onPress: handlePress, children: loading ? (_jsx(ActivityIndicator, { color: loadingColorValue, size: "small" })) : (_jsxs(_Fragment, { children: [icon ? _jsx(View, { className: "mr-2", children: icon }) : null, _jsx(Typography.Text, { allowFontScaling: false, bold: true, className: textColorClass, ellipsizeMode: "tail", numberOfLines: 1, variant: textVariantValue, children: title })] })) }));
187
+ };
188
+ const ButtonIcon = ({ icon, onPress, confirm, variant = "primary", size = "medium", loading = false, disabled = false, className, }) => {
189
+ const { show, hide } = useConfirmationContext();
190
+ const iconColorValue = getIconColor(variant, disabled);
191
+ const iconSizeValue = iconSizeMap[size] ?? 20;
192
+ const loadingColorValue = getLoadingColor(variant);
193
+ const handlePress = useCallback(() => {
194
+ if (confirm && onPress) {
195
+ show({
196
+ title: "Confirmar acción",
197
+ message: confirm,
198
+ confirmText: "Confirmar",
199
+ cancelText: "Cancelar",
200
+ onConfirm: () => {
201
+ hide();
202
+ runOnJS(onPress)();
203
+ },
204
+ onCancel: () => hide(),
205
+ });
206
+ }
207
+ else if (onPress) {
208
+ runOnJS(onPress)();
209
+ }
210
+ }, [onPress, confirm, show, hide]);
211
+ if (variant === "primary") {
212
+ return (_jsx(LinearGradient, { colors: theme.gradient.primary, end: { x: 1, y: 1 }, start: { x: 0, y: 0 }, style: { borderRadius: 13, opacity: disabled ? 0.7 : 1 }, children: _jsx(TouchableOpacity, { activeOpacity: 0.8, disabled: disabled || loading, onPress: handlePress, children: _jsx(View, { className: buttonIcon({ size, disabled }), style: { backgroundColor: "transparent" }, children: loading ? (_jsx(ActivityIndicator, { color: loadingColorValue, size: "small" })) : (_jsx(Icon, { color: iconColorValue, name: icon, size: iconSizeValue })) }) }) }));
213
+ }
214
+ return (_jsx(TouchableOpacity, { activeOpacity: 0.8, className: buttonIcon({ variant, size, disabled, className }), disabled: disabled || loading, onPress: handlePress, children: loading ? (_jsx(ActivityIndicator, { color: loadingColorValue, size: "small" })) : (_jsx(Icon, { color: iconColorValue, name: icon, size: iconSizeValue })) }));
215
+ };
216
+ const ButtonWithIcon = Object.assign(Button, { Icon: ButtonIcon });
217
+ export default ButtonWithIcon;
@@ -0,0 +1,10 @@
1
+ export interface FABProps {
2
+ icon: string;
3
+ onPress: () => void;
4
+ label?: string;
5
+ position?: "bottom-right" | "bottom-left";
6
+ className?: string;
7
+ testID?: string;
8
+ }
9
+ declare function FAB({ icon, onPress, label, position, className, testID, }: FABProps): import("react").JSX.Element;
10
+ export default FAB;
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
2
+ import Icon from "../Display/Display.Icon";
3
+ import Pressable from "../primitives/Pressable";
4
+ import { theme } from "../theme";
5
+ import { cn } from "../theme/tw";
6
+ import { Typography } from "../Typography";
7
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
8
+ function FAB({ icon, onPress, label, position = "bottom-right", className, testID, }) {
9
+ const insets = useSafeAreaInsets();
10
+ return (_jsxs(Pressable, { accessibilityLabel: label ?? "Acción", accessibilityRole: "button", className: cn("absolute flex-row items-center justify-center rounded-full bg-primary", label ? "h-14 px-5 gap-2" : "w-14 h-14", className), onPress: onPress, style: {
11
+ bottom: insets.bottom + 16,
12
+ right: position === "bottom-right" ? 16 : undefined,
13
+ left: position === "bottom-left" ? 16 : undefined,
14
+ ...theme.shadow.lg,
15
+ }, testID: testID, children: [_jsx(Icon, { color: theme.icon.inverse, name: icon, size: 24 }), label ? (_jsx(Typography.Text, { className: "text-text-on-primary font-semibold", children: label })) : null] }));
16
+ }
17
+ export default FAB;
@@ -0,0 +1,10 @@
1
+ import { FC, ReactNode } from "react";
2
+ export interface FilterButtonProps {
3
+ title: string;
4
+ active: boolean;
5
+ onPress: () => void;
6
+ }
7
+ export declare const FilterButton: FC<FilterButtonProps>;
8
+ export declare function FilterButtonGroup({ children }: {
9
+ children: ReactNode;
10
+ }): import("react").JSX.Element;
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx } from "nativewind/jsx-runtime";
2
+ import { tv } from "../theme/tw";
3
+ import { Typography } from "../Typography";
4
+ import { TouchableOpacity, View } from "react-native";
5
+ const filterButton = tv({
6
+ base: "rounded-lg items-center justify-center py-2 px-3 min-h-[36px]",
7
+ variants: {
8
+ active: {
9
+ true: "bg-primary border-0",
10
+ false: "bg-transparent border border-brand-primary",
11
+ },
12
+ },
13
+ defaultVariants: { active: false },
14
+ });
15
+ const filterText = tv({
16
+ base: "font-bold",
17
+ variants: {
18
+ active: {
19
+ true: "text-white",
20
+ false: "text-primary",
21
+ },
22
+ },
23
+ defaultVariants: { active: false },
24
+ });
25
+ export const FilterButton = ({ title, active, onPress }) => (_jsx(TouchableOpacity, { activeOpacity: 0.8, className: filterButton({ active }), onPress: onPress, children: _jsx(Typography.Text, { className: filterText({ active }), variant: "buttonSmall", children: title }) }));
26
+ export function FilterButtonGroup({ children }) {
27
+ return _jsx(View, { className: "flex-row gap-2 p-3", children: children });
28
+ }
@@ -0,0 +1,67 @@
1
+ import { type VariantProps } from "../theme/tw";
2
+ import { IconType } from "../utils/icon";
3
+ declare const iconButton: import("tailwind-variants").TVReturnType<{
4
+ variant: {
5
+ primary: string;
6
+ secondary: string;
7
+ tertiary: string;
8
+ ghost: string;
9
+ };
10
+ size: {
11
+ small: string;
12
+ medium: string;
13
+ large: string;
14
+ };
15
+ rounded: {
16
+ true: string;
17
+ };
18
+ disabled: {
19
+ true: string;
20
+ };
21
+ }, undefined, "rounded-lg items-center justify-center", {
22
+ variant: {
23
+ primary: string;
24
+ secondary: string;
25
+ tertiary: string;
26
+ ghost: string;
27
+ };
28
+ size: {
29
+ small: string;
30
+ medium: string;
31
+ large: string;
32
+ };
33
+ rounded: {
34
+ true: string;
35
+ };
36
+ disabled: {
37
+ true: string;
38
+ };
39
+ }, undefined, import("tailwind-variants").TVReturnType<{
40
+ variant: {
41
+ primary: string;
42
+ secondary: string;
43
+ tertiary: string;
44
+ ghost: string;
45
+ };
46
+ size: {
47
+ small: string;
48
+ medium: string;
49
+ large: string;
50
+ };
51
+ rounded: {
52
+ true: string;
53
+ };
54
+ disabled: {
55
+ true: string;
56
+ };
57
+ }, undefined, "rounded-lg items-center justify-center", unknown, unknown, undefined>>;
58
+ export interface IconButtonProps extends VariantProps<typeof iconButton> {
59
+ icon?: string;
60
+ type?: IconType;
61
+ onPress: () => void;
62
+ loading?: boolean;
63
+ iconColor?: string;
64
+ className?: string;
65
+ }
66
+ declare function IconButton({ icon, type, onPress, variant, size, loading, disabled, rounded, iconColor, className, }: IconButtonProps): import("react").JSX.Element;
67
+ export default IconButton;
@@ -0,0 +1,38 @@
1
+ import { jsx as _jsx } from "nativewind/jsx-runtime";
2
+ import { Display } from "../Display";
3
+ import { theme } from "../theme";
4
+ import { tv } from "../theme/tw";
5
+ import { ActivityIndicator, TouchableOpacity } from "react-native";
6
+ const iconButton = tv({
7
+ base: "rounded-lg items-center justify-center",
8
+ variants: {
9
+ variant: {
10
+ primary: "bg-primary",
11
+ secondary: "bg-bg-card border border-primary",
12
+ tertiary: "bg-accent",
13
+ ghost: "bg-transparent",
14
+ },
15
+ size: {
16
+ small: "w-8 h-8",
17
+ medium: "w-10 h-10",
18
+ large: "w-12 h-12",
19
+ },
20
+ rounded: {
21
+ true: "rounded-full",
22
+ },
23
+ disabled: {
24
+ true: "opacity-50",
25
+ },
26
+ },
27
+ defaultVariants: {
28
+ variant: "ghost",
29
+ size: "medium",
30
+ rounded: false,
31
+ disabled: false,
32
+ },
33
+ });
34
+ function IconButton({ icon, type = "feather", onPress, variant = "ghost", size = "medium", loading = false, disabled = false, rounded = false, iconColor, className, }) {
35
+ const resolvedColor = iconColor ?? theme.primary;
36
+ return (_jsx(TouchableOpacity, { activeOpacity: 0.7, className: iconButton({ variant, size, rounded, disabled, className }), disabled: disabled || loading, onPress: onPress, children: loading ? (_jsx(ActivityIndicator, { color: resolvedColor, size: "small" })) : (_jsx(Display.Icon, { color: resolvedColor, name: icon, size: 24, type: type })) }));
37
+ }
38
+ export default IconButton;
@@ -0,0 +1,22 @@
1
+ import FAB from "../Actions/Actions.FAB";
2
+ import { FilterButtonGroup } from "../Actions/Actions.FilterButton";
3
+ import IconButton from "../Actions/Actions.IconButton";
4
+ export declare const Actions: {
5
+ /** Primary action button — gradient, outline, flat, link variants. Supports confirm dialog. */
6
+ Button: import("react").FC<import("../Actions/Actions.Button").ButtonProps> & {
7
+ Icon: import("react").FC<import("../Actions/Actions.Button").ButtonIconProps>;
8
+ };
9
+ /** Small icon-only tap target — ghost, primary, secondary, tertiary variants. */
10
+ IconButton: typeof IconButton;
11
+ /** Floating Action Button — fixed bottom-right/left, label-optional. */
12
+ FAB: typeof FAB;
13
+ /** Chip-style active/inactive toggle — use inside `Actions.FilterButtonGroup`. */
14
+ FilterButton: import("react").FC<import("../Actions/Actions.FilterButton").FilterButtonProps>;
15
+ /** Horizontal scroll container for `Actions.FilterButton` chips. */
16
+ FilterButtonGroup: typeof FilterButtonGroup;
17
+ };
18
+ export type { ButtonIconProps, ButtonProps } from "../Actions/Actions.Button";
19
+ export type { FABProps } from "../Actions/Actions.FAB";
20
+ export type { FilterButtonProps } from "../Actions/Actions.FilterButton";
21
+ export type { IconButtonProps } from "../Actions/Actions.IconButton";
22
+ export default Actions;
@@ -0,0 +1,17 @@
1
+ import ButtonWithIcon from "../Actions/Actions.Button";
2
+ import FAB from "../Actions/Actions.FAB";
3
+ import { FilterButton, FilterButtonGroup, } from "../Actions/Actions.FilterButton";
4
+ import IconButton from "../Actions/Actions.IconButton";
5
+ export const Actions = {
6
+ /** Primary action button — gradient, outline, flat, link variants. Supports confirm dialog. */
7
+ Button: ButtonWithIcon,
8
+ /** Small icon-only tap target — ghost, primary, secondary, tertiary variants. */
9
+ IconButton,
10
+ /** Floating Action Button — fixed bottom-right/left, label-optional. */
11
+ FAB,
12
+ /** Chip-style active/inactive toggle — use inside `Actions.FilterButtonGroup`. */
13
+ FilterButton,
14
+ /** Horizontal scroll container for `Actions.FilterButton` chips. */
15
+ FilterButtonGroup,
16
+ };
17
+ export default Actions;
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
2
+ /* eslint-disable react-hooks/refs */
2
3
  import { theme } from "../../theme";
3
4
  import { createContext, useContext, useEffect, useRef } from "react";
4
5
  import { Animated, Dimensions, Modal, PanResponder, Pressable, ScrollView, Text, View, } from "react-native";
@@ -1,7 +1,7 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
2
2
  import { theme } from "../theme";
3
3
  import { Typography } from "../Typography";
4
- import { useEffect, useRef } from "react";
4
+ import { useEffect, useRef, useState } from "react";
5
5
  import { Animated, Modal, PanResponder, ScrollView, View } from "react-native";
6
6
  import { useSafeAreaInsets } from "react-native-safe-area-context";
7
7
  /**
@@ -18,14 +18,16 @@ export function SheetProvider({ children }) {
18
18
  */
19
19
  function Sheet({ visible, onClose, children, title, maxHeightRatio = 0.9, dismissOnBackdrop = false, testID, }) {
20
20
  const insets = useSafeAreaInsets();
21
- const translateY = useRef(new Animated.Value(0)).current;
21
+ const [translateY] = useState(() => new Animated.Value(0));
22
22
  const onCloseRef = useRef(onClose);
23
+ // eslint-disable-next-line react-hooks/refs
23
24
  onCloseRef.current = onClose;
24
25
  useEffect(() => {
25
26
  if (visible)
26
27
  translateY.setValue(0);
27
28
  }, [visible, translateY]);
28
- const pan = useRef(PanResponder.create({
29
+ // eslint-disable-next-line react-hooks/refs
30
+ const [pan] = useState(() => PanResponder.create({
29
31
  onStartShouldSetPanResponder: () => true,
30
32
  onMoveShouldSetPanResponder: (_, g) => g.dy > 2,
31
33
  onPanResponderMove: (_, g) => {
@@ -44,7 +46,7 @@ function Sheet({ visible, onClose, children, title, maxHeightRatio = 0.9, dismis
44
46
  Animated.spring(translateY, { toValue: 0, useNativeDriver: true }).start();
45
47
  }
46
48
  },
47
- })).current;
49
+ }));
48
50
  return (_jsx(Modal, { animationType: "slide", onRequestClose: onClose, transparent: true, visible: visible, children: _jsxs(View, { className: "flex-1 justify-end", testID: testID, children: [_jsx(View, { className: "absolute inset-0 bg-black/50", onResponderRelease: dismissOnBackdrop ? onClose : undefined, onStartShouldSetResponder: () => dismissOnBackdrop }), _jsxs(Animated.View, { className: "rounded-t-3xl", style: {
49
51
  backgroundColor: theme.bg.card,
50
52
  paddingBottom: insets.bottom + 12,
@@ -0,0 +1,15 @@
1
+ import { IconType } from "../utils/icon";
2
+ import { ComponentType } from "react";
3
+ export interface CircleButtonProps {
4
+ iconType?: IconType;
5
+ size?: "sm" | "md" | "lg";
6
+ color?: string;
7
+ variant?: "primary" | "secondary" | "accent" | "success" | "danger" | "warning";
8
+ className?: string;
9
+ customIcon?: ComponentType<{
10
+ size?: number;
11
+ color?: string;
12
+ }>;
13
+ }
14
+ export declare function CircleButton({ iconType, size, color, variant, className, customIcon, }: CircleButtonProps): import("react").JSX.Element;
15
+ export default CircleButton;