@sincpro/mobile-ui 0.4.1 → 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.
- package/dist/Actions/Actions.Button.d.ts +151 -0
- package/dist/Actions/Actions.Button.js +217 -0
- package/dist/Actions/Actions.FAB.d.ts +10 -0
- package/dist/Actions/Actions.FAB.js +17 -0
- package/dist/Actions/Actions.FilterButton.d.ts +10 -0
- package/dist/Actions/Actions.FilterButton.js +28 -0
- package/dist/Actions/Actions.IconButton.d.ts +67 -0
- package/dist/Actions/Actions.IconButton.js +38 -0
- package/dist/Actions/index.d.ts +22 -0
- package/dist/Actions/index.js +17 -0
- package/dist/Dialog/BottomSheet/BottomSheet.Root.js +1 -0
- package/dist/Dialog/Dialog.Sheet.js +6 -4
- package/dist/Display/Display.CircleButton.d.ts +15 -0
- package/dist/Display/Display.CircleButton.js +39 -0
- package/dist/Display/Display.MenuButton.d.ts +51 -8
- package/dist/Display/Display.MenuButton.js +79 -13
- package/dist/Display/Display.MenuCard.d.ts +15 -0
- package/dist/Display/Display.MenuCard.js +24 -0
- package/dist/Display/Display.MenuGrid.d.ts +19 -0
- package/dist/Display/Display.MenuGrid.js +7 -0
- package/dist/Display/Display.SwipeableRow.js +2 -1
- package/dist/Display/Display.Tooltip.d.ts +1 -1
- package/dist/Display/Display.Tooltip.js +16 -5
- package/dist/Display/index.d.ts +9 -0
- package/dist/Display/index.js +6 -0
- package/dist/Feedback/Feedback.Empty.js +2 -2
- package/dist/Feedback/Feedback.Error.js +2 -2
- package/dist/Feedback/Feedback.Progress.js +2 -2
- package/dist/Feedback/Feedback.Skeleton.js +2 -2
- package/dist/Feedback/Feedback.Splash.js +1 -0
- package/dist/Form/Form.Button.d.ts +3 -151
- package/dist/Form/Form.Button.js +1 -283
- package/dist/Form/Form.FAB.d.ts +3 -10
- package/dist/Form/Form.FAB.js +1 -17
- package/dist/Form/Form.FilterButton.d.ts +3 -12
- package/dist/Form/Form.FilterButton.js +1 -34
- package/dist/Form/Form.IconButton.d.ts +3 -67
- package/dist/Form/Form.IconButton.js +1 -64
- package/dist/Navigation/Navigation.AppBar.d.ts +63 -4
- package/dist/Navigation/Navigation.AppBar.js +70 -18
- package/dist/Navigation/Navigation.BottomNav.js +2 -1
- package/dist/Navigation/Navigation.Header.js +3 -2
- package/dist/Navigation/Navigation.Menu.js +6 -3
- package/dist/Navigation/Navigation.MenuSection.d.ts +19 -0
- package/dist/Navigation/Navigation.MenuSection.js +25 -0
- package/dist/Navigation/Navigation.SegmentedControl.d.ts +15 -1
- package/dist/Navigation/Navigation.SegmentedControl.js +22 -4
- package/dist/Navigation/Navigation.TabIcon.js +1 -2
- package/dist/Navigation/Navigation.TabItem.js +2 -2
- package/dist/Navigation/Navigation.Tabs.d.ts +8 -3
- package/dist/Navigation/Navigation.Tabs.js +19 -6
- package/dist/Navigation/index.d.ts +8 -7
- package/dist/Navigation/index.js +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/layouts/BottomInset.d.ts +16 -0
- package/dist/layouts/BottomInset.js +17 -0
- package/dist/layouts/TabNavigatorLayout.js +2 -2
- package/dist/primitives/BaseButton.js +3 -3
- package/dist/theme/default.js +1 -1
- package/dist/views/FormViewV2.d.ts +99 -9
- package/dist/views/FormViewV2.js +79 -19
- package/dist/views/ListViewV2.d.ts +58 -5
- package/dist/views/ListViewV2.js +58 -11
- package/dist/widgets/CircleButton.d.ts +3 -19
- package/dist/widgets/CircleButton.js +1 -41
- package/dist/widgets/JSONViewer.js +7 -7
- package/dist/widgets/MenuCard.d.ts +3 -13
- package/dist/widgets/MenuCard.js +1 -8
- package/dist/widgets/MenuGrid.d.ts +5 -17
- package/dist/widgets/MenuGrid.js +1 -6
- package/dist/widgets/MenuSection.d.ts +3 -0
- package/dist/widgets/MenuSection.js +1 -0
- package/dist/widgets/PromoBanner.d.ts +38 -0
- package/dist/widgets/PromoBanner.js +61 -0
- package/dist/widgets/PromoModal.d.ts +41 -0
- package/dist/widgets/PromoModal.js +75 -0
- package/dist/widgets/QuickActions.d.ts +26 -0
- package/dist/widgets/QuickActions.js +41 -0
- package/dist/widgets/index.d.ts +11 -1
- package/dist/widgets/index.js +4 -0
- package/package.json +2 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { jsx as _jsx } from "nativewind/jsx-runtime";
|
|
2
|
+
import Icon from "../Display/Display.Icon";
|
|
3
|
+
import { useTheme } from "../theme";
|
|
4
|
+
import { cn } from "../theme/tw";
|
|
5
|
+
import { View } from "react-native";
|
|
6
|
+
import { tv } from "tailwind-variants";
|
|
7
|
+
const circleButtonVariants = tv({
|
|
8
|
+
base: "rounded-full items-center justify-center shadow-sm",
|
|
9
|
+
variants: {
|
|
10
|
+
size: {
|
|
11
|
+
sm: "w-12 h-12",
|
|
12
|
+
md: "w-15 h-15",
|
|
13
|
+
lg: "w-20 h-20",
|
|
14
|
+
},
|
|
15
|
+
variant: {
|
|
16
|
+
primary: "bg-primary",
|
|
17
|
+
secondary: "bg-secondary",
|
|
18
|
+
accent: "bg-accent",
|
|
19
|
+
success: "bg-success",
|
|
20
|
+
danger: "bg-danger",
|
|
21
|
+
warning: "bg-warning",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
defaultVariants: {
|
|
25
|
+
size: "md",
|
|
26
|
+
variant: "accent",
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
const SIZE_MAP = {
|
|
30
|
+
sm: { icon: 24 },
|
|
31
|
+
md: { icon: 30 },
|
|
32
|
+
lg: { icon: 40 },
|
|
33
|
+
};
|
|
34
|
+
export function CircleButton({ iconType = "ionicons", size = "md", color, variant = "accent", className, customIcon, }) {
|
|
35
|
+
const theme = useTheme();
|
|
36
|
+
const iconColor = color ?? theme.text.inverse;
|
|
37
|
+
return (_jsx(View, { className: cn(circleButtonVariants({ size, variant }), className), children: _jsx(Icon, { color: iconColor, customIcon: customIcon, size: SIZE_MAP[size].icon, type: iconType }) }));
|
|
38
|
+
}
|
|
39
|
+
export default CircleButton;
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
import { type SwipeRowAction } from "../Display/Display.SwipeableRow";
|
|
1
2
|
import { type VariantProps } from "../theme/tw";
|
|
2
3
|
import { ComponentType, ReactNode } from "react";
|
|
4
|
+
export type MenuButtonSwipeAction = SwipeRowAction;
|
|
5
|
+
/**
|
|
6
|
+
* Inline status/count badge on the right of the row.
|
|
7
|
+
* Presets: `"active"` (green pill), `"inactive"` (yellow pill), `"new"` (accent pill).
|
|
8
|
+
* Any string / number renders a danger count chip.
|
|
9
|
+
*/
|
|
10
|
+
export type MenuButtonBadge = "active" | "inactive" | "new" | string | number;
|
|
3
11
|
declare const menuButton: import("tailwind-variants").TVReturnType<{
|
|
4
12
|
variant: {
|
|
5
13
|
default: {
|
|
@@ -10,6 +18,10 @@ declare const menuButton: import("tailwind-variants").TVReturnType<{
|
|
|
10
18
|
iconContainer: string;
|
|
11
19
|
label: string;
|
|
12
20
|
};
|
|
21
|
+
success: {
|
|
22
|
+
iconContainer: string;
|
|
23
|
+
label: string;
|
|
24
|
+
};
|
|
13
25
|
};
|
|
14
26
|
showDivider: {
|
|
15
27
|
true: {
|
|
@@ -27,8 +39,6 @@ declare const menuButton: import("tailwind-variants").TVReturnType<{
|
|
|
27
39
|
content: string;
|
|
28
40
|
label: string;
|
|
29
41
|
rightContainer: string;
|
|
30
|
-
chevronContainer: string;
|
|
31
|
-
chevron: string;
|
|
32
42
|
}, undefined, {
|
|
33
43
|
variant: {
|
|
34
44
|
default: {
|
|
@@ -39,6 +49,10 @@ declare const menuButton: import("tailwind-variants").TVReturnType<{
|
|
|
39
49
|
iconContainer: string;
|
|
40
50
|
label: string;
|
|
41
51
|
};
|
|
52
|
+
success: {
|
|
53
|
+
iconContainer: string;
|
|
54
|
+
label: string;
|
|
55
|
+
};
|
|
42
56
|
};
|
|
43
57
|
showDivider: {
|
|
44
58
|
true: {
|
|
@@ -56,8 +70,6 @@ declare const menuButton: import("tailwind-variants").TVReturnType<{
|
|
|
56
70
|
content: string;
|
|
57
71
|
label: string;
|
|
58
72
|
rightContainer: string;
|
|
59
|
-
chevronContainer: string;
|
|
60
|
-
chevron: string;
|
|
61
73
|
}, import("tailwind-variants").TVReturnType<{
|
|
62
74
|
variant: {
|
|
63
75
|
default: {
|
|
@@ -68,6 +80,10 @@ declare const menuButton: import("tailwind-variants").TVReturnType<{
|
|
|
68
80
|
iconContainer: string;
|
|
69
81
|
label: string;
|
|
70
82
|
};
|
|
83
|
+
success: {
|
|
84
|
+
iconContainer: string;
|
|
85
|
+
label: string;
|
|
86
|
+
};
|
|
71
87
|
};
|
|
72
88
|
showDivider: {
|
|
73
89
|
true: {
|
|
@@ -85,10 +101,8 @@ declare const menuButton: import("tailwind-variants").TVReturnType<{
|
|
|
85
101
|
content: string;
|
|
86
102
|
label: string;
|
|
87
103
|
rightContainer: string;
|
|
88
|
-
chevronContainer: string;
|
|
89
|
-
chevron: string;
|
|
90
104
|
}, undefined, unknown, unknown, undefined>>;
|
|
91
|
-
interface MenuButtonProps extends VariantProps<typeof menuButton> {
|
|
105
|
+
export interface MenuButtonProps extends VariantProps<typeof menuButton> {
|
|
92
106
|
icon?: ComponentType<{
|
|
93
107
|
size?: number;
|
|
94
108
|
color?: string;
|
|
@@ -96,8 +110,37 @@ interface MenuButtonProps extends VariantProps<typeof menuButton> {
|
|
|
96
110
|
label: string;
|
|
97
111
|
description?: string;
|
|
98
112
|
onPress?: () => void;
|
|
113
|
+
/** Arbitrary right-side slot — takes precedence over all built-in right elements. */
|
|
99
114
|
rightComponent?: ReactNode;
|
|
100
115
|
className?: string;
|
|
116
|
+
/**
|
|
117
|
+
* Inline toggle switch on the right.
|
|
118
|
+
* The row's `onPress` is still fired when the row body is tapped.
|
|
119
|
+
* The switch itself calls `onToggle` independently.
|
|
120
|
+
*/
|
|
121
|
+
toggle?: {
|
|
122
|
+
value: boolean;
|
|
123
|
+
onToggle: (v: boolean) => void;
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Current-value label shown on the right before the chevron.
|
|
127
|
+
* Great for settings rows: "Siempre", "Nunca", "24 hs".
|
|
128
|
+
*/
|
|
129
|
+
value?: string;
|
|
130
|
+
/**
|
|
131
|
+
* Status / count badge on the right.
|
|
132
|
+
* Presets: `"active"` | `"inactive"` | `"new"`.
|
|
133
|
+
* Any string or number renders a plain danger count chip.
|
|
134
|
+
*/
|
|
135
|
+
badge?: MenuButtonBadge;
|
|
136
|
+
/** Replace right content with a spinner while an async action is running. */
|
|
137
|
+
loading?: boolean;
|
|
138
|
+
/**
|
|
139
|
+
* Swipe-left (right-side) or swipe-right (left-side) reveal actions.
|
|
140
|
+
* Delegates to `Display.SwipeableRow` — same `SwipeRowAction` shape.
|
|
141
|
+
*/
|
|
142
|
+
swipeActions?: MenuButtonSwipeAction[];
|
|
143
|
+
swipeLeftActions?: MenuButtonSwipeAction[];
|
|
101
144
|
}
|
|
102
|
-
declare function MenuButton({ icon:
|
|
145
|
+
declare function MenuButton({ icon: IconComp, label, description, onPress, rightComponent, showDivider, variant, disabled, className, toggle, value, badge, loading, swipeActions, swipeLeftActions, }: MenuButtonProps): import("react").JSX.Element;
|
|
103
146
|
export default MenuButton;
|
|
@@ -1,17 +1,60 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
-
import
|
|
2
|
+
import SwipeableRow from "../Display/Display.SwipeableRow";
|
|
3
|
+
import Spinner from "../Feedback/Feedback.Spinner";
|
|
4
|
+
import { useTheme } from "../theme";
|
|
3
5
|
import { tv } from "../theme/tw";
|
|
4
6
|
import { Typography } from "../Typography";
|
|
5
|
-
import { TouchableOpacity, View } from "react-native";
|
|
7
|
+
import { Switch, TouchableOpacity, View } from "react-native";
|
|
8
|
+
function BadgeChip({ badge }) {
|
|
9
|
+
const theme = useTheme();
|
|
10
|
+
if (badge === "active") {
|
|
11
|
+
return (_jsxs(View, { style: {
|
|
12
|
+
flexDirection: "row",
|
|
13
|
+
alignItems: "center",
|
|
14
|
+
gap: 4,
|
|
15
|
+
backgroundColor: theme.successLight,
|
|
16
|
+
paddingHorizontal: 8,
|
|
17
|
+
paddingVertical: 3,
|
|
18
|
+
borderRadius: 999,
|
|
19
|
+
}, children: [_jsx(View, { style: { width: 6, height: 6, borderRadius: 999, backgroundColor: theme.success } }), _jsx(Typography.Text, { semibold: true, style: { color: theme.success, fontSize: 11 }, variant: "caption", children: "Activo" })] }));
|
|
20
|
+
}
|
|
21
|
+
if (badge === "inactive") {
|
|
22
|
+
return (_jsxs(View, { style: {
|
|
23
|
+
flexDirection: "row",
|
|
24
|
+
alignItems: "center",
|
|
25
|
+
gap: 4,
|
|
26
|
+
backgroundColor: theme.warningLight,
|
|
27
|
+
paddingHorizontal: 8,
|
|
28
|
+
paddingVertical: 3,
|
|
29
|
+
borderRadius: 999,
|
|
30
|
+
}, children: [_jsx(View, { style: { width: 6, height: 6, borderRadius: 999, backgroundColor: theme.warning } }), _jsx(Typography.Text, { semibold: true, style: { color: theme.warning, fontSize: 11 }, variant: "caption", children: "Inactivo" })] }));
|
|
31
|
+
}
|
|
32
|
+
if (badge === "new") {
|
|
33
|
+
return (_jsx(View, { style: {
|
|
34
|
+
backgroundColor: theme.accent,
|
|
35
|
+
paddingHorizontal: 8,
|
|
36
|
+
paddingVertical: 3,
|
|
37
|
+
borderRadius: 999,
|
|
38
|
+
}, children: _jsx(Typography.Text, { semibold: true, style: { color: theme.text.onAccent, fontSize: 11 }, variant: "caption", children: "Nuevo" }) }));
|
|
39
|
+
}
|
|
40
|
+
return (_jsx(View, { style: {
|
|
41
|
+
backgroundColor: theme.danger,
|
|
42
|
+
minWidth: 20,
|
|
43
|
+
height: 20,
|
|
44
|
+
borderRadius: 999,
|
|
45
|
+
alignItems: "center",
|
|
46
|
+
justifyContent: "center",
|
|
47
|
+
paddingHorizontal: 6,
|
|
48
|
+
}, children: _jsx(Typography.Text, { style: { color: "#FFFFFF", fontSize: 11, lineHeight: 14 }, variant: "caption", children: badge }) }));
|
|
49
|
+
}
|
|
50
|
+
// ─── Tailwind slots ───────────────────────────────────────────────────────────
|
|
6
51
|
const menuButton = tv({
|
|
7
52
|
slots: {
|
|
8
53
|
container: "flex-row items-center py-3 px-4 bg-bg-card",
|
|
9
54
|
iconContainer: "mr-3 w-8 h-8 rounded-lg items-center justify-center",
|
|
10
55
|
content: "flex-1",
|
|
11
56
|
label: "",
|
|
12
|
-
rightContainer: "ml-2",
|
|
13
|
-
chevronContainer: "ml-2 w-5 h-5 items-center justify-center",
|
|
14
|
-
chevron: "text-xl",
|
|
57
|
+
rightContainer: "ml-2 flex-row items-center gap-2",
|
|
15
58
|
},
|
|
16
59
|
variants: {
|
|
17
60
|
variant: {
|
|
@@ -23,16 +66,16 @@ const menuButton = tv({
|
|
|
23
66
|
iconContainer: "bg-danger-light",
|
|
24
67
|
label: "text-danger",
|
|
25
68
|
},
|
|
69
|
+
success: {
|
|
70
|
+
iconContainer: "bg-success-light",
|
|
71
|
+
label: "text-success",
|
|
72
|
+
},
|
|
26
73
|
},
|
|
27
74
|
showDivider: {
|
|
28
|
-
true: {
|
|
29
|
-
container: "border-b border-border-default",
|
|
30
|
-
},
|
|
75
|
+
true: { container: "border-b border-border-default" },
|
|
31
76
|
},
|
|
32
77
|
disabled: {
|
|
33
|
-
true: {
|
|
34
|
-
container: "opacity-40",
|
|
35
|
-
},
|
|
78
|
+
true: { container: "opacity-40" },
|
|
36
79
|
},
|
|
37
80
|
},
|
|
38
81
|
defaultVariants: {
|
|
@@ -41,10 +84,33 @@ const menuButton = tv({
|
|
|
41
84
|
disabled: false,
|
|
42
85
|
},
|
|
43
86
|
});
|
|
44
|
-
|
|
87
|
+
// ─── Component ───────────────────────────────────────────────────────────────
|
|
88
|
+
function MenuButton({ icon: IconComp, label, description, onPress, rightComponent, showDivider = true, variant = "default", disabled = false, className, toggle, value, badge, loading = false, swipeActions, swipeLeftActions, }) {
|
|
89
|
+
const theme = useTheme();
|
|
45
90
|
const styles = menuButton({ variant, showDivider, disabled });
|
|
46
91
|
const isDanger = variant === "danger";
|
|
47
92
|
const isClickable = !!onPress && !disabled;
|
|
48
|
-
|
|
93
|
+
const iconColor = isDanger ? theme.danger : theme.text.secondary;
|
|
94
|
+
// Right-side priority: loading > explicit slot > toggle > badge/value/chevron
|
|
95
|
+
const rightSlot = (() => {
|
|
96
|
+
if (loading)
|
|
97
|
+
return _jsx(Spinner, { size: "small" });
|
|
98
|
+
if (rightComponent)
|
|
99
|
+
return rightComponent;
|
|
100
|
+
if (toggle) {
|
|
101
|
+
return (_jsx(Switch, { onValueChange: toggle.onToggle, thumbColor: theme.bg.card, trackColor: { false: theme.border.strong, true: theme.accent }, value: toggle.value }));
|
|
102
|
+
}
|
|
103
|
+
const hasBadge = badge != null;
|
|
104
|
+
const hasValue = !!value;
|
|
105
|
+
const hasChevron = isClickable && !hasBadge;
|
|
106
|
+
if (!hasBadge && !hasValue && !hasChevron)
|
|
107
|
+
return null;
|
|
108
|
+
return (_jsxs(View, { style: { flexDirection: "row", alignItems: "center", gap: 6 }, children: [hasBadge ? _jsx(BadgeChip, { badge: badge }) : null, hasValue ? (_jsx(Typography.Text, { style: { color: theme.text.secondary }, variant: "bodySmall", children: value })) : null, isClickable ? (_jsx(Typography.Text, { style: { color: theme.text.tertiary, fontSize: 20 }, children: "\u203A" })) : null] }));
|
|
109
|
+
})();
|
|
110
|
+
const row = (_jsxs(TouchableOpacity, { activeOpacity: 0.5, className: styles.container({ className }), disabled: disabled || (!onPress && !toggle), onPress: onPress, children: [IconComp ? (_jsx(View, { className: styles.iconContainer(), children: _jsx(IconComp, { color: iconColor, size: 20 }) })) : null, _jsxs(View, { className: styles.content(), children: [_jsx(Typography.Text, { className: styles.label(), variant: "body", children: label }), description ? (_jsx(Typography.Text, { className: "text-text-secondary", variant: "bodySmall", children: description })) : null] }), rightSlot ? _jsx(View, { className: styles.rightContainer(), children: rightSlot }) : null] }));
|
|
111
|
+
if (swipeActions?.length || swipeLeftActions?.length) {
|
|
112
|
+
return (_jsx(SwipeableRow, { leftActions: swipeLeftActions, rightActions: swipeActions, children: row }));
|
|
113
|
+
}
|
|
114
|
+
return row;
|
|
49
115
|
}
|
|
50
116
|
export default MenuButton;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { IconType } from "../utils/icon";
|
|
2
|
+
import { ComponentType } from "react";
|
|
3
|
+
export interface MenuCardProps {
|
|
4
|
+
title: string;
|
|
5
|
+
iconType?: IconType;
|
|
6
|
+
onPress?: () => void;
|
|
7
|
+
customIcon?: ComponentType<{
|
|
8
|
+
size?: number;
|
|
9
|
+
color?: string;
|
|
10
|
+
}>;
|
|
11
|
+
/** `"md"` = 2-column grid (default). `"sm"` = 3-column grid, smaller icon. */
|
|
12
|
+
size?: "sm" | "md";
|
|
13
|
+
}
|
|
14
|
+
export declare function MenuCard({ title, iconType, onPress, customIcon, size, }: MenuCardProps): import("react").JSX.Element;
|
|
15
|
+
export default MenuCard;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
+
import CircleButton from "../Display/Display.CircleButton";
|
|
3
|
+
import { useTheme } from "../theme";
|
|
4
|
+
import { Typography } from "../Typography";
|
|
5
|
+
import { TouchableOpacity, View } from "react-native";
|
|
6
|
+
export function MenuCard({ title, iconType = "ionicons", onPress, customIcon, size = "md", }) {
|
|
7
|
+
const theme = useTheme();
|
|
8
|
+
const isSmall = size === "sm";
|
|
9
|
+
return (_jsx(TouchableOpacity, { activeOpacity: 0.7, onPress: onPress, style: {
|
|
10
|
+
backgroundColor: theme.bg.card,
|
|
11
|
+
borderRadius: 16,
|
|
12
|
+
padding: isSmall ? 12 : 16,
|
|
13
|
+
margin: isSmall ? 4 : 8,
|
|
14
|
+
width: isSmall ? "30%" : "45%",
|
|
15
|
+
borderWidth: 1,
|
|
16
|
+
borderColor: theme.border.default,
|
|
17
|
+
...theme.shadow.sm,
|
|
18
|
+
}, children: _jsxs(View, { style: { alignItems: "center", justifyContent: "center" }, children: [_jsx(CircleButton, { customIcon: customIcon, iconType: iconType, size: isSmall ? "sm" : "md" }), _jsx(Typography.Text, { numberOfLines: 2, style: {
|
|
19
|
+
color: theme.text.primary,
|
|
20
|
+
marginTop: isSmall ? 8 : 12,
|
|
21
|
+
textAlign: "center",
|
|
22
|
+
}, variant: isSmall ? "caption" : "label", children: title })] }) }));
|
|
23
|
+
}
|
|
24
|
+
export default MenuCard;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { IconType } from "../utils/icon";
|
|
2
|
+
import { ComponentType } from "react";
|
|
3
|
+
export interface MenuGridItem {
|
|
4
|
+
id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
iconType?: IconType;
|
|
7
|
+
onPress?: () => void;
|
|
8
|
+
customIcon?: ComponentType<{
|
|
9
|
+
size?: number;
|
|
10
|
+
color?: string;
|
|
11
|
+
}>;
|
|
12
|
+
}
|
|
13
|
+
export interface MenuGridProps {
|
|
14
|
+
items: MenuGridItem[];
|
|
15
|
+
/** `"md"` = 2-column (default). `"sm"` = 3-column, smaller cards. */
|
|
16
|
+
size?: "sm" | "md";
|
|
17
|
+
}
|
|
18
|
+
export declare function MenuGrid({ items, size }: MenuGridProps): import("react").JSX.Element;
|
|
19
|
+
export default MenuGrid;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx } from "nativewind/jsx-runtime";
|
|
2
|
+
import MenuCard from "../Display/Display.MenuCard";
|
|
3
|
+
import { View } from "react-native";
|
|
4
|
+
export function MenuGrid({ items, size = "md" }) {
|
|
5
|
+
return (_jsx(View, { className: "flex-row flex-wrap justify-start p-2 bg-bg-page", children: items.map((item) => (_jsx(MenuCard, { customIcon: item.customIcon, iconType: item.iconType, onPress: item.onPress, size: size, title: item.title }, item.id))) }));
|
|
6
|
+
}
|
|
7
|
+
export default MenuGrid;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
2
|
import Icon from "../Display/Display.Icon";
|
|
3
|
-
import {
|
|
3
|
+
import { useTheme } from "../theme";
|
|
4
4
|
import { Typography } from "../Typography";
|
|
5
5
|
import { useRef } from "react";
|
|
6
6
|
import { TouchableOpacity, View } from "react-native";
|
|
7
7
|
import { Swipeable } from "react-native-gesture-handler";
|
|
8
8
|
function ActionButtons({ actions, onDone, }) {
|
|
9
|
+
const theme = useTheme();
|
|
9
10
|
return (_jsx(View, { style: { flexDirection: "row" }, children: actions.map((action, index) => (_jsxs(TouchableOpacity, { accessibilityLabel: action.label ?? "Acción", accessibilityRole: "button", activeOpacity: 0.8, onPress: () => {
|
|
10
11
|
onDone();
|
|
11
12
|
action.onPress();
|
|
@@ -1,18 +1,29 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
2
|
import Pressable from "../primitives/Pressable";
|
|
3
|
-
import {
|
|
3
|
+
import { useTheme } from "../theme";
|
|
4
4
|
import { Typography } from "../Typography";
|
|
5
5
|
import { useState } from "react";
|
|
6
6
|
import { View } from "react-native";
|
|
7
|
+
function resolvePosition(placement) {
|
|
8
|
+
switch (placement) {
|
|
9
|
+
case "bottom":
|
|
10
|
+
return { top: "100%", left: 0, marginVertical: 6 };
|
|
11
|
+
case "left":
|
|
12
|
+
return { right: "100%", top: 0, marginHorizontal: 6 };
|
|
13
|
+
case "right":
|
|
14
|
+
return { left: "100%", top: 0, marginHorizontal: 6 };
|
|
15
|
+
case "top":
|
|
16
|
+
default:
|
|
17
|
+
return { bottom: "100%", left: 0, marginVertical: 6 };
|
|
18
|
+
}
|
|
19
|
+
}
|
|
7
20
|
function Tooltip({ content, children, placement = "top", width = 200, testID, }) {
|
|
21
|
+
const theme = useTheme();
|
|
8
22
|
const [visible, setVisible] = useState(false);
|
|
9
|
-
const isTop = placement === "top";
|
|
10
23
|
return (_jsxs(View, { style: { position: "relative", alignSelf: "flex-start" }, testID: testID, children: [_jsx(Pressable, { accessibilityHint: content, accessibilityRole: "button", onPress: () => setVisible((v) => !v), children: children }), visible ? (_jsx(View, { style: {
|
|
11
24
|
position: "absolute",
|
|
12
|
-
|
|
13
|
-
left: 0,
|
|
25
|
+
...resolvePosition(placement),
|
|
14
26
|
width,
|
|
15
|
-
marginVertical: 6,
|
|
16
27
|
paddingHorizontal: 10,
|
|
17
28
|
paddingVertical: 8,
|
|
18
29
|
borderRadius: 8,
|
package/dist/Display/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import AvatarGroup from "../Display/Display.AvatarGroup";
|
|
|
2
2
|
import Badge, { type BadgeProps, BadgeVariants } from "../Display/Display.Badge";
|
|
3
3
|
import Carousel from "../Display/Display.Carousel";
|
|
4
4
|
import Chip from "../Display/Display.Chip";
|
|
5
|
+
import { CircleButton } from "../Display/Display.CircleButton";
|
|
5
6
|
import CopyableText from "../Display/Display.CopyableText";
|
|
6
7
|
import CountRecords from "../Display/Display.CountRecords";
|
|
7
8
|
import DataTable from "../Display/Display.DataTable";
|
|
@@ -15,6 +16,8 @@ import ListItem from "../Display/Display.ListItem";
|
|
|
15
16
|
import MediaCard from "../Display/Display.MediaCard";
|
|
16
17
|
import MediaEmbed from "../Display/Display.MediaEmbed";
|
|
17
18
|
import MenuButton from "../Display/Display.MenuButton";
|
|
19
|
+
import { MenuCard } from "../Display/Display.MenuCard";
|
|
20
|
+
import { MenuGrid } from "../Display/Display.MenuGrid";
|
|
18
21
|
import Monetary from "../Display/Display.Monetary";
|
|
19
22
|
import Pattern from "../Display/Display.Pattern";
|
|
20
23
|
import PriceTag from "../Display/Display.PriceTag";
|
|
@@ -84,9 +87,15 @@ export declare const Display: {
|
|
|
84
87
|
Icon: import("react").FC<import("../Display/Display.Icon").IconProps>;
|
|
85
88
|
CountRecords: typeof CountRecords;
|
|
86
89
|
Logo: import("react").FC<import("../Display/Display.Logo").LogoProps>;
|
|
90
|
+
CircleButton: typeof CircleButton;
|
|
87
91
|
MenuButton: typeof MenuButton;
|
|
92
|
+
MenuCard: typeof MenuCard;
|
|
93
|
+
MenuGrid: typeof MenuGrid;
|
|
88
94
|
Monetary: typeof Monetary;
|
|
89
95
|
Pattern: typeof Pattern;
|
|
90
96
|
};
|
|
91
97
|
export { type BadgeProps, BadgeVariants };
|
|
98
|
+
export type { CircleButtonProps } from "../Display/Display.CircleButton";
|
|
99
|
+
export type { MenuCardProps } from "../Display/Display.MenuCard";
|
|
100
|
+
export type { MenuGridItem } from "../Display/Display.MenuGrid";
|
|
92
101
|
export default Display;
|
package/dist/Display/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import Badge, { BadgeVariants, } from "../Display/Display.Badge";
|
|
|
5
5
|
import Card from "../Display/Display.Card";
|
|
6
6
|
import Carousel from "../Display/Display.Carousel";
|
|
7
7
|
import Chip from "../Display/Display.Chip";
|
|
8
|
+
import { CircleButton } from "../Display/Display.CircleButton";
|
|
8
9
|
import CopyableText from "../Display/Display.CopyableText";
|
|
9
10
|
import CountRecords from "../Display/Display.CountRecords";
|
|
10
11
|
import DataTable from "../Display/Display.DataTable";
|
|
@@ -20,6 +21,8 @@ import Logo from "../Display/Display.Logo";
|
|
|
20
21
|
import MediaCard from "../Display/Display.MediaCard";
|
|
21
22
|
import MediaEmbed from "../Display/Display.MediaEmbed";
|
|
22
23
|
import MenuButton from "../Display/Display.MenuButton";
|
|
24
|
+
import { MenuCard } from "../Display/Display.MenuCard";
|
|
25
|
+
import { MenuGrid } from "../Display/Display.MenuGrid";
|
|
23
26
|
import Monetary from "../Display/Display.Monetary";
|
|
24
27
|
import Pattern from "../Display/Display.Pattern";
|
|
25
28
|
import PriceTag from "../Display/Display.PriceTag";
|
|
@@ -75,7 +78,10 @@ export const Display = {
|
|
|
75
78
|
Icon,
|
|
76
79
|
CountRecords,
|
|
77
80
|
Logo,
|
|
81
|
+
CircleButton,
|
|
78
82
|
MenuButton,
|
|
83
|
+
MenuCard,
|
|
84
|
+
MenuGrid,
|
|
79
85
|
Monetary,
|
|
80
86
|
Pattern,
|
|
81
87
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
-
import
|
|
2
|
+
import Icon from "../Display/Display.Icon";
|
|
3
3
|
import { cn } from "../theme/tw";
|
|
4
4
|
import { Typography } from "../Typography";
|
|
5
5
|
import { View } from "react-native";
|
|
6
6
|
function Empty({ handleGoHome, className }) {
|
|
7
|
-
return (_jsxs(View, { className: cn("flex-1 items-center justify-center px-4", className), children: [_jsx(
|
|
7
|
+
return (_jsxs(View, { className: cn("flex-1 items-center justify-center px-4", className), children: [_jsx(Icon, { name: "sad-cry", size: 80, type: "fontawesome5" }), _jsx(Typography.Text, { className: "pt-4 text-text-primary", semibold: true, variant: "h3", children: "\u00A1Oops!" }), _jsx(Typography.Text, { className: "pt-2 text-center text-base leading-5.5 text-text-secondary", variant: "h5", children: "No se encontraron registros disponibles." })] }));
|
|
8
8
|
}
|
|
9
9
|
export default Empty;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
-
import
|
|
2
|
+
import Icon from "../Display/Display.Icon";
|
|
3
3
|
import Button from "../Form/Form.Button";
|
|
4
4
|
import { cn } from "../theme/tw";
|
|
5
5
|
import { Typography } from "../Typography";
|
|
6
6
|
import { View } from "react-native";
|
|
7
7
|
function Error({ message, onRetry, onBack, onHome, className }) {
|
|
8
|
-
return (_jsxs(View, { className: cn("flex-1 items-center justify-center px-4", className), children: [_jsx(
|
|
8
|
+
return (_jsxs(View, { className: cn("flex-1 items-center justify-center px-4", className), children: [_jsx(Icon, { color: "#ef4444", name: "exclamation-circle", size: 80, type: "fontawesome5" }), _jsx(Typography.Text, { className: "pt-4 text-text-primary", semibold: true, variant: "h3", children: "\u00A1Error!" }), _jsx(Typography.Text, { className: "pt-2 text-center text-base leading-5.5 text-text-secondary", variant: "h5", children: message || "Ocurrió un error al cargar la información" }), _jsxs(View, { className: "mt-8 w-full gap-3", children: [onRetry && _jsx(Button, { className: "w-full", onPress: onRetry, title: "Reintentar" }), onBack && (_jsx(Button, { className: "w-full", onPress: onBack, title: "Volver", variant: "secondary" })), onHome && (_jsx(Button, { className: "w-full", onPress: onHome, title: "Ir al inicio", variant: "outline" }))] })] }));
|
|
9
9
|
}
|
|
10
10
|
export default Error;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx } from "nativewind/jsx-runtime";
|
|
2
2
|
import { cn } from "../theme/tw";
|
|
3
3
|
import { motion } from "../tokens/motion";
|
|
4
|
-
import { useEffect,
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
5
|
import { Animated, Easing, View } from "react-native";
|
|
6
6
|
function clamp(n) {
|
|
7
7
|
return Math.max(0, Math.min(1, n));
|
|
8
8
|
}
|
|
9
9
|
function Progress({ value = 0, indeterminate = false, height = 6, className, testID, }) {
|
|
10
|
-
const translate =
|
|
10
|
+
const [translate] = useState(() => new Animated.Value(0));
|
|
11
11
|
useEffect(() => {
|
|
12
12
|
if (!indeterminate)
|
|
13
13
|
return;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx } from "nativewind/jsx-runtime";
|
|
2
2
|
import { cn } from "../theme/tw";
|
|
3
3
|
import { motion } from "../tokens/motion";
|
|
4
|
-
import { useEffect,
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
5
|
import { Animated, Easing } from "react-native";
|
|
6
6
|
function Skeleton({ width = "100%", height = 16, radius = 8, circle = false, className, style, }) {
|
|
7
|
-
const opacity =
|
|
7
|
+
const [opacity] = useState(() => new Animated.Value(0.5));
|
|
8
8
|
useEffect(() => {
|
|
9
9
|
const pulse = Animated.loop(Animated.sequence([
|
|
10
10
|
Animated.timing(opacity, {
|