@sincpro/mobile-ui 0.3.0 → 0.3.1

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 (71) hide show
  1. package/dist/Dialog/BottomSheet/BottomSheet.Root.d.ts +2 -2
  2. package/dist/Dialog/BottomSheet/BottomSheet.Root.js +2 -2
  3. package/dist/Dialog/Dialog.Confirmation.js +5 -1
  4. package/dist/Dialog/Dialog.EditValue.js +1 -1
  5. package/dist/Display/Display.GradientSurface.d.ts +116 -0
  6. package/dist/Display/Display.GradientSurface.js +62 -0
  7. package/dist/Display/Display.KeyValue.js +1 -1
  8. package/dist/Display/Display.ListItem.d.ts +5 -1
  9. package/dist/Display/Display.ListItem.js +6 -2
  10. package/dist/Display/Display.Monetary.js +1 -1
  11. package/dist/Display/Display.Pattern.d.ts +26 -0
  12. package/dist/Display/Display.Pattern.js +27 -0
  13. package/dist/Display/Display.PriceTag.js +3 -3
  14. package/dist/Display/Display.Stat.js +1 -1
  15. package/dist/Display/Display.StatCard.js +1 -1
  16. package/dist/Display/index.d.ts +4 -0
  17. package/dist/Display/index.js +4 -0
  18. package/dist/Feedback/Feedback.DomainSplashScreen.js +3 -2
  19. package/dist/Feedback/Feedback.Loading.d.ts +6 -0
  20. package/dist/Feedback/Feedback.Loading.js +7 -1
  21. package/dist/Feedback/Feedback.Spinner.js +2 -1
  22. package/dist/Feedback/Feedback.Splash.d.ts +7 -1
  23. package/dist/Feedback/Feedback.Splash.js +11 -2
  24. package/dist/Feedback/Toast.context.d.ts +8 -1
  25. package/dist/Feedback/Toast.context.js +25 -23
  26. package/dist/Form/Form.Button.d.ts +4 -4
  27. package/dist/Form/Form.Button.js +19 -19
  28. package/dist/Form/Form.Checkbox.js +1 -1
  29. package/dist/Form/Form.Input.js +1 -1
  30. package/dist/Form/Form.InputField.js +1 -1
  31. package/dist/Form/Form.Switch.js +1 -1
  32. package/dist/Navigation/Navigation.AppBar.d.ts +18 -2
  33. package/dist/Navigation/Navigation.AppBar.js +48 -9
  34. package/dist/Navigation/Navigation.BottomNav.d.ts +33 -5
  35. package/dist/Navigation/Navigation.BottomNav.js +90 -17
  36. package/dist/Navigation/Navigation.SearchBar.js +7 -1
  37. package/dist/Navigation/Navigation.TabIcon.d.ts +4 -0
  38. package/dist/Navigation/Navigation.TabIcon.js +4 -0
  39. package/dist/Navigation/Navigation.TabItem.d.ts +5 -0
  40. package/dist/Navigation/Navigation.TabItem.js +5 -0
  41. package/dist/Navigation/index.d.ts +2 -2
  42. package/dist/Typography/Typography.Text.d.ts +1 -1
  43. package/dist/Typography/Typography.Text.js +16 -6
  44. package/dist/icons/OdooIcon.d.ts +5 -0
  45. package/dist/icons/OdooIcon.js +5 -0
  46. package/dist/icons/PrinterIcon.d.ts +5 -0
  47. package/dist/icons/PrinterIcon.js +5 -0
  48. package/dist/layouts/AuthContainer.js +2 -2
  49. package/dist/theme/dark.d.ts +3 -3
  50. package/dist/theme/dark.js +54 -53
  51. package/dist/theme/default.js +1 -0
  52. package/dist/theme/index.d.ts +1 -0
  53. package/dist/theme/index.js +1 -0
  54. package/dist/theme/types.d.ts +1 -0
  55. package/dist/theme/typography.d.ts +117 -60
  56. package/dist/theme/typography.js +115 -29
  57. package/dist/utils/timezone.d.ts +5 -0
  58. package/dist/views/FormViewV2.d.ts +2 -1
  59. package/dist/views/FormViewV2.js +8 -4
  60. package/dist/views/ListViewV2.context.d.ts +5 -1
  61. package/dist/views/ListViewV2.context.js +3 -1
  62. package/dist/views/ListViewV2.d.ts +7 -2
  63. package/dist/views/ListViewV2.js +18 -20
  64. package/dist/widgets/GeoPermissionCard.d.ts +5 -0
  65. package/dist/widgets/GeoPermissionCard.js +8 -3
  66. package/dist/widgets/JSONViewer.js +3 -6
  67. package/dist/widgets/TimeZoneSelector.d.ts +5 -0
  68. package/dist/widgets/TimeZoneSelector.js +6 -1
  69. package/dist/widgets/TimeZoneSelectorModal.d.ts +5 -0
  70. package/dist/widgets/TimeZoneSelectorModal.js +8 -3
  71. package/package.json +12 -7
@@ -1,20 +1,24 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment } from "nativewind/jsx-runtime";
2
2
  import { ErrorBoundary, Feedback } from "../Feedback";
3
3
  import Container from "../layouts/Container";
4
+ import { AppBar } from "../Navigation/Navigation.AppBar";
4
5
  import { theme } from "../theme";
5
6
  import { FormViewProvider, useFormView } from "../views/FormViewV2.context";
6
- import ScreenHeader, { EVariantScreenHeader } from "../widgets/ScreenHeader";
7
7
  import React from "react";
8
8
  import { RefreshControl, View } from "react-native";
9
9
  import { KeyboardAwareScrollView } from "react-native-keyboard-controller";
10
10
  function FormViewRoot({ name, description, item, isLoading = false, isEmpty = false, hasError = false, errorMessage, readonly = false, onRefresh, onRetry, onBack, withContainer = true, children, }) {
11
11
  const Wrapper = withContainer ? Container : View;
12
- const wrapperProps = withContainer ? {} : { style: { flex: 1 } };
12
+ // The header (AppBar) / parent layout owns the TOP safe-area; the inner Container only
13
+ // reserves the remaining edges to avoid stacking the top inset (double padding).
14
+ const wrapperProps = withContainer
15
+ ? { edges: ["bottom", "left", "right"] }
16
+ : { style: { flex: 1 } };
13
17
  return (_jsx(FormViewProvider, { description: description, errorMessage: errorMessage, hasError: hasError, isEmpty: isEmpty, isLoading: isLoading, item: item, name: name, onBack: onBack, onRefresh: onRefresh, onRetry: onRetry, readonly: readonly, children: _jsx(ErrorBoundary, { children: _jsx(Wrapper, { ...wrapperProps, children: children }) }) }));
14
18
  }
15
- function Header({ variant = EVariantScreenHeader.FLAT_HEADER, logoSource, children, }) {
19
+ function Header({ children, }) {
16
20
  const { name, description, onBack } = useFormView();
17
- return (_jsx(_Fragment, { children: _jsx(ScreenHeader, { logoSource: logoSource, onBack: onBack, subtitle: description ? description : `Seleccionar ${name}`, title: name, variant: variant, children: children }) }));
21
+ return (_jsx(AppBar, { onBack: onBack, safeArea: false, subheader: children, subtitle: description ? description : `Seleccionar ${name}`, title: name }));
18
22
  }
19
23
  function HeaderActions({ children }) {
20
24
  return (_jsx(View, { className: "flex-row px-4 my-4 items-center justify-between flex-1 gap-2", children: children }));
@@ -15,8 +15,10 @@ interface ListViewContextValue<T> {
15
15
  onDeleteItem?: (item: T) => void;
16
16
  onSearch?: (query: string) => void;
17
17
  onBack?: () => void;
18
+ onLoadMore?: () => void;
19
+ loadingMore?: boolean;
18
20
  }
19
- export declare function ListViewProvider<T>({ name, description, items, isLoading, hasError, errorMessage, readonly, onRefresh, onRetry, onPressItem, onDeleteItem, onSearch, onBack, children, }: {
21
+ export declare function ListViewProvider<T>({ name, description, items, isLoading, hasError, errorMessage, readonly, onRefresh, onRetry, onPressItem, onDeleteItem, onSearch, onBack, onLoadMore, loadingMore, children, }: {
20
22
  name: string;
21
23
  description?: string;
22
24
  items: T[];
@@ -30,6 +32,8 @@ export declare function ListViewProvider<T>({ name, description, items, isLoadin
30
32
  onDeleteItem?: (item: T) => void;
31
33
  onSearch?: (query: string) => void;
32
34
  onBack?: () => void;
35
+ onLoadMore?: () => void;
36
+ loadingMore?: boolean;
33
37
  children: ReactNode;
34
38
  }): import("react").JSX.Element;
35
39
  export declare function useListView<T>(): ListViewContextValue<T>;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "nativewind/jsx-runtime";
2
2
  import { createContext, useContext, useState } from "react";
3
3
  const Context = createContext(null);
4
- export function ListViewProvider({ name, description, items, isLoading = false, hasError = false, errorMessage, readonly = false, onRefresh, onRetry, onPressItem, onDeleteItem, onSearch, onBack, children, }) {
4
+ export function ListViewProvider({ name, description, items, isLoading = false, hasError = false, errorMessage, readonly = false, onRefresh, onRetry, onPressItem, onDeleteItem, onSearch, onBack, onLoadMore, loadingMore = false, children, }) {
5
5
  const [showRefreshing, setShowRefreshing] = useState(false);
6
6
  return (_jsx(Context.Provider, { value: {
7
7
  name,
@@ -19,6 +19,8 @@ export function ListViewProvider({ name, description, items, isLoading = false,
19
19
  onDeleteItem,
20
20
  onSearch,
21
21
  onBack,
22
+ onLoadMore,
23
+ loadingMore,
22
24
  }, children: children }));
23
25
  }
24
26
  export function useListView() {
@@ -15,12 +15,17 @@ interface ListViewProps<T> {
15
15
  onDeleteItem?: (item: T) => void;
16
16
  onSearch?: (query: string) => void;
17
17
  onBack?: () => void;
18
+ /** Called when the list nears the end — wire to fetch the next page. */
19
+ onLoadMore?: () => void;
20
+ /** Show a footer spinner while the next page loads. */
21
+ loadingMore?: boolean;
18
22
  backgroundColor?: string;
19
23
  withContainer?: boolean;
20
24
  children: ReactNode;
21
25
  }
22
- declare function ListViewRoot<T>({ name, description, items, isLoading, hasError, errorMessage, readonly, onRefresh, onRetry, onPressItem, onDeleteItem, onSearch, onBack, backgroundColor, withContainer, children, }: ListViewProps<T>): React.JSX.Element;
23
- declare function Header({ variant, children, }: {
26
+ declare function ListViewRoot<T>({ name, description, items, isLoading, hasError, errorMessage, readonly, onRefresh, onRetry, onPressItem, onDeleteItem, onSearch, onBack, onLoadMore, loadingMore, backgroundColor, withContainer, children, }: ListViewProps<T>): React.JSX.Element;
27
+ declare function Header({ children, }: {
28
+ /** @deprecated The header is now flat (Navigation.AppBar); `variant` is ignored. */
24
29
  variant?: EVariantScreenHeader;
25
30
  children?: ReactNode;
26
31
  }): React.JSX.Element;
@@ -1,7 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "nativewind/jsx-runtime";
2
2
  import { Display } from "../Display";
3
3
  import { ErrorBoundary, Feedback } from "../Feedback";
4
- import { Form } from "../Form";
5
4
  import Container from "../layouts/Container";
6
5
  import { Navigation } from "../Navigation";
7
6
  import { theme } from "../theme";
@@ -9,20 +8,21 @@ import { cn, tv } from "../theme/tw";
9
8
  import { Typography } from "../Typography";
10
9
  import { ListViewProvider, useListView } from "../views/ListViewV2.context";
11
10
  import { toRowItems } from "../views/types/IListView";
12
- import ScreenHeader, { EVariantScreenHeader } from "../widgets/ScreenHeader";
13
- import React, { useCallback, useEffect, useMemo, useState } from "react";
11
+ import { useCallback, useEffect, useMemo, useState } from "react";
14
12
  import { FlatList, RefreshControl, ScrollView, TouchableOpacity, View, } from "react-native";
15
- function ListViewRoot({ name, description, items, isLoading = false, hasError = false, errorMessage, readonly = false, onRefresh, onRetry, onPressItem, onDeleteItem, onSearch, onBack, backgroundColor, withContainer = true, children, }) {
13
+ function ListViewRoot({ name, description, items, isLoading = false, hasError = false, errorMessage, readonly = false, onRefresh, onRetry, onPressItem, onDeleteItem, onSearch, onBack, onLoadMore, loadingMore = false, backgroundColor, withContainer = true, children, }) {
16
14
  const Wrapper = withContainer ? Container : View;
15
+ // The header (AppBar) / parent layout owns the TOP safe-area; the Container only reserves
16
+ // the remaining edges to avoid stacking the top inset (double padding).
17
17
  const wrapperProps = withContainer
18
- ? {} // Container maneja su propio backgroundColor
18
+ ? { edges: ["bottom", "left", "right"] }
19
19
  : { className: "flex-1 bg-bg-page" };
20
20
  // Propagate contentWithMargin to ContentList via context
21
- return (_jsx(ListViewProvider, { description: description, errorMessage: errorMessage, hasError: hasError, isLoading: isLoading, items: items, name: name, onBack: onBack, onDeleteItem: onDeleteItem, onPressItem: onPressItem, onRefresh: onRefresh, onRetry: onRetry, onSearch: onSearch, readonly: readonly, children: _jsx(ErrorBoundary, { children: _jsx(Wrapper, { ...wrapperProps, children: children }) }) }));
21
+ return (_jsx(ListViewProvider, { description: description, errorMessage: errorMessage, hasError: hasError, isLoading: isLoading, items: items, loadingMore: loadingMore, name: name, onBack: onBack, onDeleteItem: onDeleteItem, onLoadMore: onLoadMore, onPressItem: onPressItem, onRefresh: onRefresh, onRetry: onRetry, onSearch: onSearch, readonly: readonly, children: _jsx(ErrorBoundary, { children: _jsx(Wrapper, { ...wrapperProps, children: children }) }) }));
22
22
  }
23
- function Header({ variant = EVariantScreenHeader.ROUNDED_HEADER, children, }) {
23
+ function Header({ children, }) {
24
24
  const { name, description, onBack } = useListView();
25
- return (_jsx(ScreenHeader, { onBack: onBack, subtitle: description ? description : `Seleccionar ${name}`, title: name, variant: variant, children: children }));
25
+ return (_jsx(Navigation.AppBar, { onBack: onBack, safeArea: false, subheader: children, subtitle: description ? description : `Seleccionar ${name}`, title: name }));
26
26
  }
27
27
  function HeaderSearch({ searchQuery = "" }) {
28
28
  const { name, onSearch } = useListView();
@@ -42,7 +42,7 @@ function HeaderSearch({ searchQuery = "" }) {
42
42
  if (!onSearch) {
43
43
  return null;
44
44
  }
45
- return (_jsx(View, { className: "px-4 pb-3 mt-2", children: _jsx(Form.SearchBar, { onChangeText: setQuery, placeholder: `Buscar ${name}`, value: query }) }));
45
+ return (_jsx(View, { className: "pb-2", children: _jsx(Navigation.SearchBar, { onChangeText: setQuery, placeholder: `Buscar ${name}`, value: query }) }));
46
46
  }
47
47
  function HeaderActions({ children }) {
48
48
  return (_jsx(View, { className: "flex-row px-4 my-3 items-center justify-between flex-1 gap-2", children: children }));
@@ -50,12 +50,13 @@ function HeaderActions({ children }) {
50
50
  function HeaderFilters({ children }) {
51
51
  return _jsx(View, { className: "px-4 py-2 items-center", children: children });
52
52
  }
53
+ // Modern filter pills (2026): rounded-full, active = accent (green), inactive = muted track.
53
54
  const filterChip = tv({
54
- base: "py-[5px] px-2.5 items-center justify-center rounded-md",
55
+ base: "py-1.5 px-3.5 items-center justify-center rounded-full",
55
56
  variants: {
56
57
  active: {
57
- true: "bg-primary",
58
- false: "bg-transparent",
58
+ true: "bg-accent",
59
+ false: "bg-bg-muted",
59
60
  },
60
61
  },
61
62
  defaultVariants: { active: false },
@@ -63,20 +64,17 @@ const filterChip = tv({
63
64
  const filterChipText = tv({
64
65
  variants: {
65
66
  active: {
66
- true: "text-text-on-primary font-semibold",
67
+ true: "text-text-inverse font-semibold",
67
68
  false: "text-text-secondary",
68
69
  },
69
70
  },
70
71
  defaultVariants: { active: false },
71
72
  });
72
73
  function FilterChip({ label, active = false, onPress }) {
73
- return (_jsx(TouchableOpacity, { activeOpacity: 0.7, className: filterChip({ active }), onPress: onPress, children: _jsxs(Typography.Text, { className: filterChipText({ active }), variant: "bodySmall", children: [active ? "• " : "", label] }) }));
74
+ return (_jsx(TouchableOpacity, { activeOpacity: 0.8, className: filterChip({ active }), onPress: onPress, children: _jsx(Typography.Text, { className: filterChipText({ active }), variant: "bodySmall", children: label }) }));
74
75
  }
75
76
  function FilterChips({ children }) {
76
- const childArray = React.Children.toArray(children);
77
- return (_jsx(ScrollView, { contentContainerStyle: {
78
- paddingHorizontal: 16,
79
- }, horizontal: true, showsHorizontalScrollIndicator: false, style: { flexGrow: 0 }, children: _jsx(View, { className: "flex-row bg-bg-card rounded-[10px] border-[1.5px] border-border-default self-center shadow-sm overflow-hidden", children: childArray.map((child, index) => (_jsxs(View, { className: "flex-row items-center", children: [child, index < childArray.length - 1 && (_jsx(View, { className: "w-[1.5px] h-[22px] bg-border-divider opacity-50 my-0.5" }))] }, index))) }) }));
77
+ return (_jsx(ScrollView, { contentContainerStyle: { paddingHorizontal: 16, gap: 8 }, horizontal: true, showsHorizontalScrollIndicator: false, style: { flexGrow: 0 }, children: children }));
80
78
  }
81
79
  function Content({ children, withMargin = true, }) {
82
80
  const { name, items, isLoading, hasError, errorMessage, onRefresh, onRetry, onBack, showRefreshing, setShowRefreshing, } = useListView();
@@ -107,7 +105,7 @@ function Content({ children, withMargin = true, }) {
107
105
  return (_jsxs(View, { style: { flex: 1 }, children: [_jsx(Display.CountRecords, { count: items.length || 0, name: name }), _jsx(ContentList, { contentWithMargin: withMargin, children: children })] }));
108
106
  }
109
107
  function ContentList({ children, contentWithMargin, }) {
110
- const { items, onRefresh, showRefreshing, setShowRefreshing, onPressItem, onDeleteItem, readonly, } = useListView();
108
+ const { items, onRefresh, showRefreshing, setShowRefreshing, onPressItem, onDeleteItem, readonly, onLoadMore, loadingMore, } = useListView();
111
109
  const rowItems = useMemo(() => toRowItems(items), [items]);
112
110
  const handleRefresh = useCallback(async () => {
113
111
  setShowRefreshing(true);
@@ -129,7 +127,7 @@ function ContentList({ children, contentWithMargin, }) {
129
127
  flex: 1,
130
128
  marginTop: 2,
131
129
  paddingHorizontal: contentWithMargin ? 4 : 0,
132
- }, children: _jsx(FlatList, { data: rowItems, keyExtractor: (item) => String(item.index), refreshControl: _jsx(RefreshControl, { colors: [theme.primary], onRefresh: handleRefresh, refreshing: showRefreshing }), renderItem: renderItem, scrollEnabled: true, showsVerticalScrollIndicator: false }) }));
130
+ }, children: _jsx(FlatList, { data: rowItems, keyExtractor: (item) => String(item.index), ListFooterComponent: loadingMore ? (_jsx(View, { className: "py-4", children: _jsx(Feedback.Spinner, { size: "small" }) })) : null, onEndReached: onLoadMore ? () => onLoadMore() : undefined, onEndReachedThreshold: 0.5, refreshControl: _jsx(RefreshControl, { colors: [theme.primary], onRefresh: handleRefresh, refreshing: showRefreshing }), renderItem: renderItem, scrollEnabled: true, showsVerticalScrollIndicator: false }) }));
133
131
  }
134
132
  function Footer({ children }) {
135
133
  const { items } = useListView();
@@ -4,5 +4,10 @@ interface GeoPermissionCardProps {
4
4
  loading?: boolean;
5
5
  handleRequestPermission?: () => void;
6
6
  }
7
+ /**
8
+ * @deprecated Domain-coupled (geo permission + Spanish copy); relocated to the core.
9
+ * Import from `@sincpro/mobile/ui/components/molecules` instead. Kept here for
10
+ * backwards compatibility and removed in the next major.
11
+ */
7
12
  declare function GeoPermissionCard({ title, loading, handleRequestPermission, hasPermission, }: GeoPermissionCardProps): import("react").JSX.Element;
8
13
  export default GeoPermissionCard;
@@ -7,13 +7,18 @@ import { tv } from "tailwind-variants";
7
7
  const statusTextVariants = tv({
8
8
  variants: {
9
9
  granted: {
10
- true: "text-green-600",
11
- false: "text-red-500",
10
+ true: "text-success",
11
+ false: "text-danger",
12
12
  },
13
13
  },
14
14
  });
15
+ /**
16
+ * @deprecated Domain-coupled (geo permission + Spanish copy); relocated to the core.
17
+ * Import from `@sincpro/mobile/ui/components/molecules` instead. Kept here for
18
+ * backwards compatibility and removed in the next major.
19
+ */
15
20
  function GeoPermissionCard({ title, loading, handleRequestPermission, hasPermission, }) {
16
21
  const granted = hasPermission !== undefined ? hasPermission : false;
17
- return (_jsx(View, { className: "bg-slate-50 rounded-xl p-5 my-2.5 shadow-sm", children: _jsxs(View, { className: "flex-row items-start", children: [_jsx(Display.Icon, { color: granted ? theme.success : theme.danger, name: granted ? "check-circle" : "location-off", size: 35, type: "material" }), _jsxs(View, { className: "ml-2.5 flex-1", children: [_jsx(Typography.Text, { className: "text-base mb-1", semibold: true, children: title }), _jsx(Typography.Text, { className: statusTextVariants({ granted }), children: granted ? "Permiso activo." : "Permiso inactivo." }), !granted && (_jsx(Form.Button, { loading: loading, onPress: handleRequestPermission, size: "small", title: "Abrir Configuración" }))] })] }) }));
22
+ return (_jsx(View, { className: "bg-bg-muted rounded-xl p-5 my-2.5 shadow-sm", children: _jsxs(View, { className: "flex-row items-start", children: [_jsx(Display.Icon, { color: granted ? theme.success : theme.danger, name: granted ? "check-circle" : "location-off", size: 35, type: "material" }), _jsxs(View, { className: "ml-2.5 flex-1", children: [_jsx(Typography.Text, { className: "text-base mb-1", semibold: true, children: title }), _jsx(Typography.Text, { className: statusTextVariants({ granted }), children: granted ? "Permiso activo." : "Permiso inactivo." }), !granted && (_jsx(Form.Button, { loading: loading, onPress: handleRequestPermission, size: "small", title: "Abrir Configuración" }))] })] }) }));
18
23
  }
19
24
  export default GeoPermissionCard;
@@ -1,7 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
2
2
  import { ThemedActivityIndicator } from "../theme";
3
+ import { fontFamilies } from "../theme/typography";
3
4
  import { useMemo, useState } from "react";
4
- import { Platform, Text, View } from "react-native";
5
+ import { Text, View } from "react-native";
5
6
  const parseDeepJson = (value) => {
6
7
  if (typeof value === "string") {
7
8
  try {
@@ -134,11 +135,7 @@ const JsonPreview = ({ selectedJson }) => {
134
135
  return (_jsxs(View, { className: "p-4 items-center justify-center min-h-[200px]", children: [_jsx(ThemedActivityIndicator, { size: "large" }), _jsx(Text, { className: "mt-2 text-text-secondary text-sm", children: "Procesando JSON..." })] }));
135
136
  }
136
137
  return (_jsx(View, { className: "p-4", children: _jsx(Text, { selectable: true, style: {
137
- fontFamily: Platform.select({
138
- ios: "Courier",
139
- android: "monospace",
140
- default: "Courier",
141
- }),
138
+ fontFamily: fontFamilies.mono,
142
139
  fontSize: 13,
143
140
  lineHeight: 18,
144
141
  }, children: coloredLines.map((line, index) => (_jsx(Text, { style: { color: line.color }, children: line.text }, index))) }) }));
@@ -3,5 +3,10 @@ interface TimeZoneSelectorProps {
3
3
  onSelect?: (tz: TimezoneLocale) => void;
4
4
  timezone?: string | null;
5
5
  }
6
+ /**
7
+ * @deprecated Domain/region-coupled (hardcoded LatAm timezones + Spanish copy); relocated
8
+ * to the core. Import from `@sincpro/mobile/ui/components/molecules` instead. Kept here for
9
+ * backwards compatibility and removed in the next major.
10
+ */
6
11
  export declare function TimeZoneSelector({ onSelect, timezone }: TimeZoneSelectorProps): import("react").JSX.Element;
7
12
  export {};
@@ -5,6 +5,11 @@ import { Typography } from "../Typography";
5
5
  import { TimeZoneSelectorModal } from "../widgets/TimeZoneSelectorModal";
6
6
  import { useState } from "react";
7
7
  import { View } from "react-native";
8
+ /**
9
+ * @deprecated Domain/region-coupled (hardcoded LatAm timezones + Spanish copy); relocated
10
+ * to the core. Import from `@sincpro/mobile/ui/components/molecules` instead. Kept here for
11
+ * backwards compatibility and removed in the next major.
12
+ */
8
13
  export function TimeZoneSelector({ onSelect, timezone }) {
9
14
  const [currentTimezone, setCurrentTimezone] = useState(timezone);
10
15
  const [selectorVisible, setSelectorVisible] = useState(false);
@@ -15,5 +20,5 @@ export function TimeZoneSelector({ onSelect, timezone }) {
15
20
  const displayTimezone = currentTimezone
16
21
  ? currentTimezone.replace(/_/g, " ").replace("America/", "")
17
22
  : "No configurada";
18
- return (_jsxs(View, { className: "bg-slate-50 rounded-xl p-5 my-2.5 shadow-sm", children: [_jsxs(View, { className: "flex-row items-start", children: [_jsx(Display.Icon, { color: currentTimezone ? theme.info : theme.text.tertiary, name: "schedule", size: 35, type: "material" }), _jsxs(View, { className: "ml-2.5 flex-1", children: [_jsx(Typography.Text, { className: "text-base mb-1", semibold: true, children: "Zona Horaria" }), currentTimezone ? (_jsxs(View, { className: "mt-2 bg-white rounded-lg p-3", children: [_jsx(Typography.Text, { className: "text-gray-700", semibold: true, children: displayTimezone }), _jsx(Typography.Text, { className: "text-gray-400 text-xs", children: currentTimezone }), _jsx(View, { className: "flex-row gap-2 mt-2", children: _jsx(Form.Button, { onPress: () => setSelectorVisible(true), size: "small", title: "Cambiar", variant: "outline" }) })] })) : (_jsxs(_Fragment, { children: [_jsx(Typography.Text, { className: "text-gray-500 mb-2", children: "Selecciona una zona horaria" }), _jsx(Form.Button, { onPress: () => setSelectorVisible(true), size: "small", title: "Seleccionar Zona Horaria" })] }))] })] }), _jsx(TimeZoneSelectorModal, { currentTimezone: currentTimezone, onClose: () => setSelectorVisible(false), onSelect: handleTimezoneSelected, visible: selectorVisible })] }));
23
+ return (_jsxs(View, { className: "bg-bg-muted rounded-xl p-5 my-2.5 shadow-sm", children: [_jsxs(View, { className: "flex-row items-start", children: [_jsx(Display.Icon, { color: currentTimezone ? theme.info : theme.text.tertiary, name: "schedule", size: 35, type: "material" }), _jsxs(View, { className: "ml-2.5 flex-1", children: [_jsx(Typography.Text, { className: "text-base mb-1", semibold: true, children: "Zona Horaria" }), currentTimezone ? (_jsxs(View, { className: "mt-2 bg-white rounded-lg p-3", children: [_jsx(Typography.Text, { className: "text-text-primary", semibold: true, children: displayTimezone }), _jsx(Typography.Text, { className: "text-text-tertiary text-xs", children: currentTimezone }), _jsx(View, { className: "flex-row gap-2 mt-2", children: _jsx(Form.Button, { onPress: () => setSelectorVisible(true), size: "small", title: "Cambiar", variant: "outline" }) })] })) : (_jsxs(_Fragment, { children: [_jsx(Typography.Text, { className: "text-text-secondary mb-2", children: "Selecciona una zona horaria" }), _jsx(Form.Button, { onPress: () => setSelectorVisible(true), size: "small", title: "Seleccionar Zona Horaria" })] }))] })] }), _jsx(TimeZoneSelectorModal, { currentTimezone: currentTimezone, onClose: () => setSelectorVisible(false), onSelect: handleTimezoneSelected, visible: selectorVisible })] }));
19
24
  }
@@ -5,5 +5,10 @@ interface TimeZoneSelectorModalProps {
5
5
  onSelect: (tz: TimezoneLocale) => void;
6
6
  currentTimezone?: string | null;
7
7
  }
8
+ /**
9
+ * @deprecated Domain/region-coupled (hardcoded LatAm timezones + Spanish copy); relocated
10
+ * to the core. Import from `@sincpro/mobile/ui/components/molecules` instead. Kept here for
11
+ * backwards compatibility and removed in the next major.
12
+ */
8
13
  declare function TimeZoneSelectorModal({ visible, onClose, onSelect, currentTimezone, }: TimeZoneSelectorModalProps): import("react").JSX.Element;
9
14
  export { TimeZoneSelectorModal };
@@ -15,11 +15,16 @@ const TIMEZONES_LOCALES = {
15
15
  japon: { timezone: "Asia/Tokyo", locale: "ja-JP" },
16
16
  };
17
17
  function TimezoneRow({ item, isSelected, onSelect, }) {
18
- return (_jsxs(TouchableOpacity, { activeOpacity: 0.7, className: `flex-row items-center p-4 border-b border-gray-100 ${isSelected ? "bg-blue-50" : "bg-white"}`, onPress: onSelect, children: [_jsx(Display.Icon, { color: isSelected ? theme.info : theme.text.secondary, name: "schedule", size: 24, type: "material" }), _jsxs(View, { className: "ml-3 flex-1", children: [_jsx(Typography.Text, { semibold: true, children: item.label }), _jsx(Typography.Text, { className: "text-gray-400 text-xs", children: item.locale })] }), isSelected && (_jsx(View, { className: "w-6 h-6 rounded-full bg-blue-500 items-center justify-center", children: _jsx(Display.Icon, { color: theme.text.inverse, name: "check", size: 16, type: "material" }) }))] }));
18
+ return (_jsxs(TouchableOpacity, { activeOpacity: 0.7, className: `flex-row items-center p-4 border-b border-border-light ${isSelected ? "bg-info-light" : "bg-white"}`, onPress: onSelect, children: [_jsx(Display.Icon, { color: isSelected ? theme.info : theme.text.secondary, name: "schedule", size: 24, type: "material" }), _jsxs(View, { className: "ml-3 flex-1", children: [_jsx(Typography.Text, { semibold: true, children: item.label }), _jsx(Typography.Text, { className: "text-text-tertiary text-xs", children: item.locale })] }), isSelected && (_jsx(View, { className: "w-6 h-6 rounded-full bg-info items-center justify-center", children: _jsx(Display.Icon, { color: theme.text.inverse, name: "check", size: 16, type: "material" }) }))] }));
19
19
  }
20
20
  function EmptyState() {
21
- return (_jsxs(View, { className: "p-8 items-center justify-center", style: { minHeight: 200 }, children: [_jsx(Display.Icon, { color: theme.text.tertiary, name: "search-off", size: 48, type: "material" }), _jsx(Typography.Text, { className: "text-gray-500 text-center mt-4", children: "No se encontraron zonas horarias" })] }));
21
+ return (_jsxs(View, { className: "p-8 items-center justify-center", style: { minHeight: 200 }, children: [_jsx(Display.Icon, { color: theme.text.tertiary, name: "search-off", size: 48, type: "material" }), _jsx(Typography.Text, { className: "text-text-secondary text-center mt-4", children: "No se encontraron zonas horarias" })] }));
22
22
  }
23
+ /**
24
+ * @deprecated Domain/region-coupled (hardcoded LatAm timezones + Spanish copy); relocated
25
+ * to the core. Import from `@sincpro/mobile/ui/components/molecules` instead. Kept here for
26
+ * backwards compatibility and removed in the next major.
27
+ */
23
28
  function TimeZoneSelectorModal({ visible, onClose, onSelect, currentTimezone, }) {
24
29
  const [query, setQuery] = useState("");
25
30
  const [selectedTimezone, setSelectedTimezone] = useState(currentTimezone || null);
@@ -52,6 +57,6 @@ function TimeZoneSelectorModal({ visible, onClose, onSelect, currentTimezone, })
52
57
  onClose();
53
58
  }
54
59
  }
55
- return (_jsxs(BottomSheet.Root, { onClose: onClose, size: "large", visible: visible, children: [_jsxs(BottomSheet.Header, { children: [_jsxs(View, { className: "px-5 pb-3", children: [_jsx(Typography.Text, { bold: true, variant: "subtitle", children: "Zona Horaria" }), _jsx(Typography.Text, { className: "text-gray-500 text-xs", children: "Selecciona tu zona horaria" })] }), _jsx(View, { className: "px-5 pb-3", children: _jsx(TextInput, { className: "bg-gray-100 px-4 py-3 rounded-xl", onChangeText: setQuery, placeholder: "Buscar zona horaria...", placeholderTextColor: theme.text.tertiary, value: query }) })] }), _jsx(BottomSheet.Content, { scrollable: true, children: filteredTimezones.length === 0 ? (_jsx(EmptyState, {})) : (_jsx(FlatList, { data: filteredTimezones, keyExtractor: (item) => item.timezone, renderItem: ({ item }) => (_jsx(TimezoneRow, { isSelected: selectedTimezone === item.timezone, item: item, onSelect: () => setSelectedTimezone(item.timezone) })), scrollEnabled: false })) }), _jsxs(BottomSheet.Actions, { layout: "horizontal", children: [_jsx(View, { className: "flex-1", children: _jsx(Form.Button, { onPress: onClose, title: "Cancelar", variant: "outline" }) }), selectedTimezone && (_jsx(View, { className: "flex-1", children: _jsx(Form.Button, { onPress: handleConfirm, title: "Confirmar", variant: "primary" }) }))] })] }));
60
+ return (_jsxs(BottomSheet.Root, { onClose: onClose, size: "large", visible: visible, children: [_jsxs(BottomSheet.Header, { children: [_jsxs(View, { className: "px-5 pb-3", children: [_jsx(Typography.Text, { bold: true, variant: "subtitle", children: "Zona Horaria" }), _jsx(Typography.Text, { className: "text-text-secondary text-xs", children: "Selecciona tu zona horaria" })] }), _jsx(View, { className: "px-5 pb-3", children: _jsx(TextInput, { className: "bg-bg-muted px-4 py-3 rounded-xl", onChangeText: setQuery, placeholder: "Buscar zona horaria...", placeholderTextColor: theme.text.tertiary, value: query }) })] }), _jsx(BottomSheet.Content, { scrollable: true, children: filteredTimezones.length === 0 ? (_jsx(EmptyState, {})) : (_jsx(FlatList, { data: filteredTimezones, keyExtractor: (item) => item.timezone, renderItem: ({ item }) => (_jsx(TimezoneRow, { isSelected: selectedTimezone === item.timezone, item: item, onSelect: () => setSelectedTimezone(item.timezone) })), scrollEnabled: false })) }), _jsxs(BottomSheet.Actions, { layout: "horizontal", children: [_jsx(View, { className: "flex-1", children: _jsx(Form.Button, { onPress: onClose, title: "Cancelar", variant: "outline" }) }), selectedTimezone && (_jsx(View, { className: "flex-1", children: _jsx(Form.Button, { onPress: handleConfirm, title: "Confirmar", variant: "primary" }) }))] })] }));
56
61
  }
57
62
  export { TimeZoneSelectorModal };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sincpro/mobile-ui",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Sincpro Mobile design system: generic, presentational React Native components (no domain logic)",
5
5
  "main": "expo/AppEntry.js",
6
6
  "types": "./dist/index.d.ts",
@@ -47,9 +47,13 @@
47
47
  "author": "Gutierrez, Andres <andres.gutierrez@sincpro.com.bo>",
48
48
  "license": "MIT",
49
49
  "peerDependencies": {
50
+ "@expo-google-fonts/fira-code": "*",
51
+ "@expo-google-fonts/inter": "*",
50
52
  "@expo-google-fonts/montserrat": "*",
51
53
  "@expo/ui": "*",
52
54
  "@expo/vector-icons": "*",
55
+ "@react-native-community/datetimepicker": "*",
56
+ "@react-native-community/slider": "*",
53
57
  "expo-checkbox": "*",
54
58
  "expo-clipboard": "*",
55
59
  "expo-linear-gradient": "*",
@@ -63,9 +67,7 @@
63
67
  "react-native-reanimated": "*",
64
68
  "react-native-safe-area-context": "*",
65
69
  "react-native-svg": "*",
66
- "react-native-worklets": "*",
67
- "@react-native-community/slider": "*",
68
- "@react-native-community/datetimepicker": "*"
70
+ "react-native-worklets": "*"
69
71
  },
70
72
  "peerDependenciesMeta": {
71
73
  "@expo/ui": {
@@ -80,10 +82,15 @@
80
82
  "tailwind-variants": "^3.2.2"
81
83
  },
82
84
  "devDependencies": {
85
+ "@expo-google-fonts/fira-code": "^0.4.1",
86
+ "@expo-google-fonts/inter": "^0.4.2",
83
87
  "@expo-google-fonts/montserrat": "^0.4.2",
88
+ "@expo/ui": "~56.0.18",
84
89
  "@expo/vector-icons": "^15.0.3",
90
+ "@gorhom/bottom-sheet": "^5",
85
91
  "@react-native-async-storage/async-storage": "^2",
86
92
  "@react-native-community/datetimepicker": "9.1.0",
93
+ "@react-native-community/slider": "5.2.0",
87
94
  "@storybook/addon-ondevice-actions": "^10.4.6",
88
95
  "@storybook/addon-ondevice-controls": "^10.4.6",
89
96
  "@storybook/react-native": "^10.4.6",
@@ -119,9 +126,7 @@
119
126
  "storybook": "^10.4.6",
120
127
  "tailwindcss": "^3.4.17",
121
128
  "tsc-alias": "^1.8.17",
122
- "typescript": "~6.0.3",
123
- "@expo/ui": "~56.0.18",
124
- "@react-native-community/slider": "5.2.0"
129
+ "typescript": "~6.0.3"
125
130
  },
126
131
  "scripts": {
127
132
  "start": "expo start",