@sincpro/mobile-ui 0.2.1 → 0.3.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/README.md +75 -20
- package/dist/Dialog/BottomSheet/BottomSheet.Root.d.ts +11 -7
- package/dist/Dialog/BottomSheet/BottomSheet.Root.js +4 -0
- package/dist/Dialog/Confirmation.context.d.ts +1 -1
- package/dist/Dialog/Dialog.ActionSheet.d.ts +17 -0
- package/dist/Dialog/Dialog.ActionSheet.js +16 -0
- package/dist/Dialog/Dialog.EditValue.d.ts +1 -1
- package/dist/Dialog/Dialog.Sheet.d.ts +26 -0
- package/dist/Dialog/Dialog.Sheet.js +55 -0
- package/dist/Dialog/index.d.ts +9 -7
- package/dist/Dialog/index.js +2 -0
- package/dist/Display/Display.Accordion.d.ts +18 -0
- package/dist/Display/Display.Accordion.js +22 -0
- package/dist/Display/Display.AvatarGroup.d.ts +12 -0
- package/dist/Display/Display.AvatarGroup.js +23 -0
- package/dist/Display/Display.Badge.d.ts +1 -1
- package/dist/Display/Display.Card.d.ts +46 -0
- package/dist/Display/Display.Card.js +36 -0
- package/dist/Display/Display.Carousel.d.ts +13 -0
- package/dist/Display/Display.Carousel.js +19 -0
- package/dist/Display/Display.Chip.d.ts +105 -0
- package/dist/Display/Display.Chip.js +45 -0
- package/dist/Display/Display.CopyableText.d.ts +1 -1
- package/dist/Display/Display.CountRecords.d.ts +1 -1
- package/dist/Display/Display.DataTable.d.ts +19 -0
- package/dist/Display/Display.DataTable.js +22 -0
- package/dist/Display/Display.Date.d.ts +15 -2
- package/dist/Display/Display.Date.js +34 -4
- package/dist/Display/Display.Divider.d.ts +1 -1
- package/dist/Display/Display.IconBadge.d.ts +13 -0
- package/dist/Display/Display.IconBadge.js +30 -0
- package/dist/Display/Display.Image.d.ts +15 -0
- package/dist/Display/Display.Image.js +17 -0
- package/dist/Display/Display.KeyValue.d.ts +10 -0
- package/dist/Display/Display.KeyValue.js +9 -0
- package/dist/Display/Display.ListItem.d.ts +13 -0
- package/dist/Display/Display.ListItem.js +14 -0
- package/dist/Display/Display.Logo.js +3 -1
- package/dist/Display/Display.MediaCard.d.ts +17 -0
- package/dist/Display/Display.MediaCard.js +12 -0
- package/dist/Display/Display.MediaEmbed.d.ts +19 -0
- package/dist/Display/Display.MediaEmbed.js +39 -0
- package/dist/Display/Display.MenuButton.d.ts +1 -1
- package/dist/Display/Display.Monetary.d.ts +1 -1
- package/dist/Display/Display.PriceTag.d.ts +10 -0
- package/dist/Display/Display.PriceTag.js +23 -0
- package/dist/Display/Display.ProductCard.d.ts +17 -0
- package/dist/Display/Display.ProductCard.js +13 -0
- package/dist/Display/Display.Rating.d.ts +11 -0
- package/dist/Display/Display.Rating.js +16 -0
- package/dist/Display/Display.SearchHistory.d.ts +12 -0
- package/dist/Display/Display.SearchHistory.js +13 -0
- package/dist/Display/Display.SectionHeader.d.ts +13 -0
- package/dist/Display/Display.SectionHeader.js +9 -0
- package/dist/Display/Display.Stat.d.ts +10 -0
- package/dist/Display/Display.Stat.js +9 -0
- package/dist/Display/Display.StatCard.d.ts +14 -0
- package/dist/Display/Display.StatCard.js +13 -0
- package/dist/Display/Display.StatusDot.d.ts +11 -0
- package/dist/Display/Display.StatusDot.js +28 -0
- package/dist/Display/Display.Story.d.ts +15 -0
- package/dist/Display/Display.Story.js +43 -0
- package/dist/Display/Display.StoryTray.d.ts +26 -0
- package/dist/Display/Display.StoryTray.js +43 -0
- package/dist/Display/Display.StoryViewer.d.ts +26 -0
- package/dist/Display/Display.StoryViewer.js +79 -0
- package/dist/Display/Display.SwipeableRow.d.ts +15 -0
- package/dist/Display/Display.SwipeableRow.js +28 -0
- package/dist/Display/Display.Tag.d.ts +11 -0
- package/dist/Display/Display.Tag.js +9 -0
- package/dist/Display/Display.Timeline.d.ts +13 -0
- package/dist/Display/Display.Timeline.js +19 -0
- package/dist/Display/Display.Tooltip.d.ts +10 -0
- package/dist/Display/Display.Tooltip.js +24 -0
- package/dist/Display/index.d.ts +66 -0
- package/dist/Display/index.js +54 -0
- package/dist/Feedback/ErrorBoundary.d.ts +1 -1
- package/dist/Feedback/Feedback.Banner.d.ts +82 -0
- package/dist/Feedback/Feedback.Banner.js +35 -0
- package/dist/Feedback/Feedback.DomainSplashScreen.d.ts +2 -1
- package/dist/Feedback/Feedback.DomainSplashScreen.js +1 -1
- package/dist/Feedback/Feedback.Empty.d.ts +1 -1
- package/dist/Feedback/Feedback.EmptyState.d.ts +15 -0
- package/dist/Feedback/Feedback.EmptyState.js +11 -0
- package/dist/Feedback/Feedback.Error.d.ts +1 -1
- package/dist/Feedback/Feedback.Loading.d.ts +2 -1
- package/dist/Feedback/Feedback.PermissionCard.d.ts +15 -0
- package/dist/Feedback/Feedback.PermissionCard.js +11 -0
- package/dist/Feedback/Feedback.Progress.d.ts +9 -0
- package/dist/Feedback/Feedback.Progress.js +35 -0
- package/dist/Feedback/Feedback.ProgressCircle.d.ts +12 -0
- package/dist/Feedback/Feedback.ProgressCircle.js +15 -0
- package/dist/Feedback/Feedback.Skeleton.d.ts +11 -0
- package/dist/Feedback/Feedback.Skeleton.js +29 -0
- package/dist/Feedback/Feedback.Splash.d.ts +1 -1
- package/dist/Feedback/Toast.context.d.ts +35 -0
- package/dist/Feedback/Toast.context.js +119 -0
- package/dist/Feedback/index.d.ts +15 -0
- package/dist/Feedback/index.js +15 -0
- package/dist/Form/Form.Button.d.ts +6 -0
- package/dist/Form/Form.Button.js +12 -1
- package/dist/Form/Form.Checkbox.d.ts +1 -1
- package/dist/Form/Form.ControlledCheckbox.d.ts +1 -1
- package/dist/Form/Form.ControlledInput.d.ts +1 -1
- package/dist/Form/Form.ControlledMonetaryInput.d.ts +1 -1
- package/dist/Form/Form.ControlledRadioButton.d.ts +1 -1
- package/dist/Form/Form.DatePicker.d.ts +20 -0
- package/dist/Form/Form.DatePicker.js +38 -0
- package/dist/Form/Form.Dropdown.d.ts +1 -1
- package/dist/Form/Form.FAB.d.ts +10 -0
- package/dist/Form/Form.FAB.js +17 -0
- package/dist/Form/Form.FilterButton.d.ts +1 -1
- package/dist/Form/Form.FractionalQuantityInput.d.ts +1 -1
- package/dist/Form/Form.IconButton.d.ts +1 -1
- package/dist/Form/Form.Input.d.ts +2 -1
- package/dist/Form/Form.MonetaryInput.d.ts +1 -1
- package/dist/Form/Form.PinInput.d.ts +12 -0
- package/dist/Form/Form.PinInput.js +23 -0
- package/dist/Form/Form.QuantitySelector.d.ts +2 -1
- package/dist/Form/Form.QuantitySelector.js +1 -1
- package/dist/Form/Form.RadioButton.d.ts +1 -1
- package/dist/Form/Form.SearchBar.d.ts +6 -1
- package/dist/Form/Form.SearchBar.js +4 -0
- package/dist/Form/Form.Select.d.ts +17 -0
- package/dist/Form/Form.Select.js +26 -0
- package/dist/Form/Form.Slider.d.ts +20 -0
- package/dist/Form/Form.Slider.js +16 -0
- package/dist/Form/Form.Switch.d.ts +10 -0
- package/dist/Form/Form.Switch.js +9 -0
- package/dist/Form/index.d.ts +12 -0
- package/dist/Form/index.js +12 -0
- package/dist/Navigation/Navigation.AppBar.d.ts +41 -0
- package/dist/Navigation/Navigation.AppBar.js +33 -0
- package/dist/Navigation/Navigation.BottomNav.d.ts +29 -0
- package/dist/Navigation/Navigation.BottomNav.js +35 -0
- package/dist/Navigation/Navigation.CollapsingHeader.d.ts +34 -0
- package/dist/Navigation/Navigation.CollapsingHeader.js +47 -0
- package/dist/Navigation/Navigation.FloatingBar.d.ts +15 -0
- package/dist/Navigation/Navigation.FloatingBar.js +21 -0
- package/dist/Navigation/Navigation.Header.d.ts +6 -2
- package/dist/Navigation/Navigation.Header.js +4 -0
- package/dist/Navigation/Navigation.HeaderToolbar.d.ts +1 -1
- package/dist/Navigation/Navigation.Menu.d.ts +21 -0
- package/dist/Navigation/Navigation.Menu.js +42 -0
- package/dist/Navigation/Navigation.RowItem.d.ts +1 -1
- package/dist/Navigation/Navigation.SearchBar.d.ts +18 -0
- package/dist/Navigation/Navigation.SearchBar.js +22 -0
- package/dist/Navigation/Navigation.SegmentedControl.d.ts +14 -0
- package/dist/Navigation/Navigation.SegmentedControl.js +13 -0
- package/dist/Navigation/Navigation.Steps.d.ts +8 -0
- package/dist/Navigation/Navigation.Steps.js +17 -0
- package/dist/Navigation/Navigation.TabIcon.d.ts +1 -1
- package/dist/Navigation/Navigation.Tabs.d.ts +28 -0
- package/dist/Navigation/Navigation.Tabs.js +45 -0
- package/dist/Navigation/index.d.ts +32 -1
- package/dist/Navigation/index.js +18 -0
- package/dist/Typography/Typography.Text.d.ts +2 -1
- package/dist/branding.d.ts +6 -0
- package/dist/branding.js +7 -0
- package/dist/icons/ArrowDownIcon.d.ts +2 -1
- package/dist/icons/ArrowUpIcon.d.ts +2 -1
- package/dist/icons/CreditIcon.d.ts +1 -1
- package/dist/icons/OdooIcon.d.ts +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/layouts/AuthContainer.d.ts +1 -1
- package/dist/layouts/Container.d.ts +1 -0
- package/dist/layouts/Container.js +2 -3
- package/dist/layouts/GradientContainer.d.ts +1 -1
- package/dist/layouts/PlainLayout.d.ts +1 -1
- package/dist/layouts/ScrollContainer.d.ts +2 -2
- package/dist/layouts/ScrollContainer.js +1 -1
- package/dist/layouts/TabNavigatorLayout.d.ts +2 -2
- package/dist/layouts/TabNavigatorLayout.js +4 -0
- package/dist/primitives/AspectRatio.d.ts +10 -0
- package/dist/primitives/AspectRatio.js +8 -0
- package/dist/primitives/Box.d.ts +1 -1
- package/dist/primitives/Pressable.d.ts +10 -0
- package/dist/primitives/Pressable.js +9 -0
- package/dist/primitives/Row.d.ts +1 -1
- package/dist/primitives/Spacer.d.ts +8 -0
- package/dist/primitives/Spacer.js +9 -0
- package/dist/primitives/Stack.d.ts +1 -1
- package/dist/primitives/index.d.ts +3 -0
- package/dist/primitives/index.js +3 -0
- package/dist/theme/active.d.ts +2 -0
- package/dist/theme/active.js +13 -0
- package/dist/theme/components/ThemedActivityIndicator.d.ts +1 -1
- package/dist/theme/components/index.d.ts +1 -1
- package/dist/theme/components/index.js +1 -1
- package/dist/theme/dark.d.ts +7 -0
- package/dist/theme/dark.js +84 -0
- package/dist/theme/define.d.ts +5 -5
- package/dist/theme/define.js +5 -5
- package/dist/theme/index.d.ts +3 -1
- package/dist/theme/index.js +3 -1
- package/dist/theme/theme.d.ts +1 -1
- package/dist/theme/theme.js +1 -1
- package/dist/theme/types.d.ts +14 -14
- package/dist/theme/types.js +2 -2
- package/dist/theme/useTheme.d.ts +3 -1
- package/dist/theme/useTheme.js +6 -1
- package/dist/tokens/index.d.ts +2 -0
- package/dist/tokens/index.js +2 -0
- package/dist/tokens/motion.d.ts +71 -0
- package/dist/tokens/motion.js +25 -0
- package/dist/utils/date.d.ts +33 -33
- package/dist/utils/date.js +39 -39
- package/dist/views/AuthFormView.d.ts +1 -1
- package/dist/views/FormViewV2.context.d.ts +1 -1
- package/dist/views/FormViewV2.d.ts +10 -10
- package/dist/views/ListViewV2.context.d.ts +1 -1
- package/dist/views/ListViewV2.d.ts +20 -20
- package/dist/views/Wizard/Wizard.context.d.ts +1 -1
- package/dist/widgets/CircleButton.d.ts +6 -2
- package/dist/widgets/CircleButton.js +4 -0
- package/dist/widgets/GeoPermissionCard.d.ts +1 -1
- package/dist/widgets/HomeHeader.d.ts +4 -0
- package/dist/widgets/HomeHeader.js +4 -0
- package/dist/widgets/JSONViewer.d.ts +2 -1
- package/dist/widgets/JSONViewer.js +6 -6
- package/dist/widgets/MenuCard.d.ts +1 -1
- package/dist/widgets/ScreenHeader.d.ts +5 -1
- package/dist/widgets/ScreenHeader.js +4 -0
- package/dist/widgets/TimeZoneSelector.d.ts +1 -1
- package/dist/widgets/TimeZoneSelectorModal.d.ts +1 -1
- package/package.json +38 -25
- package/tailwind.preset.js +14 -0
- package/dist/notifications/index.d.ts +0 -1
- package/dist/notifications/index.js +0 -1
- package/dist/providers/index.d.ts +0 -1
- package/dist/providers/index.js +0 -2
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { type VariantProps } from "../theme/tw";
|
|
2
|
+
declare const chip: import("tailwind-variants").TVReturnType<{
|
|
3
|
+
tone: {
|
|
4
|
+
neutral: {
|
|
5
|
+
root: string;
|
|
6
|
+
label: string;
|
|
7
|
+
};
|
|
8
|
+
primary: {
|
|
9
|
+
root: string;
|
|
10
|
+
label: string;
|
|
11
|
+
};
|
|
12
|
+
success: {
|
|
13
|
+
root: string;
|
|
14
|
+
label: string;
|
|
15
|
+
};
|
|
16
|
+
warning: {
|
|
17
|
+
root: string;
|
|
18
|
+
label: string;
|
|
19
|
+
};
|
|
20
|
+
danger: {
|
|
21
|
+
root: string;
|
|
22
|
+
label: string;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
selected: {
|
|
26
|
+
true: {
|
|
27
|
+
root: string;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
}, {
|
|
31
|
+
root: string;
|
|
32
|
+
label: string;
|
|
33
|
+
}, undefined, {
|
|
34
|
+
tone: {
|
|
35
|
+
neutral: {
|
|
36
|
+
root: string;
|
|
37
|
+
label: string;
|
|
38
|
+
};
|
|
39
|
+
primary: {
|
|
40
|
+
root: string;
|
|
41
|
+
label: string;
|
|
42
|
+
};
|
|
43
|
+
success: {
|
|
44
|
+
root: string;
|
|
45
|
+
label: string;
|
|
46
|
+
};
|
|
47
|
+
warning: {
|
|
48
|
+
root: string;
|
|
49
|
+
label: string;
|
|
50
|
+
};
|
|
51
|
+
danger: {
|
|
52
|
+
root: string;
|
|
53
|
+
label: string;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
selected: {
|
|
57
|
+
true: {
|
|
58
|
+
root: string;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
}, {
|
|
62
|
+
root: string;
|
|
63
|
+
label: string;
|
|
64
|
+
}, import("tailwind-variants").TVReturnType<{
|
|
65
|
+
tone: {
|
|
66
|
+
neutral: {
|
|
67
|
+
root: string;
|
|
68
|
+
label: string;
|
|
69
|
+
};
|
|
70
|
+
primary: {
|
|
71
|
+
root: string;
|
|
72
|
+
label: string;
|
|
73
|
+
};
|
|
74
|
+
success: {
|
|
75
|
+
root: string;
|
|
76
|
+
label: string;
|
|
77
|
+
};
|
|
78
|
+
warning: {
|
|
79
|
+
root: string;
|
|
80
|
+
label: string;
|
|
81
|
+
};
|
|
82
|
+
danger: {
|
|
83
|
+
root: string;
|
|
84
|
+
label: string;
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
selected: {
|
|
88
|
+
true: {
|
|
89
|
+
root: string;
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
}, {
|
|
93
|
+
root: string;
|
|
94
|
+
label: string;
|
|
95
|
+
}, undefined, unknown, unknown, undefined>>;
|
|
96
|
+
export interface ChipProps extends VariantProps<typeof chip> {
|
|
97
|
+
label: string;
|
|
98
|
+
onPress?: () => void;
|
|
99
|
+
onRemove?: () => void;
|
|
100
|
+
className?: string;
|
|
101
|
+
testID?: string;
|
|
102
|
+
}
|
|
103
|
+
declare function Chip({ label, tone, selected, onPress, onRemove, className, testID, }: ChipProps): import("react").JSX.Element;
|
|
104
|
+
export default Chip;
|
|
105
|
+
export { Chip };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, 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 { tv } from "../theme/tw";
|
|
6
|
+
import { Text, View } from "react-native";
|
|
7
|
+
const chip = tv({
|
|
8
|
+
slots: {
|
|
9
|
+
root: "flex-row items-center self-start rounded-full px-3 py-1.5 gap-1",
|
|
10
|
+
label: "text-xs font-medium",
|
|
11
|
+
},
|
|
12
|
+
variants: {
|
|
13
|
+
tone: {
|
|
14
|
+
neutral: { root: "bg-bg-muted", label: "text-text-secondary" },
|
|
15
|
+
primary: { root: "bg-bg-accent", label: "text-text-accent" },
|
|
16
|
+
success: { root: "bg-success-light", label: "text-success" },
|
|
17
|
+
warning: { root: "bg-warning-light", label: "text-warning" },
|
|
18
|
+
danger: { root: "bg-danger-light", label: "text-danger" },
|
|
19
|
+
},
|
|
20
|
+
selected: {
|
|
21
|
+
true: { root: "border border-primary" },
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
defaultVariants: {
|
|
25
|
+
tone: "neutral",
|
|
26
|
+
selected: false,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
const removeIconColor = {
|
|
30
|
+
neutral: theme.text.secondary,
|
|
31
|
+
primary: theme.text.accent,
|
|
32
|
+
success: theme.success,
|
|
33
|
+
warning: theme.warning,
|
|
34
|
+
danger: theme.danger,
|
|
35
|
+
};
|
|
36
|
+
function Chip({ label, tone = "neutral", selected = false, onPress, onRemove, className, testID, }) {
|
|
37
|
+
const styles = chip({ tone, selected });
|
|
38
|
+
const content = (_jsxs(_Fragment, { children: [_jsx(Text, { className: styles.label(), numberOfLines: 1, children: label }), onRemove ? (_jsx(Pressable, { accessibilityLabel: `Quitar ${label}`, hitSlop: 8, onPress: onRemove, children: _jsx(Icon, { color: removeIconColor[tone ?? "neutral"], name: "close", size: 14 }) })) : null] }));
|
|
39
|
+
if (onPress) {
|
|
40
|
+
return (_jsx(Pressable, { accessibilityLabel: label, accessibilityState: { selected }, className: styles.root({ className }), onPress: onPress, testID: testID, children: content }));
|
|
41
|
+
}
|
|
42
|
+
return (_jsx(View, { className: styles.root({ className }), testID: testID, children: content }));
|
|
43
|
+
}
|
|
44
|
+
export default Chip;
|
|
45
|
+
export { Chip };
|
|
@@ -9,5 +9,5 @@ type CopyableTextProps = {
|
|
|
9
9
|
label?: string;
|
|
10
10
|
className?: string;
|
|
11
11
|
};
|
|
12
|
-
declare function CopyableText({ value, getValue, label, className }: CopyableTextProps): import("react
|
|
12
|
+
declare function CopyableText({ value, getValue, label, className }: CopyableTextProps): import("react").JSX.Element;
|
|
13
13
|
export default CopyableText;
|
|
@@ -4,5 +4,5 @@ interface IProps {
|
|
|
4
4
|
withPadding?: boolean;
|
|
5
5
|
className?: string;
|
|
6
6
|
}
|
|
7
|
-
declare function CountRecords({ name, count, withPadding, className }: IProps): import("react
|
|
7
|
+
declare function CountRecords({ name, count, withPadding, className }: IProps): import("react").JSX.Element;
|
|
8
8
|
export default CountRecords;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface DataTableColumn<T> {
|
|
3
|
+
key: string;
|
|
4
|
+
header: string;
|
|
5
|
+
align?: "left" | "right" | "center";
|
|
6
|
+
flex?: number;
|
|
7
|
+
render?: (row: T) => ReactNode;
|
|
8
|
+
}
|
|
9
|
+
export interface DataTableProps<T> {
|
|
10
|
+
columns: DataTableColumn<T>[];
|
|
11
|
+
data: T[];
|
|
12
|
+
keyExtractor: (row: T, index: number) => string;
|
|
13
|
+
footer?: ReactNode;
|
|
14
|
+
emptyText?: string;
|
|
15
|
+
className?: string;
|
|
16
|
+
testID?: string;
|
|
17
|
+
}
|
|
18
|
+
declare function DataTable<T>({ columns, data, keyExtractor, footer, emptyText, className, testID, }: DataTableProps<T>): import("react").JSX.Element;
|
|
19
|
+
export default DataTable;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
+
import { cn } from "../theme/tw";
|
|
3
|
+
import { Typography } from "../Typography";
|
|
4
|
+
import { ScrollView, View } from "react-native";
|
|
5
|
+
const alignClass = {
|
|
6
|
+
left: "text-left",
|
|
7
|
+
right: "text-right",
|
|
8
|
+
center: "text-center",
|
|
9
|
+
};
|
|
10
|
+
function cellValue(col, row) {
|
|
11
|
+
if (col.render)
|
|
12
|
+
return col.render(row);
|
|
13
|
+
const raw = row[col.key];
|
|
14
|
+
return raw == null ? "" : String(raw);
|
|
15
|
+
}
|
|
16
|
+
function DataTable({ columns, data, keyExtractor, footer, emptyText = "Sin datos", className, testID, }) {
|
|
17
|
+
return (_jsxs(View, { className: cn("bg-bg-card rounded-lg border border-border-light overflow-hidden", className), testID: testID, children: [_jsx(View, { className: "flex-row bg-bg-muted px-3 py-2.5", children: columns.map((col) => (_jsx(View, { style: { flex: col.flex ?? 1 }, children: _jsx(Typography.Text, { className: cn("text-text-secondary font-semibold", alignClass[col.align ?? "left"]), numberOfLines: 1, variant: "caption", children: col.header }) }, col.key))) }), data.length === 0 ? (_jsx(View, { className: "px-3 py-6 items-center", children: _jsx(Typography.Text, { className: "text-text-tertiary", variant: "bodySmall", children: emptyText }) })) : (_jsx(ScrollView, { children: data.map((row, index) => (_jsx(View, { className: "flex-row px-3 py-3 border-t border-border-light", children: columns.map((col) => {
|
|
18
|
+
const content = cellValue(col, row);
|
|
19
|
+
return (_jsx(View, { style: { flex: col.flex ?? 1 }, children: typeof content === "string" || typeof content === "number" ? (_jsx(Typography.Text, { className: cn("text-text-primary", alignClass[col.align ?? "left"]), variant: "bodySmall", children: content })) : (content) }, col.key));
|
|
20
|
+
}) }, keyExtractor(row, index)))) })), footer ? (_jsx(View, { className: "flex-row px-3 py-3 border-t border-border-default bg-bg-muted", children: footer })) : null] }));
|
|
21
|
+
}
|
|
22
|
+
export default DataTable;
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { typographyVariants } from "../theme/typography";
|
|
2
|
-
import type
|
|
2
|
+
import { type StyleProp, type TextStyle } from "react-native";
|
|
3
3
|
type DateFormat = "short" | "long" | "numeric";
|
|
4
|
+
/**
|
|
5
|
+
* Visual layout:
|
|
6
|
+
* - `inline` (default): plain text, backward-compatible with previous usage.
|
|
7
|
+
* - `withIcon`: leading calendar/clock icon + text — the app-like default.
|
|
8
|
+
* - `pill`: tokenized rounded chip with icon (compact metadata).
|
|
9
|
+
*/
|
|
10
|
+
type DateVariant = "inline" | "withIcon" | "pill";
|
|
4
11
|
interface DateFieldProps {
|
|
5
12
|
value: string | Date | null | undefined;
|
|
6
13
|
format?: DateFormat;
|
|
@@ -13,6 +20,12 @@ interface DateFieldProps {
|
|
|
13
20
|
className?: string;
|
|
14
21
|
showTime?: boolean;
|
|
15
22
|
timezone?: string;
|
|
23
|
+
/** App-like layout. Default `inline` (no visual change vs. previous version). */
|
|
24
|
+
variant?: DateVariant;
|
|
25
|
+
/** Override the leading icon (ionicons). Defaults: calendar, or clock if `showTime`. */
|
|
26
|
+
icon?: string;
|
|
27
|
+
/** Show relative time ("hace 2 h") instead of the absolute date. */
|
|
28
|
+
relative?: boolean;
|
|
16
29
|
}
|
|
17
|
-
declare function DateField({ value, format, prefix, textVariant, color, style, semibold, bold, className, showTime, timezone, }: DateFieldProps): import("react
|
|
30
|
+
declare function DateField({ value, format, prefix, textVariant, color, style, semibold, bold, className, showTime, timezone, variant, icon, relative, }: DateFieldProps): import("react").JSX.Element;
|
|
18
31
|
export default DateField;
|
|
@@ -1,13 +1,43 @@
|
|
|
1
|
-
import { jsx as _jsx } from "nativewind/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
+
import Icon from "../Display/Display.Icon";
|
|
3
|
+
import { theme } from "../theme";
|
|
4
|
+
import { cn } from "../theme/tw";
|
|
2
5
|
import { Typography } from "../Typography";
|
|
3
6
|
import { formatDate, formatDateWithDefaultTimezone } from "../utils/date";
|
|
4
|
-
|
|
7
|
+
import { View } from "react-native";
|
|
8
|
+
function relativeTime(value) {
|
|
9
|
+
const then = new Date(value).getTime();
|
|
10
|
+
const diffSec = Math.round((Date.now() - then) / 1000);
|
|
11
|
+
const abs = Math.abs(diffSec);
|
|
12
|
+
const fut = diffSec < 0;
|
|
13
|
+
const fmt = (n, unit) => (fut ? `en ${n} ${unit}` : `hace ${n} ${unit}`);
|
|
14
|
+
if (abs < 60)
|
|
15
|
+
return "ahora";
|
|
16
|
+
if (abs < 3600)
|
|
17
|
+
return fmt(Math.floor(abs / 60), "min");
|
|
18
|
+
if (abs < 86400)
|
|
19
|
+
return fmt(Math.floor(abs / 3600), "h");
|
|
20
|
+
if (abs < 604800)
|
|
21
|
+
return fmt(Math.floor(abs / 86400), "d");
|
|
22
|
+
return fmt(Math.floor(abs / 604800), "sem");
|
|
23
|
+
}
|
|
24
|
+
function DateField({ value, format = "short", prefix = "", textVariant = "body", color, style = {}, semibold = false, bold = false, className, showTime = true, timezone, variant = "inline", icon, relative = false, }) {
|
|
5
25
|
const locale = "es-CR";
|
|
6
|
-
const
|
|
26
|
+
const absolute = !value
|
|
7
27
|
? "-"
|
|
8
28
|
: timezone
|
|
9
29
|
? formatDate(value, timezone, { showTime, locale })
|
|
10
30
|
: formatDateWithDefaultTimezone(value, { showTime, locale });
|
|
11
|
-
|
|
31
|
+
const formatted = value && relative ? relativeTime(value) : absolute;
|
|
32
|
+
const text = prefix ? `${prefix}${formatted}` : formatted;
|
|
33
|
+
const iconName = icon ?? (showTime && !relative ? "time-outline" : "calendar-outline");
|
|
34
|
+
const label = (_jsx(Typography.Text, { bold: bold, color: color, semibold: semibold && !bold, style: style, variant: textVariant, children: text }));
|
|
35
|
+
if (variant === "inline") {
|
|
36
|
+
return (_jsx(Typography.Text, { bold: bold, className: className, color: color, semibold: semibold && !bold, style: style, variant: textVariant, children: text }));
|
|
37
|
+
}
|
|
38
|
+
if (variant === "pill") {
|
|
39
|
+
return (_jsxs(View, { className: cn("flex-row items-center self-start gap-1.5 rounded-full bg-bg-muted px-2.5 py-1", className), children: [_jsx(Icon, { color: color ?? theme.icon.secondary, name: iconName, size: 14 }), label] }));
|
|
40
|
+
}
|
|
41
|
+
return (_jsxs(View, { className: cn("flex-row items-center gap-1.5", className), children: [_jsx(Icon, { color: color ?? theme.icon.secondary, name: iconName, size: 16 }), label] }));
|
|
12
42
|
}
|
|
13
43
|
export default DateField;
|
|
@@ -40,5 +40,5 @@ interface DividerProps extends VariantProps<typeof divider> {
|
|
|
40
40
|
thickness?: number;
|
|
41
41
|
className?: string;
|
|
42
42
|
}
|
|
43
|
-
declare function Divider({ thickness, spacing, colorScheme, className }: DividerProps): import("react
|
|
43
|
+
declare function Divider({ thickness, spacing, colorScheme, className }: DividerProps): import("react").JSX.Element;
|
|
44
44
|
export default Divider;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface IconBadgeProps {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
count?: number;
|
|
5
|
+
max?: number;
|
|
6
|
+
dot?: boolean;
|
|
7
|
+
color?: string;
|
|
8
|
+
onPress?: () => void;
|
|
9
|
+
accessibilityLabel?: string;
|
|
10
|
+
testID?: string;
|
|
11
|
+
}
|
|
12
|
+
declare function IconBadge({ children, count, max, dot, color, onPress, accessibilityLabel, testID, }: IconBadgeProps): import("react").JSX.Element;
|
|
13
|
+
export default IconBadge;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
+
import Pressable from "../primitives/Pressable";
|
|
3
|
+
import { theme } from "../theme";
|
|
4
|
+
import { Typography } from "../Typography";
|
|
5
|
+
import { View } from "react-native";
|
|
6
|
+
function IconBadge({ children, count, max = 99, dot = false, color, onPress, accessibilityLabel, testID, }) {
|
|
7
|
+
const showCount = typeof count === "number" && count > 0;
|
|
8
|
+
const showBadge = dot || showCount;
|
|
9
|
+
const label = showCount ? (count > max ? `${max}+` : String(count)) : "";
|
|
10
|
+
const badgeColor = color ?? theme.danger;
|
|
11
|
+
const content = (_jsxs(View, { style: { position: "relative" }, children: [children, showBadge ? (_jsx(View, { style: {
|
|
12
|
+
position: "absolute",
|
|
13
|
+
top: -4,
|
|
14
|
+
right: -6,
|
|
15
|
+
minWidth: dot ? 10 : 18,
|
|
16
|
+
height: dot ? 10 : 18,
|
|
17
|
+
borderRadius: 999,
|
|
18
|
+
paddingHorizontal: dot ? 0 : 4,
|
|
19
|
+
backgroundColor: badgeColor,
|
|
20
|
+
alignItems: "center",
|
|
21
|
+
justifyContent: "center",
|
|
22
|
+
borderWidth: 2,
|
|
23
|
+
borderColor: theme.bg.card,
|
|
24
|
+
}, children: !dot && label ? (_jsx(Typography.Text, { style: { color: theme.text.inverse, fontSize: 10, lineHeight: 12 }, children: label })) : null })) : null] }));
|
|
25
|
+
if (onPress) {
|
|
26
|
+
return (_jsx(Pressable, { accessibilityLabel: accessibilityLabel, hitSlop: 10, onPress: onPress, testID: testID, children: content }));
|
|
27
|
+
}
|
|
28
|
+
return (_jsx(View, { accessibilityLabel: accessibilityLabel, testID: testID, children: content }));
|
|
29
|
+
}
|
|
30
|
+
export default IconBadge;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ImageResizeMode, type ImageSourcePropType, type ImageStyle } from "react-native";
|
|
2
|
+
export interface DisplayImageProps {
|
|
3
|
+
source: ImageSourcePropType;
|
|
4
|
+
width?: number | `${number}%`;
|
|
5
|
+
height?: number;
|
|
6
|
+
aspectRatio?: number;
|
|
7
|
+
radius?: number;
|
|
8
|
+
resizeMode?: ImageResizeMode;
|
|
9
|
+
fallbackIcon?: string;
|
|
10
|
+
className?: string;
|
|
11
|
+
style?: ImageStyle;
|
|
12
|
+
testID?: string;
|
|
13
|
+
}
|
|
14
|
+
declare function DisplayImage({ source, width, height, aspectRatio, radius, resizeMode, fallbackIcon, className, style, testID, }: DisplayImageProps): import("react").JSX.Element;
|
|
15
|
+
export default DisplayImage;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
+
import Icon from "../Display/Display.Icon";
|
|
3
|
+
import Skeleton from "../Feedback/Feedback.Skeleton";
|
|
4
|
+
import { theme } from "../theme";
|
|
5
|
+
import { cn } from "../theme/tw";
|
|
6
|
+
import { useState } from "react";
|
|
7
|
+
import { Image, View, } from "react-native";
|
|
8
|
+
function DisplayImage({ source, width = "100%", height, aspectRatio, radius = 12, resizeMode = "cover", fallbackIcon = "image-outline", className, style, testID, }) {
|
|
9
|
+
const [loading, setLoading] = useState(true);
|
|
10
|
+
const [failed, setFailed] = useState(false);
|
|
11
|
+
const dimensions = { width, height, aspectRatio, borderRadius: radius };
|
|
12
|
+
return (_jsx(View, { className: cn("overflow-hidden bg-bg-muted", className), style: dimensions, testID: testID, children: failed ? (_jsx(View, { className: "flex-1 items-center justify-center", children: _jsx(Icon, { color: theme.icon.disabled, name: fallbackIcon, size: 32 }) })) : (_jsxs(_Fragment, { children: [_jsx(Image, { onError: () => {
|
|
13
|
+
setFailed(true);
|
|
14
|
+
setLoading(false);
|
|
15
|
+
}, onLoadEnd: () => setLoading(false), resizeMode: resizeMode, source: source, style: [{ width: "100%", height: "100%" }, style] }), loading ? (_jsx(View, { style: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0 }, children: _jsx(Skeleton, { height: "100%", radius: radius, width: "100%" }) })) : null] })) }));
|
|
16
|
+
}
|
|
17
|
+
export default DisplayImage;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface KeyValueProps {
|
|
3
|
+
label: string;
|
|
4
|
+
value?: ReactNode;
|
|
5
|
+
align?: "row" | "stacked";
|
|
6
|
+
className?: string;
|
|
7
|
+
testID?: string;
|
|
8
|
+
}
|
|
9
|
+
declare function KeyValue({ label, value, align, className, testID }: KeyValueProps): import("react").JSX.Element;
|
|
10
|
+
export default KeyValue;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
+
import { cn } from "../theme/tw";
|
|
3
|
+
import { Typography } from "../Typography";
|
|
4
|
+
import { View } from "react-native";
|
|
5
|
+
function KeyValue({ label, value, align = "row", className, testID }) {
|
|
6
|
+
const isRow = align === "row";
|
|
7
|
+
return (_jsxs(View, { className: cn(isRow ? "flex-row items-center justify-between gap-3" : "gap-0.5", "py-2", className), testID: testID, children: [_jsx(Typography.Text, { className: "text-text-secondary", variant: "bodySmall", children: label }), typeof value === "string" || typeof value === "number" ? (_jsx(Typography.Text, { className: cn("text-text-primary", isRow && "text-right"), semibold: isRow, children: value })) : (value)] }));
|
|
8
|
+
}
|
|
9
|
+
export default KeyValue;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface ListItemProps {
|
|
3
|
+
title: string;
|
|
4
|
+
subtitle?: string;
|
|
5
|
+
leading?: ReactNode;
|
|
6
|
+
trailing?: ReactNode;
|
|
7
|
+
onPress?: () => void;
|
|
8
|
+
showDivider?: boolean;
|
|
9
|
+
className?: string;
|
|
10
|
+
testID?: string;
|
|
11
|
+
}
|
|
12
|
+
declare function ListItem({ title, subtitle, leading, trailing, onPress, showDivider, className, testID, }: ListItemProps): import("react").JSX.Element;
|
|
13
|
+
export default ListItem;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "nativewind/jsx-runtime";
|
|
2
|
+
import Pressable from "../primitives/Pressable";
|
|
3
|
+
import { cn } from "../theme/tw";
|
|
4
|
+
import { Typography } from "../Typography";
|
|
5
|
+
import { View } from "react-native";
|
|
6
|
+
function ListItem({ title, subtitle, leading, trailing, onPress, showDivider = true, className, testID, }) {
|
|
7
|
+
const content = (_jsxs(_Fragment, { children: [leading ? _jsx(View, { className: "mr-3 justify-center", children: leading }) : null, _jsxs(View, { className: "flex-1 gap-0.5", children: [_jsx(Typography.Text, { className: "text-text-primary", numberOfLines: 1, semibold: true, variant: "body", children: title }), subtitle ? (_jsx(Typography.Text, { className: "text-text-secondary", numberOfLines: 1, variant: "bodySmall", children: subtitle })) : null] }), trailing ? _jsx(View, { className: "ml-3 justify-center", children: trailing }) : null] }));
|
|
8
|
+
const base = cn("flex-row items-center py-3 px-4 bg-bg-card", showDivider && "border-b border-border-default", className);
|
|
9
|
+
if (onPress) {
|
|
10
|
+
return (_jsx(Pressable, { className: base, onPress: onPress, testID: testID, children: content }));
|
|
11
|
+
}
|
|
12
|
+
return (_jsx(View, { className: base, testID: testID, children: content }));
|
|
13
|
+
}
|
|
14
|
+
export default ListItem;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "nativewind/jsx-runtime";
|
|
2
|
+
import { getBrandingLogo } from "../branding";
|
|
2
3
|
import { tv } from "../theme/tw";
|
|
3
4
|
import { Image, View } from "react-native";
|
|
4
5
|
const logo = tv({
|
|
@@ -31,6 +32,7 @@ function renderImage(imageClassName, source) {
|
|
|
31
32
|
}
|
|
32
33
|
const Logo = ({ source, size = "medium", className }) => {
|
|
33
34
|
const styles = logo({ size });
|
|
34
|
-
|
|
35
|
+
const resolvedSource = source ?? getBrandingLogo();
|
|
36
|
+
return (_jsx(View, { className: styles.container({ className }), children: renderImage(styles.image(), resolvedSource) }));
|
|
35
37
|
};
|
|
36
38
|
export default Logo;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { type ImageSourcePropType } from "react-native";
|
|
3
|
+
export interface MediaCardProps {
|
|
4
|
+
image: ImageSourcePropType;
|
|
5
|
+
title?: string;
|
|
6
|
+
subtitle?: string;
|
|
7
|
+
badge?: ReactNode;
|
|
8
|
+
overlay?: ReactNode;
|
|
9
|
+
aspectRatio?: number;
|
|
10
|
+
height?: number;
|
|
11
|
+
radius?: number;
|
|
12
|
+
onPress?: () => void;
|
|
13
|
+
className?: string;
|
|
14
|
+
testID?: string;
|
|
15
|
+
}
|
|
16
|
+
declare function MediaCard({ image, title, subtitle, badge, overlay, aspectRatio, height, radius, onPress, className, testID, }: MediaCardProps): import("react").JSX.Element;
|
|
17
|
+
export default MediaCard;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
+
import DisplayImage from "../Display/Display.Image";
|
|
3
|
+
import Pressable from "../primitives/Pressable";
|
|
4
|
+
import { cn } from "../theme/tw";
|
|
5
|
+
import { Typography } from "../Typography";
|
|
6
|
+
import { LinearGradient } from "expo-linear-gradient";
|
|
7
|
+
import { View } from "react-native";
|
|
8
|
+
function MediaCard({ image, title, subtitle, badge, overlay, aspectRatio = 16 / 9, height, radius = 16, onPress, className, testID, }) {
|
|
9
|
+
const Wrapper = onPress ? Pressable : View;
|
|
10
|
+
return (_jsxs(Wrapper, { accessibilityLabel: title, accessibilityRole: onPress ? "button" : undefined, className: cn("overflow-hidden", className), onPress: onPress, style: { borderRadius: radius }, testID: testID, children: [_jsx(DisplayImage, { aspectRatio: height ? undefined : aspectRatio, height: height, radius: radius, source: image }), badge ? _jsx(View, { className: "absolute top-3 left-3", children: badge }) : null, title || subtitle || overlay ? (_jsxs(LinearGradient, { colors: ["transparent", "rgba(0,0,0,0.75)"], style: { position: "absolute", left: 0, right: 0, bottom: 0, padding: 12 }, children: [overlay, title ? (_jsx(Typography.Text, { className: "text-white", numberOfLines: 1, semibold: true, variant: "subtitle", children: title })) : null, subtitle ? (_jsx(Typography.Text, { className: "text-white/80", numberOfLines: 1, variant: "bodySmall", children: subtitle })) : null] })) : null] }));
|
|
11
|
+
}
|
|
12
|
+
export default MediaCard;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { type ImageSourcePropType } from "react-native";
|
|
3
|
+
export interface MediaEmbedProps {
|
|
4
|
+
thumbnail: ImageSourcePropType;
|
|
5
|
+
onPress: () => void;
|
|
6
|
+
duration?: string;
|
|
7
|
+
title?: string;
|
|
8
|
+
source?: ReactNode;
|
|
9
|
+
aspectRatio?: number;
|
|
10
|
+
className?: string;
|
|
11
|
+
testID?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Linkable short-video card (Short/TikTok/Reel): thumbnail + play + duration.
|
|
15
|
+
* Opens the content on press (onPress). True inline embedding needs WebView (optional
|
|
16
|
+
* peer) — this is the lightweight/portable piece; wrap it with your player if needed.
|
|
17
|
+
*/
|
|
18
|
+
declare function MediaEmbed({ thumbnail, onPress, duration, title, source, aspectRatio, className, testID, }: MediaEmbedProps): import("react").JSX.Element;
|
|
19
|
+
export default MediaEmbed;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
+
import Icon from "../Display/Display.Icon";
|
|
3
|
+
import DisplayImage from "../Display/Display.Image";
|
|
4
|
+
import Pressable from "../primitives/Pressable";
|
|
5
|
+
import { theme } from "../theme";
|
|
6
|
+
import { cn } from "../theme/tw";
|
|
7
|
+
import { Typography } from "../Typography";
|
|
8
|
+
import { View } from "react-native";
|
|
9
|
+
/**
|
|
10
|
+
* Linkable short-video card (Short/TikTok/Reel): thumbnail + play + duration.
|
|
11
|
+
* Opens the content on press (onPress). True inline embedding needs WebView (optional
|
|
12
|
+
* peer) — this is the lightweight/portable piece; wrap it with your player if needed.
|
|
13
|
+
*/
|
|
14
|
+
function MediaEmbed({ thumbnail, onPress, duration, title, source, aspectRatio = 9 / 16, className, testID, }) {
|
|
15
|
+
return (_jsxs(Pressable, { accessibilityLabel: title ?? "Reproducir video", accessibilityRole: "button", className: cn("overflow-hidden rounded-xl", className), onPress: onPress, testID: testID, children: [_jsx(DisplayImage, { aspectRatio: aspectRatio, radius: 12, source: thumbnail }), _jsx(View, { style: {
|
|
16
|
+
position: "absolute",
|
|
17
|
+
top: 0,
|
|
18
|
+
left: 0,
|
|
19
|
+
right: 0,
|
|
20
|
+
bottom: 0,
|
|
21
|
+
alignItems: "center",
|
|
22
|
+
justifyContent: "center",
|
|
23
|
+
}, children: _jsx(View, { style: {
|
|
24
|
+
width: 44,
|
|
25
|
+
height: 44,
|
|
26
|
+
borderRadius: 22,
|
|
27
|
+
backgroundColor: "rgba(0,0,0,0.55)",
|
|
28
|
+
alignItems: "center",
|
|
29
|
+
justifyContent: "center",
|
|
30
|
+
}, children: _jsx(Icon, { color: theme.text.inverse, name: "play", size: 22 }) }) }), duration ? (_jsx(View, { className: "rounded", style: {
|
|
31
|
+
position: "absolute",
|
|
32
|
+
bottom: 8,
|
|
33
|
+
right: 8,
|
|
34
|
+
backgroundColor: "rgba(0,0,0,0.7)",
|
|
35
|
+
paddingHorizontal: 6,
|
|
36
|
+
paddingVertical: 2,
|
|
37
|
+
}, children: _jsx(Typography.Text, { className: "text-white", variant: "caption", children: duration }) })) : null, source ? (_jsx(View, { style: { position: "absolute", top: 8, left: 8 }, children: source })) : null, title ? (_jsx(View, { style: { position: "absolute", left: 8, right: 8, bottom: 8 }, children: _jsx(Typography.Text, { className: "text-white", numberOfLines: 2, variant: "bodySmall", children: title }) })) : null] }));
|
|
38
|
+
}
|
|
39
|
+
export default MediaEmbed;
|
|
@@ -99,5 +99,5 @@ interface MenuButtonProps extends VariantProps<typeof menuButton> {
|
|
|
99
99
|
rightComponent?: ReactNode;
|
|
100
100
|
className?: string;
|
|
101
101
|
}
|
|
102
|
-
declare function MenuButton({ icon: Icon, label, description, onPress, rightComponent, showDivider, variant, disabled, className, }: MenuButtonProps): import("react
|
|
102
|
+
declare function MenuButton({ icon: Icon, label, description, onPress, rightComponent, showDivider, variant, disabled, className, }: MenuButtonProps): import("react").JSX.Element;
|
|
103
103
|
export default MenuButton;
|
|
@@ -15,5 +15,5 @@ interface MonetaryFieldProps {
|
|
|
15
15
|
bold?: boolean;
|
|
16
16
|
className?: string;
|
|
17
17
|
}
|
|
18
|
-
declare function MonetaryField({ value, currencySymbol, prefix, color, textVariant, style, symbolColor, semibold, bold, className, }: MonetaryFieldProps): import("react
|
|
18
|
+
declare function MonetaryField({ value, currencySymbol, prefix, color, textVariant, style, symbolColor, semibold, bold, className, }: MonetaryFieldProps): import("react").JSX.Element;
|
|
19
19
|
export default MonetaryField;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface PriceTagProps {
|
|
2
|
+
amount: number;
|
|
3
|
+
originalAmount?: number;
|
|
4
|
+
currency?: string;
|
|
5
|
+
size?: "sm" | "md" | "lg";
|
|
6
|
+
className?: string;
|
|
7
|
+
testID?: string;
|
|
8
|
+
}
|
|
9
|
+
declare function PriceTag({ amount, originalAmount, currency, size, className, testID, }: PriceTagProps): import("react").JSX.Element;
|
|
10
|
+
export default PriceTag;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "nativewind/jsx-runtime";
|
|
2
|
+
import { cn } from "../theme/tw";
|
|
3
|
+
import { Typography } from "../Typography";
|
|
4
|
+
import { View } from "react-native";
|
|
5
|
+
const sizeMap = {
|
|
6
|
+
sm: { price: "body", original: "caption" },
|
|
7
|
+
md: { price: "subtitle", original: "bodySmall" },
|
|
8
|
+
lg: { price: "h3", original: "body" },
|
|
9
|
+
};
|
|
10
|
+
function format(amount, currency) {
|
|
11
|
+
const formatted = amount.toLocaleString("es-BO", {
|
|
12
|
+
minimumFractionDigits: 2,
|
|
13
|
+
maximumFractionDigits: 2,
|
|
14
|
+
});
|
|
15
|
+
return `${currency} ${formatted}`;
|
|
16
|
+
}
|
|
17
|
+
function PriceTag({ amount, originalAmount, currency = "Bs", size = "md", className, testID, }) {
|
|
18
|
+
const variants = sizeMap[size];
|
|
19
|
+
const hasDiscount = typeof originalAmount === "number" && originalAmount > amount;
|
|
20
|
+
const off = hasDiscount ? Math.round((1 - amount / originalAmount) * 100) : 0;
|
|
21
|
+
return (_jsxs(View, { className: cn("flex-row items-baseline gap-2", className), testID: testID, children: [_jsx(Typography.Text, { className: "text-text-primary", semibold: true, variant: variants.price, children: format(amount, currency) }), hasDiscount ? (_jsxs(_Fragment, { children: [_jsx(Typography.Text, { className: "text-text-tertiary", style: { textDecorationLine: "line-through" }, variant: variants.original, children: format(originalAmount, currency) }), _jsx(View, { className: "bg-danger-light rounded px-1.5 py-0.5", children: _jsxs(Typography.Text, { className: "text-danger font-semibold", variant: "caption", children: ["-", off, "%"] }) })] })) : null] }));
|
|
22
|
+
}
|
|
23
|
+
export default PriceTag;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { type ImageSourcePropType } from "react-native";
|
|
3
|
+
export interface ProductCardProps {
|
|
4
|
+
title: string;
|
|
5
|
+
image: ImageSourcePropType;
|
|
6
|
+
price: number;
|
|
7
|
+
originalPrice?: number;
|
|
8
|
+
currency?: string;
|
|
9
|
+
subtitle?: string;
|
|
10
|
+
rating?: number;
|
|
11
|
+
badge?: ReactNode;
|
|
12
|
+
onPress?: () => void;
|
|
13
|
+
className?: string;
|
|
14
|
+
testID?: string;
|
|
15
|
+
}
|
|
16
|
+
declare function ProductCard({ title, image, price, originalPrice, currency, subtitle, rating, badge, onPress, className, testID, }: ProductCardProps): import("react").JSX.Element;
|
|
17
|
+
export default ProductCard;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
+
import DisplayImage from "../Display/Display.Image";
|
|
3
|
+
import PriceTag from "../Display/Display.PriceTag";
|
|
4
|
+
import Rating from "../Display/Display.Rating";
|
|
5
|
+
import Pressable from "../primitives/Pressable";
|
|
6
|
+
import { theme } from "../theme";
|
|
7
|
+
import { cn } from "../theme/tw";
|
|
8
|
+
import { Typography } from "../Typography";
|
|
9
|
+
import { View } from "react-native";
|
|
10
|
+
function ProductCard({ title, image, price, originalPrice, currency, subtitle, rating, badge, onPress, className, testID, }) {
|
|
11
|
+
return (_jsxs(Pressable, { accessibilityLabel: title, className: cn("bg-bg-card rounded-xl overflow-hidden border border-border-light", className), onPress: onPress, style: theme.shadow.sm, testID: testID, children: [_jsxs(View, { children: [_jsx(DisplayImage, { aspectRatio: 1, radius: 0, source: image }), badge ? _jsx(View, { className: "absolute top-2 left-2", children: badge }) : null] }), _jsxs(View, { className: "p-3 gap-1", children: [_jsx(Typography.Text, { className: "text-text-primary", numberOfLines: 1, semibold: true, variant: "body", children: title }), subtitle ? (_jsx(Typography.Text, { className: "text-text-secondary", numberOfLines: 1, variant: "bodySmall", children: subtitle })) : null, typeof rating === "number" ? _jsx(Rating, { readOnly: true, size: 14, value: rating }) : null, _jsx(View, { className: "mt-1", children: _jsx(PriceTag, { amount: price, currency: currency, originalAmount: originalPrice, size: "sm" }) })] })] }));
|
|
12
|
+
}
|
|
13
|
+
export default ProductCard;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface RatingProps {
|
|
2
|
+
value: number;
|
|
3
|
+
max?: number;
|
|
4
|
+
size?: number;
|
|
5
|
+
onChange?: (value: number) => void;
|
|
6
|
+
readOnly?: boolean;
|
|
7
|
+
className?: string;
|
|
8
|
+
testID?: string;
|
|
9
|
+
}
|
|
10
|
+
declare function Rating({ value, max, size, onChange, readOnly, className, testID, }: RatingProps): import("react").JSX.Element;
|
|
11
|
+
export default Rating;
|