@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.
- package/dist/Dialog/BottomSheet/BottomSheet.Root.d.ts +2 -2
- package/dist/Dialog/BottomSheet/BottomSheet.Root.js +2 -2
- package/dist/Dialog/Dialog.Confirmation.js +5 -1
- package/dist/Dialog/Dialog.EditValue.js +1 -1
- package/dist/Display/Display.GradientSurface.d.ts +116 -0
- package/dist/Display/Display.GradientSurface.js +62 -0
- package/dist/Display/Display.KeyValue.js +1 -1
- package/dist/Display/Display.ListItem.d.ts +5 -1
- package/dist/Display/Display.ListItem.js +6 -2
- package/dist/Display/Display.Monetary.js +1 -1
- package/dist/Display/Display.Pattern.d.ts +26 -0
- package/dist/Display/Display.Pattern.js +27 -0
- package/dist/Display/Display.PriceTag.js +3 -3
- package/dist/Display/Display.Stat.js +1 -1
- package/dist/Display/Display.StatCard.js +1 -1
- package/dist/Display/index.d.ts +4 -0
- package/dist/Display/index.js +4 -0
- package/dist/Feedback/Feedback.DomainSplashScreen.js +3 -2
- package/dist/Feedback/Feedback.Loading.d.ts +6 -0
- package/dist/Feedback/Feedback.Loading.js +7 -1
- package/dist/Feedback/Feedback.Spinner.js +2 -1
- package/dist/Feedback/Feedback.Splash.d.ts +7 -1
- package/dist/Feedback/Feedback.Splash.js +11 -2
- package/dist/Feedback/Toast.context.d.ts +8 -1
- package/dist/Feedback/Toast.context.js +25 -23
- package/dist/Form/Form.Button.d.ts +4 -4
- package/dist/Form/Form.Button.js +19 -19
- package/dist/Form/Form.Checkbox.js +1 -1
- package/dist/Form/Form.Input.js +1 -1
- package/dist/Form/Form.InputField.js +1 -1
- package/dist/Form/Form.Switch.js +1 -1
- package/dist/Navigation/Navigation.AppBar.d.ts +18 -2
- package/dist/Navigation/Navigation.AppBar.js +48 -9
- package/dist/Navigation/Navigation.BottomNav.d.ts +33 -5
- package/dist/Navigation/Navigation.BottomNav.js +90 -17
- package/dist/Navigation/Navigation.SearchBar.js +7 -1
- package/dist/Navigation/Navigation.TabIcon.d.ts +4 -0
- package/dist/Navigation/Navigation.TabIcon.js +4 -0
- package/dist/Navigation/Navigation.TabItem.d.ts +5 -0
- package/dist/Navigation/Navigation.TabItem.js +5 -0
- package/dist/Navigation/index.d.ts +2 -2
- package/dist/Typography/Typography.Text.d.ts +1 -1
- package/dist/Typography/Typography.Text.js +16 -6
- package/dist/icons/OdooIcon.d.ts +5 -0
- package/dist/icons/OdooIcon.js +5 -0
- package/dist/icons/PrinterIcon.d.ts +5 -0
- package/dist/icons/PrinterIcon.js +5 -0
- package/dist/layouts/AuthContainer.js +2 -2
- package/dist/theme/dark.d.ts +3 -3
- package/dist/theme/dark.js +54 -53
- package/dist/theme/default.js +1 -0
- package/dist/theme/index.d.ts +1 -0
- package/dist/theme/index.js +1 -0
- package/dist/theme/types.d.ts +1 -0
- package/dist/theme/typography.d.ts +117 -60
- package/dist/theme/typography.js +115 -29
- package/dist/utils/timezone.d.ts +5 -0
- package/dist/views/FormViewV2.d.ts +2 -1
- package/dist/views/FormViewV2.js +8 -4
- package/dist/views/ListViewV2.context.d.ts +5 -1
- package/dist/views/ListViewV2.context.js +3 -1
- package/dist/views/ListViewV2.d.ts +7 -2
- package/dist/views/ListViewV2.js +18 -20
- package/dist/widgets/GeoPermissionCard.d.ts +5 -0
- package/dist/widgets/GeoPermissionCard.js +8 -3
- package/dist/widgets/JSONViewer.js +3 -6
- package/dist/widgets/TimeZoneSelector.d.ts +5 -0
- package/dist/widgets/TimeZoneSelector.js +6 -1
- package/dist/widgets/TimeZoneSelectorModal.d.ts +5 -0
- package/dist/widgets/TimeZoneSelectorModal.js +8 -3
- package/package.json +12 -7
package/dist/views/FormViewV2.js
CHANGED
|
@@ -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
|
-
|
|
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({
|
|
19
|
+
function Header({ children, }) {
|
|
16
20
|
const { name, description, onBack } = useFormView();
|
|
17
|
-
return (_jsx(
|
|
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({
|
|
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;
|
package/dist/views/ListViewV2.js
CHANGED
|
@@ -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
|
|
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
|
-
? {
|
|
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({
|
|
23
|
+
function Header({ children, }) {
|
|
24
24
|
const { name, description, onBack } = useListView();
|
|
25
|
-
return (_jsx(
|
|
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: "
|
|
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-
|
|
55
|
+
base: "py-1.5 px-3.5 items-center justify-center rounded-full",
|
|
55
56
|
variants: {
|
|
56
57
|
active: {
|
|
57
|
-
true: "bg-
|
|
58
|
-
false: "bg-
|
|
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-
|
|
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.
|
|
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
|
-
|
|
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-
|
|
11
|
-
false: "text-
|
|
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-
|
|
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 {
|
|
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:
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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.
|
|
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",
|