@sincpro/mobile-ui 0.4.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Actions/Actions.Button.d.ts +151 -0
- package/dist/Actions/Actions.Button.js +217 -0
- package/dist/Actions/Actions.FAB.d.ts +10 -0
- package/dist/Actions/Actions.FAB.js +17 -0
- package/dist/Actions/Actions.FilterButton.d.ts +10 -0
- package/dist/Actions/Actions.FilterButton.js +28 -0
- package/dist/Actions/Actions.IconButton.d.ts +67 -0
- package/dist/Actions/Actions.IconButton.js +38 -0
- package/dist/Actions/index.d.ts +22 -0
- package/dist/Actions/index.js +17 -0
- package/dist/Dialog/BottomSheet/BottomSheet.Root.js +1 -0
- package/dist/Dialog/Dialog.Sheet.js +6 -4
- package/dist/Display/Display.CircleButton.d.ts +15 -0
- package/dist/Display/Display.CircleButton.js +39 -0
- package/dist/Display/Display.MenuButton.d.ts +51 -8
- package/dist/Display/Display.MenuButton.js +79 -13
- package/dist/Display/Display.MenuCard.d.ts +15 -0
- package/dist/Display/Display.MenuCard.js +24 -0
- package/dist/Display/Display.MenuGrid.d.ts +19 -0
- package/dist/Display/Display.MenuGrid.js +7 -0
- package/dist/Display/Display.SwipeableRow.js +2 -1
- package/dist/Display/Display.Tooltip.d.ts +1 -1
- package/dist/Display/Display.Tooltip.js +16 -5
- package/dist/Display/index.d.ts +9 -0
- package/dist/Display/index.js +6 -0
- package/dist/Feedback/Feedback.Empty.js +2 -2
- package/dist/Feedback/Feedback.Error.js +2 -2
- package/dist/Feedback/Feedback.Progress.js +2 -2
- package/dist/Feedback/Feedback.Skeleton.js +2 -2
- package/dist/Feedback/Feedback.Splash.js +1 -0
- package/dist/Form/Form.Button.d.ts +3 -151
- package/dist/Form/Form.Button.js +1 -283
- package/dist/Form/Form.FAB.d.ts +3 -10
- package/dist/Form/Form.FAB.js +1 -17
- package/dist/Form/Form.FilterButton.d.ts +3 -12
- package/dist/Form/Form.FilterButton.js +1 -34
- package/dist/Form/Form.IconButton.d.ts +3 -67
- package/dist/Form/Form.IconButton.js +1 -64
- package/dist/Navigation/Navigation.AppBar.d.ts +63 -4
- package/dist/Navigation/Navigation.AppBar.js +70 -18
- package/dist/Navigation/Navigation.BottomNav.js +2 -1
- package/dist/Navigation/Navigation.Header.js +3 -2
- package/dist/Navigation/Navigation.Menu.js +6 -3
- package/dist/Navigation/Navigation.MenuSection.d.ts +19 -0
- package/dist/Navigation/Navigation.MenuSection.js +25 -0
- package/dist/Navigation/Navigation.SegmentedControl.d.ts +15 -1
- package/dist/Navigation/Navigation.SegmentedControl.js +22 -4
- package/dist/Navigation/Navigation.TabIcon.js +1 -2
- package/dist/Navigation/Navigation.TabItem.js +2 -2
- package/dist/Navigation/Navigation.Tabs.d.ts +8 -3
- package/dist/Navigation/Navigation.Tabs.js +19 -6
- package/dist/Navigation/index.d.ts +8 -7
- package/dist/Navigation/index.js +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/layouts/BottomInset.d.ts +16 -0
- package/dist/layouts/BottomInset.js +17 -0
- package/dist/layouts/TabNavigatorLayout.js +2 -2
- package/dist/primitives/BaseButton.js +3 -3
- package/dist/theme/default.js +1 -1
- package/dist/views/FormViewV2.d.ts +99 -9
- package/dist/views/FormViewV2.js +79 -19
- package/dist/views/ListViewV2.d.ts +58 -5
- package/dist/views/ListViewV2.js +58 -11
- package/dist/widgets/CircleButton.d.ts +3 -19
- package/dist/widgets/CircleButton.js +1 -41
- package/dist/widgets/JSONViewer.js +7 -7
- package/dist/widgets/MenuCard.d.ts +3 -13
- package/dist/widgets/MenuCard.js +1 -8
- package/dist/widgets/MenuGrid.d.ts +5 -17
- package/dist/widgets/MenuGrid.js +1 -6
- package/dist/widgets/MenuSection.d.ts +3 -0
- package/dist/widgets/MenuSection.js +1 -0
- package/dist/widgets/PromoBanner.d.ts +38 -0
- package/dist/widgets/PromoBanner.js +61 -0
- package/dist/widgets/PromoModal.d.ts +41 -0
- package/dist/widgets/PromoModal.js +75 -0
- package/dist/widgets/QuickActions.d.ts +26 -0
- package/dist/widgets/QuickActions.js +41 -0
- package/dist/widgets/index.d.ts +11 -1
- package/dist/widgets/index.js +4 -0
- package/package.json +2 -1
package/dist/views/ListViewV2.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "nativewind/jsx-runtime";
|
|
2
2
|
import { Display } from "../Display";
|
|
3
|
+
import SearchHistory from "../Display/Display.SearchHistory";
|
|
3
4
|
import { ErrorBoundary, Feedback } from "../Feedback";
|
|
5
|
+
import { useBottomInset } from "../layouts/BottomInset";
|
|
4
6
|
import Container from "../layouts/Container";
|
|
5
7
|
import { Navigation } from "../Navigation";
|
|
6
|
-
import {
|
|
8
|
+
import { SegmentedControl, } from "../Navigation/Navigation.SegmentedControl";
|
|
9
|
+
import { useTheme } from "../theme";
|
|
7
10
|
import { cn, tv } from "../theme/tw";
|
|
8
11
|
import { Typography } from "../Typography";
|
|
9
12
|
import { ListViewProvider, useListView } from "../views/ListViewV2.context";
|
|
@@ -12,17 +15,15 @@ import { useCallback, useEffect, useMemo, useState } from "react";
|
|
|
12
15
|
import { FlatList, RefreshControl, ScrollView, TouchableOpacity, View, } from "react-native";
|
|
13
16
|
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, }) {
|
|
14
17
|
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
18
|
const wrapperProps = withContainer
|
|
18
19
|
? { edges: ["bottom", "left", "right"] }
|
|
19
20
|
: { className: "flex-1 bg-bg-page" };
|
|
20
21
|
// Propagate contentWithMargin to ContentList via context
|
|
21
22
|
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
23
|
}
|
|
23
|
-
function Header({ children, }) {
|
|
24
|
+
function Header({ variant = "large", tone, actions, children, background, topSpacing, }) {
|
|
24
25
|
const { name, description, onBack } = useListView();
|
|
25
|
-
return (_jsx(Navigation.AppBar, { onBack: onBack, safeArea: false, subheader: children, subtitle: description
|
|
26
|
+
return (_jsx(Navigation.AppBar, { actions: actions, background: background, onBack: onBack, safeArea: false, subheader: children, subtitle: description ?? undefined, title: name, tone: tone, topSpacing: topSpacing, variant: variant }));
|
|
26
27
|
}
|
|
27
28
|
function HeaderSearch({ searchQuery = "" }) {
|
|
28
29
|
const { name, onSearch } = useListView();
|
|
@@ -38,14 +39,32 @@ function HeaderSearch({ searchQuery = "" }) {
|
|
|
38
39
|
if (onSearch && debouncedQuery !== undefined) {
|
|
39
40
|
onSearch(debouncedQuery);
|
|
40
41
|
}
|
|
41
|
-
}, [debouncedQuery]);
|
|
42
|
+
}, [debouncedQuery, onSearch]);
|
|
42
43
|
if (!onSearch) {
|
|
43
44
|
return null;
|
|
44
45
|
}
|
|
45
46
|
return (_jsx(View, { className: "pb-2", children: _jsx(Navigation.SearchBar, { onChangeText: setQuery, placeholder: `Buscar ${name}`, value: query }) }));
|
|
46
47
|
}
|
|
47
48
|
function HeaderActions({ children }) {
|
|
48
|
-
return (_jsx(View, { className: "flex-row px-4 my-
|
|
49
|
+
return (_jsx(View, { className: "flex-row px-4 my-2 items-center justify-between flex-1 gap-2", children: children }));
|
|
50
|
+
}
|
|
51
|
+
/** Secondary action bar docked below the AppBar — use for Save/Cancel, filter chips, etc. */
|
|
52
|
+
function HeaderActionsBar({ children }) {
|
|
53
|
+
return (_jsx(View, { className: "bg-bg-card px-4 pt-1 pb-3 border-b border-border-light flex-row gap-2 items-center", children: children }));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Tab-like segmented switch for the header subheader (e.g. "Activos" / "Archivados").
|
|
57
|
+
* Use as a child of `<ListViewV2.Header>` — it lands in the AppBar subheader slot.
|
|
58
|
+
*/
|
|
59
|
+
function HeaderSegmented(props) {
|
|
60
|
+
return _jsx(SegmentedControl, { ...props });
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Recent-searches list. Render as a SIBLING of the Header (like Filters/ActionsBar) —
|
|
64
|
+
* typically while the search query is empty. Delegates to `Display.SearchHistory`.
|
|
65
|
+
*/
|
|
66
|
+
function HeaderSearchHistory(props) {
|
|
67
|
+
return _jsx(SearchHistory, { ...props });
|
|
49
68
|
}
|
|
50
69
|
function HeaderFilters({ children }) {
|
|
51
70
|
return _jsx(View, { className: "px-4 py-2 items-center", children: children });
|
|
@@ -78,6 +97,8 @@ function FilterChips({ children }) {
|
|
|
78
97
|
}
|
|
79
98
|
function Content({ children, withMargin = true, }) {
|
|
80
99
|
const { name, items, isLoading, hasError, errorMessage, onRefresh, onRetry, onBack, showRefreshing, setShowRefreshing, } = useListView();
|
|
100
|
+
const bottomInset = useBottomInset();
|
|
101
|
+
const theme = useTheme();
|
|
81
102
|
const handleRefresh = useCallback(async () => {
|
|
82
103
|
setShowRefreshing(true);
|
|
83
104
|
if (onRefresh) {
|
|
@@ -93,19 +114,23 @@ function Content({ children, withMargin = true, }) {
|
|
|
93
114
|
flexGrow: 1,
|
|
94
115
|
justifyContent: "center",
|
|
95
116
|
alignItems: "center",
|
|
96
|
-
|
|
117
|
+
paddingBottom: bottomInset,
|
|
118
|
+
}, refreshControl: _jsx(RefreshControl, { colors: [theme.primary], onRefresh: handleRefresh, refreshing: showRefreshing }), style: { backgroundColor: theme.bg.page }, children: _jsx(Feedback.Error, { message: errorMessage, onBack: onBack, onRetry: onRetry }) }));
|
|
97
119
|
}
|
|
98
120
|
if (items.length === 0) {
|
|
99
121
|
return (_jsx(ScrollView, { contentContainerStyle: {
|
|
100
122
|
flexGrow: 1,
|
|
101
123
|
justifyContent: "center",
|
|
102
124
|
alignItems: "center",
|
|
103
|
-
|
|
125
|
+
paddingBottom: bottomInset,
|
|
126
|
+
}, refreshControl: _jsx(RefreshControl, { colors: [theme.primary], onRefresh: handleRefresh, refreshing: showRefreshing }), style: { backgroundColor: theme.bg.page }, children: _jsx(Feedback.Empty, {}) }));
|
|
104
127
|
}
|
|
105
|
-
return (_jsxs(View, { style: { flex: 1 }, children: [_jsx(Display.CountRecords, { count: items.length || 0, name: name }), _jsx(ContentList, { contentWithMargin: withMargin, children: children })] }));
|
|
128
|
+
return (_jsxs(View, { style: { flex: 1, backgroundColor: theme.bg.page }, children: [_jsx(Display.CountRecords, { count: items.length || 0, name: name }), _jsx(ContentList, { contentWithMargin: withMargin, children: children })] }));
|
|
106
129
|
}
|
|
107
130
|
function ContentList({ children, contentWithMargin, }) {
|
|
108
131
|
const { items, onRefresh, showRefreshing, setShowRefreshing, onPressItem, onDeleteItem, readonly, onLoadMore, loadingMore, } = useListView();
|
|
132
|
+
const bottomInset = useBottomInset();
|
|
133
|
+
const theme = useTheme();
|
|
109
134
|
const rowItems = useMemo(() => toRowItems(items), [items]);
|
|
110
135
|
const handleRefresh = useCallback(async () => {
|
|
111
136
|
setShowRefreshing(true);
|
|
@@ -127,7 +152,8 @@ function ContentList({ children, contentWithMargin, }) {
|
|
|
127
152
|
flex: 1,
|
|
128
153
|
marginTop: 2,
|
|
129
154
|
paddingHorizontal: contentWithMargin ? 4 : 0,
|
|
130
|
-
|
|
155
|
+
backgroundColor: theme.bg.page,
|
|
156
|
+
}, children: _jsx(FlatList, { contentContainerStyle: bottomInset ? { paddingBottom: bottomInset } : undefined, 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 }) }));
|
|
131
157
|
}
|
|
132
158
|
function Footer({ children }) {
|
|
133
159
|
const { items } = useListView();
|
|
@@ -178,7 +204,10 @@ const FiltersWithSubComponents = Object.assign(HeaderFilters, {
|
|
|
178
204
|
});
|
|
179
205
|
const HeaderWithSubComponents = Object.assign(Header, {
|
|
180
206
|
Search: HeaderSearch,
|
|
207
|
+
SearchHistory: HeaderSearchHistory,
|
|
208
|
+
Segmented: HeaderSegmented,
|
|
181
209
|
Actions: HeaderActions,
|
|
210
|
+
ActionsBar: HeaderActionsBar,
|
|
182
211
|
Filters: FiltersWithSubComponents,
|
|
183
212
|
});
|
|
184
213
|
const RowWithSubComponents = Object.assign(RowRoot, {
|
|
@@ -194,6 +223,24 @@ const ContentWithSubComponents = Object.assign(Content, {
|
|
|
194
223
|
List: ContentList,
|
|
195
224
|
Row: RowWithSubComponents,
|
|
196
225
|
});
|
|
226
|
+
/**
|
|
227
|
+
* Screen container for a collection (list / index / search results).
|
|
228
|
+
* Owns safe-area, the FlatList (pagination + pull-to-refresh), record count, and the
|
|
229
|
+
* loading/empty/error states.
|
|
230
|
+
*
|
|
231
|
+
* API map:
|
|
232
|
+
* ListViewV2.Root — provider + container; pass `items`, `onSearch`, `onLoadMore`, `onBack`…
|
|
233
|
+
* ListViewV2.Header — AppBar (variant: default | large | center · tone: default | dark | gradient)
|
|
234
|
+
* .Header.Search — debounced SearchBar in the subheader (wires `onSearch`)
|
|
235
|
+
* .Header.SearchHistory — recent-searches list (SIBLING; show while query is empty)
|
|
236
|
+
* .Header.Segmented — tab-like switch in the subheader (Activos / Archivados)
|
|
237
|
+
* .Header.Filters(.Chips/.Chip) — horizontal filter pills (SIBLING below the header)
|
|
238
|
+
* .Header.ActionsBar — SIBLING bar below the header (bulk select, etc.)
|
|
239
|
+
* ListViewV2.Content — FlatList body; `children` is an optional custom row renderer
|
|
240
|
+
* .Content.Row(.Avatar/.Content/.Title/.Subtitle/.Footer/.Actions/.ActionButton)
|
|
241
|
+
* ListViewV2.Footer — pinned footer (hidden when empty)
|
|
242
|
+
* ListViewV2.FloatingButton — absolute FAB overlay
|
|
243
|
+
*/
|
|
197
244
|
export const ListViewV2 = {
|
|
198
245
|
Root: ListViewRoot,
|
|
199
246
|
Header: HeaderWithSubComponents,
|
|
@@ -1,19 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
iconType?: IconType;
|
|
5
|
-
size?: "sm" | "md" | "lg";
|
|
6
|
-
color?: string;
|
|
7
|
-
variant?: "primary" | "secondary" | "accent" | "success" | "danger" | "warning";
|
|
8
|
-
className?: string;
|
|
9
|
-
customIcon?: ComponentType<{
|
|
10
|
-
size?: number;
|
|
11
|
-
color?: string;
|
|
12
|
-
}>;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* @deprecated Duplicates the icon-button. Use `Form.IconButton` (general) or
|
|
16
|
-
* `Navigation.AppBar.Action` (headers). Kept for backwards compatibility.
|
|
17
|
-
*/
|
|
18
|
-
export declare function CircleButton({ iconType, size, color, variant, className, customIcon, }: CircleButtonProps): React.JSX.Element;
|
|
19
|
-
export {};
|
|
1
|
+
/** @deprecated Import from `@sincpro/mobile-ui/Display` → `Display.CircleButton` instead. */
|
|
2
|
+
export type { CircleButtonProps } from "../Display/Display.CircleButton";
|
|
3
|
+
export { CircleButton } from "../Display/Display.CircleButton";
|
|
@@ -1,41 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { Display } from "../Display";
|
|
3
|
-
import { theme } from "../theme";
|
|
4
|
-
import { cn } from "../theme/tw";
|
|
5
|
-
import { View } from "react-native";
|
|
6
|
-
import { tv } from "tailwind-variants";
|
|
7
|
-
const circleButtonVariants = tv({
|
|
8
|
-
base: "rounded-full items-center justify-center shadow-sm",
|
|
9
|
-
variants: {
|
|
10
|
-
size: {
|
|
11
|
-
sm: "w-12 h-12", // 48px
|
|
12
|
-
md: "w-15 h-15", // 60px
|
|
13
|
-
lg: "w-20 h-20", // 80px
|
|
14
|
-
},
|
|
15
|
-
variant: {
|
|
16
|
-
primary: "bg-primary",
|
|
17
|
-
secondary: "bg-secondary",
|
|
18
|
-
accent: "bg-accent",
|
|
19
|
-
success: "bg-success",
|
|
20
|
-
danger: "bg-danger",
|
|
21
|
-
warning: "bg-warning",
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
defaultVariants: {
|
|
25
|
-
size: "md",
|
|
26
|
-
variant: "accent",
|
|
27
|
-
},
|
|
28
|
-
});
|
|
29
|
-
const SIZE_MAP = {
|
|
30
|
-
sm: { container: 48, icon: 24 },
|
|
31
|
-
md: { container: 60, icon: 30 },
|
|
32
|
-
lg: { container: 80, icon: 40 },
|
|
33
|
-
};
|
|
34
|
-
/**
|
|
35
|
-
* @deprecated Duplicates the icon-button. Use `Form.IconButton` (general) or
|
|
36
|
-
* `Navigation.AppBar.Action` (headers). Kept for backwards compatibility.
|
|
37
|
-
*/
|
|
38
|
-
export function CircleButton({ iconType = "ionicons", size = "md", color = theme.text.inverse, variant = "accent", className, customIcon, }) {
|
|
39
|
-
const iconSize = SIZE_MAP[size].icon;
|
|
40
|
-
return (_jsx(View, { className: cn(circleButtonVariants({ size, variant }), className), children: _jsx(Display.Icon, { color: color, customIcon: customIcon, size: iconSize, type: iconType }) }));
|
|
41
|
-
}
|
|
1
|
+
export { CircleButton } from "../Display/Display.CircleButton";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
2
|
import { ThemedActivityIndicator } from "../theme";
|
|
3
3
|
import { fontFamilies } from "../theme/typography";
|
|
4
|
-
import { useMemo, useState } from "react";
|
|
4
|
+
import { useEffect, useMemo, useState } from "react";
|
|
5
5
|
import { Text, View } from "react-native";
|
|
6
6
|
const parseDeepJson = (value) => {
|
|
7
7
|
if (typeof value === "string") {
|
|
@@ -116,19 +116,19 @@ const JsonPreview = ({ selectedJson }) => {
|
|
|
116
116
|
}, [selectedJson]);
|
|
117
117
|
// Guard 4: colorize with processing control
|
|
118
118
|
const coloredLines = useMemo(() => {
|
|
119
|
-
setIsProcessing(true);
|
|
120
119
|
try {
|
|
121
120
|
return parseJsonToColoredLines(formattedJson);
|
|
122
121
|
}
|
|
123
122
|
catch (error) {
|
|
124
123
|
console.warn("[JSONViewer] Error coloring JSON:", error);
|
|
125
|
-
// Fallback a texto plano si falla el coloreado
|
|
126
124
|
return [{ text: formattedJson, color: "#333333" }];
|
|
127
125
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
}, [formattedJson]);
|
|
127
|
+
useEffect(() => {
|
|
128
|
+
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
129
|
+
setIsProcessing(true);
|
|
130
|
+
const t = setTimeout(() => setIsProcessing(false), 50);
|
|
131
|
+
return () => clearTimeout(t);
|
|
132
132
|
}, [formattedJson]);
|
|
133
133
|
// Guard 5: show loading while processing large JSON
|
|
134
134
|
if (isProcessing && formattedJson.length > 50_000) {
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
title: string;
|
|
5
|
-
iconType?: IconType;
|
|
6
|
-
onPress?: () => void;
|
|
7
|
-
customIcon?: ComponentType<{
|
|
8
|
-
size?: number;
|
|
9
|
-
color?: string;
|
|
10
|
-
}>;
|
|
11
|
-
}
|
|
12
|
-
export declare function MenuCard({ title, iconType, onPress, customIcon, }: MenuCardProps): import("react").JSX.Element;
|
|
13
|
-
export {};
|
|
1
|
+
/** @deprecated Import from `@sincpro/mobile-ui/Display` → `Display.MenuCard` instead. */
|
|
2
|
+
export type { MenuCardProps } from "../Display/Display.MenuCard";
|
|
3
|
+
export { MenuCard } from "../Display/Display.MenuCard";
|
package/dist/widgets/MenuCard.js
CHANGED
|
@@ -1,8 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { theme } from "../theme/useTheme";
|
|
3
|
-
import { Typography } from "../Typography";
|
|
4
|
-
import { CircleButton } from "../widgets/CircleButton";
|
|
5
|
-
import { TouchableOpacity, View } from "react-native";
|
|
6
|
-
export function MenuCard({ title, iconType = "ionicons", onPress, customIcon, }) {
|
|
7
|
-
return (_jsx(TouchableOpacity, { activeOpacity: 0.7, className: "bg-bg-card rounded-2xl p-4 m-2 w-[45%] shadow-sm", onPress: onPress, style: theme.shadow["sm"], children: _jsxs(View, { className: "items-center justify-center", children: [_jsx(CircleButton, { customIcon: customIcon, iconType: iconType }), _jsx(Typography.Text, { className: "text-text-primary mt-3 text-center", variant: "label", children: title })] }) }));
|
|
8
|
-
}
|
|
1
|
+
export { MenuCard } from "../Display/Display.MenuCard";
|
|
@@ -1,17 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
iconType?: IconType;
|
|
7
|
-
onPress?: () => void;
|
|
8
|
-
customIcon?: ComponentType<{
|
|
9
|
-
size?: number;
|
|
10
|
-
color?: string;
|
|
11
|
-
}>;
|
|
12
|
-
}
|
|
13
|
-
interface MenuGridProps {
|
|
14
|
-
readonly items: MenuItem[];
|
|
15
|
-
}
|
|
16
|
-
export declare const MenuGrid: React.FC<MenuGridProps>;
|
|
17
|
-
export {};
|
|
1
|
+
/** @deprecated Import from `@sincpro/mobile-ui/Display` → `Display.MenuGrid` instead. */
|
|
2
|
+
export type { MenuGridItem, MenuGridProps, } from "../Display/Display.MenuGrid";
|
|
3
|
+
export { MenuGrid } from "../Display/Display.MenuGrid";
|
|
4
|
+
/** @deprecated Renamed to `MenuGridItem`. */
|
|
5
|
+
export type { MenuGridItem as MenuItem } from "../Display/Display.MenuGrid";
|
package/dist/widgets/MenuGrid.js
CHANGED
|
@@ -1,6 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { MenuCard } from "../widgets/MenuCard";
|
|
3
|
-
import { View } from "react-native";
|
|
4
|
-
export const MenuGrid = ({ items }) => {
|
|
5
|
-
return (_jsx(View, { className: "flex-row flex-wrap justify-start p-2 bg-bg-page", children: items.map((item) => (_jsx(MenuCard, { customIcon: item.customIcon, iconType: item.iconType, onPress: item.onPress, title: item.title }, item.id))) }));
|
|
6
|
-
};
|
|
1
|
+
export { MenuGrid } from "../Display/Display.MenuGrid";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MenuSection } from "../Navigation/Navigation.MenuSection";
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ComponentType } from "react";
|
|
2
|
+
export interface PromoBannerItem {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
subtitle?: string;
|
|
6
|
+
/** Left accent icon. */
|
|
7
|
+
icon?: ComponentType<{
|
|
8
|
+
size?: number;
|
|
9
|
+
color?: string;
|
|
10
|
+
}>;
|
|
11
|
+
/** Gradient color stops for the card surface. */
|
|
12
|
+
gradient?: readonly [string, string, ...string[]];
|
|
13
|
+
/** Accent color for the CTA button and badge. Defaults to `theme.accent`. */
|
|
14
|
+
accentColor?: string;
|
|
15
|
+
ctaLabel?: string;
|
|
16
|
+
onPress?: () => void;
|
|
17
|
+
/** Small badge text (e.g. "Nuevo", "Promo"). */
|
|
18
|
+
badge?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface PromoBannerProps {
|
|
21
|
+
items: PromoBannerItem[];
|
|
22
|
+
/** Section heading above the banners row. */
|
|
23
|
+
title?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Horizontal scrollable row of promotional/announcement cards.
|
|
27
|
+
* Each card supports gradient surfaces, icon, badge, title, subtitle, and a CTA button.
|
|
28
|
+
*
|
|
29
|
+
* Usage:
|
|
30
|
+
* <PromoBanner
|
|
31
|
+
* title="Destacados"
|
|
32
|
+
* items={[
|
|
33
|
+
* { id: "1", title: "Nueva ruta", subtitle: "Servicio express", badge: "Nuevo",
|
|
34
|
+
* gradient: ["#0D2B1F", "#00C357"], ctaLabel: "Ver más", onPress: ... },
|
|
35
|
+
* ]}
|
|
36
|
+
* />
|
|
37
|
+
*/
|
|
38
|
+
export declare function PromoBanner({ items, title }: PromoBannerProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
+
import GradientSurface from "../Display/Display.GradientSurface";
|
|
3
|
+
import { useTheme } from "../theme";
|
|
4
|
+
import { Typography } from "../Typography";
|
|
5
|
+
import { ScrollView, TouchableOpacity, View } from "react-native";
|
|
6
|
+
function BannerCard({ item }) {
|
|
7
|
+
const theme = useTheme();
|
|
8
|
+
const accent = item.accentColor ?? theme.accent;
|
|
9
|
+
const hasGradient = !!item.gradient;
|
|
10
|
+
const Icon = item.icon;
|
|
11
|
+
const textColor = hasGradient ? "#FFFFFF" : theme.text.primary;
|
|
12
|
+
const subtextColor = hasGradient ? "rgba(255,255,255,0.75)" : theme.text.secondary;
|
|
13
|
+
return (_jsxs(TouchableOpacity, { activeOpacity: 0.85, onPress: item.onPress, style: {
|
|
14
|
+
width: 280,
|
|
15
|
+
borderRadius: 16,
|
|
16
|
+
overflow: "hidden",
|
|
17
|
+
marginRight: 12,
|
|
18
|
+
backgroundColor: hasGradient ? "transparent" : theme.bg.card,
|
|
19
|
+
borderWidth: hasGradient ? 0 : 1,
|
|
20
|
+
borderColor: theme.border.default,
|
|
21
|
+
...theme.shadow.md,
|
|
22
|
+
}, children: [hasGradient ? (_jsx(GradientSurface, { colors: item.gradient, padding: "none", radius: "none", style: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0 } })) : null, _jsxs(View, { style: { padding: 16 }, children: [item.badge ? (_jsx(View, { style: {
|
|
23
|
+
alignSelf: "flex-start",
|
|
24
|
+
backgroundColor: accent,
|
|
25
|
+
borderRadius: 999,
|
|
26
|
+
paddingHorizontal: 10,
|
|
27
|
+
paddingVertical: 3,
|
|
28
|
+
marginBottom: 10,
|
|
29
|
+
}, children: _jsx(Typography.Text, { semibold: true, style: { color: "#FFFFFF", fontSize: 11 }, variant: "caption", children: item.badge }) })) : null, _jsxs(View, { style: { flexDirection: "row", alignItems: "center", gap: 12 }, children: [Icon ? (_jsx(View, { style: {
|
|
30
|
+
width: 48,
|
|
31
|
+
height: 48,
|
|
32
|
+
borderRadius: 12,
|
|
33
|
+
backgroundColor: hasGradient ? "rgba(255,255,255,0.15)" : theme.bg.muted,
|
|
34
|
+
alignItems: "center",
|
|
35
|
+
justifyContent: "center",
|
|
36
|
+
}, children: _jsx(Icon, { color: hasGradient ? "#FFFFFF" : theme.icon.primary, size: 24 }) })) : null, _jsxs(View, { style: { flex: 1 }, children: [_jsx(Typography.Text, { semibold: true, style: { color: textColor }, variant: "subtitle", children: item.title }), item.subtitle ? (_jsx(Typography.Text, { style: { color: subtextColor, marginTop: 2 }, variant: "bodySmall", children: item.subtitle })) : null] })] }), item.ctaLabel ? (_jsx(View, { style: {
|
|
37
|
+
marginTop: 14,
|
|
38
|
+
alignSelf: "flex-start",
|
|
39
|
+
backgroundColor: hasGradient ? "rgba(255,255,255,0.2)" : accent,
|
|
40
|
+
borderRadius: 999,
|
|
41
|
+
paddingHorizontal: 16,
|
|
42
|
+
paddingVertical: 7,
|
|
43
|
+
}, children: _jsx(Typography.Text, { semibold: true, style: { color: hasGradient ? "#FFFFFF" : theme.text.onAccent, fontSize: 13 }, variant: "bodySmall", children: item.ctaLabel }) })) : null] })] }));
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Horizontal scrollable row of promotional/announcement cards.
|
|
47
|
+
* Each card supports gradient surfaces, icon, badge, title, subtitle, and a CTA button.
|
|
48
|
+
*
|
|
49
|
+
* Usage:
|
|
50
|
+
* <PromoBanner
|
|
51
|
+
* title="Destacados"
|
|
52
|
+
* items={[
|
|
53
|
+
* { id: "1", title: "Nueva ruta", subtitle: "Servicio express", badge: "Nuevo",
|
|
54
|
+
* gradient: ["#0D2B1F", "#00C357"], ctaLabel: "Ver más", onPress: ... },
|
|
55
|
+
* ]}
|
|
56
|
+
* />
|
|
57
|
+
*/
|
|
58
|
+
export function PromoBanner({ items, title }) {
|
|
59
|
+
const theme = useTheme();
|
|
60
|
+
return (_jsxs(View, { children: [title ? (_jsx(Typography.Text, { semibold: true, style: { color: theme.text.secondary, marginBottom: 10, paddingHorizontal: 16 }, variant: "caption", children: title.toUpperCase() })) : null, _jsx(ScrollView, { contentContainerStyle: { paddingHorizontal: 16, paddingVertical: 2 }, horizontal: true, showsHorizontalScrollIndicator: false, children: items.map((item) => (_jsx(BannerCard, { item: item }, item.id))) })] }));
|
|
61
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ComponentType } from "react";
|
|
2
|
+
export interface PromoModalProps {
|
|
3
|
+
visible: boolean;
|
|
4
|
+
onDismiss: () => void;
|
|
5
|
+
title: string;
|
|
6
|
+
body?: string;
|
|
7
|
+
/** Optional icon rendered at the top of the card. */
|
|
8
|
+
icon?: ComponentType<{
|
|
9
|
+
size?: number;
|
|
10
|
+
color?: string;
|
|
11
|
+
}>;
|
|
12
|
+
/** Gradient for the icon header area (top strip). */
|
|
13
|
+
headerGradient?: readonly [string, string, ...string[]];
|
|
14
|
+
/** Primary CTA label. */
|
|
15
|
+
ctaLabel?: string;
|
|
16
|
+
onPressCta?: () => void;
|
|
17
|
+
/** Secondary link/dismiss label. Defaults to "Ahora no". */
|
|
18
|
+
dismissLabel?: string;
|
|
19
|
+
/** Badge chip text above the title (e.g. "Novedad", "Oferta"). */
|
|
20
|
+
badge?: string;
|
|
21
|
+
/** Accent color for the CTA button and badge. */
|
|
22
|
+
accentColor?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Bottom-anchored modal for news, promotions, or announcements.
|
|
26
|
+
* Tapping outside (backdrop) also dismisses it.
|
|
27
|
+
*
|
|
28
|
+
* Usage:
|
|
29
|
+
* <PromoModal
|
|
30
|
+
* visible={showPromo}
|
|
31
|
+
* onDismiss={() => setShowPromo(false)}
|
|
32
|
+
* title="Nueva función disponible"
|
|
33
|
+
* body="Ahora puedes filtrar rutas por color directamente desde el panel principal."
|
|
34
|
+
* badge="Novedad"
|
|
35
|
+
* headerGradient={["#022B14", "#065E2B"]}
|
|
36
|
+
* icon={BellIcon}
|
|
37
|
+
* ctaLabel="Explorar"
|
|
38
|
+
* onPressCta={handleExplore}
|
|
39
|
+
* />
|
|
40
|
+
*/
|
|
41
|
+
export declare function PromoModal({ visible, onDismiss, title, body, icon: Icon, headerGradient, ctaLabel, onPressCta, dismissLabel, badge, accentColor, }: PromoModalProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
+
import GradientSurface from "../Display/Display.GradientSurface";
|
|
3
|
+
import { useTheme } from "../theme";
|
|
4
|
+
import { Typography } from "../Typography";
|
|
5
|
+
import { Modal, TouchableOpacity, TouchableWithoutFeedback, View } from "react-native";
|
|
6
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
7
|
+
/**
|
|
8
|
+
* Bottom-anchored modal for news, promotions, or announcements.
|
|
9
|
+
* Tapping outside (backdrop) also dismisses it.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* <PromoModal
|
|
13
|
+
* visible={showPromo}
|
|
14
|
+
* onDismiss={() => setShowPromo(false)}
|
|
15
|
+
* title="Nueva función disponible"
|
|
16
|
+
* body="Ahora puedes filtrar rutas por color directamente desde el panel principal."
|
|
17
|
+
* badge="Novedad"
|
|
18
|
+
* headerGradient={["#022B14", "#065E2B"]}
|
|
19
|
+
* icon={BellIcon}
|
|
20
|
+
* ctaLabel="Explorar"
|
|
21
|
+
* onPressCta={handleExplore}
|
|
22
|
+
* />
|
|
23
|
+
*/
|
|
24
|
+
export function PromoModal({ visible, onDismiss, title, body, icon: Icon, headerGradient, ctaLabel, onPressCta, dismissLabel = "Ahora no", badge, accentColor, }) {
|
|
25
|
+
const theme = useTheme();
|
|
26
|
+
const insets = useSafeAreaInsets();
|
|
27
|
+
const accent = accentColor ?? theme.accent;
|
|
28
|
+
return (_jsxs(Modal, { animationType: "fade", onRequestClose: onDismiss, statusBarTranslucent: true, transparent: true, visible: visible, children: [_jsx(TouchableWithoutFeedback, { onPress: onDismiss, children: _jsx(View, { style: {
|
|
29
|
+
flex: 1,
|
|
30
|
+
backgroundColor: "rgba(0,0,0,0.55)",
|
|
31
|
+
alignItems: "center",
|
|
32
|
+
justifyContent: "center",
|
|
33
|
+
paddingHorizontal: 24,
|
|
34
|
+
paddingVertical: insets.top + 16,
|
|
35
|
+
} }) }), _jsx(View, { pointerEvents: "box-none", style: {
|
|
36
|
+
position: "absolute",
|
|
37
|
+
top: 0,
|
|
38
|
+
left: 0,
|
|
39
|
+
right: 0,
|
|
40
|
+
bottom: 0,
|
|
41
|
+
alignItems: "center",
|
|
42
|
+
justifyContent: "center",
|
|
43
|
+
paddingHorizontal: 24,
|
|
44
|
+
}, children: _jsxs(View, { style: {
|
|
45
|
+
backgroundColor: theme.bg.card,
|
|
46
|
+
borderRadius: 28,
|
|
47
|
+
borderWidth: 1,
|
|
48
|
+
borderColor: theme.border.default,
|
|
49
|
+
width: "100%",
|
|
50
|
+
maxWidth: 400,
|
|
51
|
+
overflow: "hidden",
|
|
52
|
+
}, children: [headerGradient || Icon ? (_jsxs(View, { style: { height: 120, justifyContent: "center", alignItems: "center" }, children: [headerGradient ? (_jsx(GradientSurface, { colors: headerGradient, padding: "none", radius: "none", style: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0 } })) : null, Icon ? (_jsx(View, { style: {
|
|
53
|
+
width: 64,
|
|
54
|
+
height: 64,
|
|
55
|
+
borderRadius: 20,
|
|
56
|
+
backgroundColor: "rgba(255,255,255,0.18)",
|
|
57
|
+
alignItems: "center",
|
|
58
|
+
justifyContent: "center",
|
|
59
|
+
}, children: _jsx(Icon, { color: "#FFFFFF", size: 32 }) })) : null] })) : null, _jsxs(View, { style: { paddingHorizontal: 24, paddingTop: 12, paddingBottom: 8 }, children: [badge ? (_jsx(View, { style: {
|
|
60
|
+
alignSelf: "flex-start",
|
|
61
|
+
backgroundColor: accent,
|
|
62
|
+
borderRadius: 999,
|
|
63
|
+
paddingHorizontal: 12,
|
|
64
|
+
paddingVertical: 4,
|
|
65
|
+
marginBottom: 12,
|
|
66
|
+
}, children: _jsx(Typography.Text, { semibold: true, style: { color: theme.text.onAccent, fontSize: 11 }, variant: "caption", children: badge }) })) : null, _jsx(Typography.Text, { semibold: true, style: { color: theme.text.primary }, variant: "h3", children: title }), body ? (_jsx(Typography.Text, { style: { color: theme.text.secondary, marginTop: 8, lineHeight: 22 }, variant: "body", children: body })) : null] }), _jsxs(View, { style: { paddingHorizontal: 24, paddingTop: 16, gap: 10 }, children: [ctaLabel ? (_jsx(TouchableOpacity, { activeOpacity: 0.8, onPress: () => {
|
|
67
|
+
onPressCta?.();
|
|
68
|
+
onDismiss();
|
|
69
|
+
}, style: {
|
|
70
|
+
backgroundColor: accent,
|
|
71
|
+
borderRadius: 14,
|
|
72
|
+
paddingVertical: 15,
|
|
73
|
+
alignItems: "center",
|
|
74
|
+
}, children: _jsx(Typography.Text, { semibold: true, style: { color: theme.text.onAccent }, variant: "body", children: ctaLabel }) })) : null, _jsx(TouchableOpacity, { activeOpacity: 0.7, onPress: onDismiss, style: { alignItems: "center", paddingVertical: 12 }, children: _jsx(Typography.Text, { style: { color: theme.text.secondary }, variant: "body", children: dismissLabel }) })] })] }) })] }));
|
|
75
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ComponentType } from "react";
|
|
2
|
+
export interface QuickActionItem {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
/** Ionicon name — use this OR `customIcon`. */
|
|
6
|
+
icon?: string;
|
|
7
|
+
customIcon?: ComponentType<{
|
|
8
|
+
size?: number;
|
|
9
|
+
color?: string;
|
|
10
|
+
}>;
|
|
11
|
+
badge?: string | number;
|
|
12
|
+
onPress?: () => void;
|
|
13
|
+
/** Circle background color override. Defaults to `theme.bg.muted`. */
|
|
14
|
+
color?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface QuickActionsProps {
|
|
17
|
+
items: QuickActionItem[];
|
|
18
|
+
/** Section heading rendered above the row. */
|
|
19
|
+
title?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Horizontal scrollable row of small icon+label shortcuts ("Acciones Rápidas").
|
|
23
|
+
* Each item renders a 48 px icon circle + optional badge + label below.
|
|
24
|
+
* Scroll is horizontal and indicator-free for a clean look.
|
|
25
|
+
*/
|
|
26
|
+
export declare function QuickActions({ items, title }: QuickActionsProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
+
import Icon from "../Display/Display.Icon";
|
|
3
|
+
import { useTheme } from "../theme";
|
|
4
|
+
import { Typography } from "../Typography";
|
|
5
|
+
import { ScrollView, TouchableOpacity, View } from "react-native";
|
|
6
|
+
/**
|
|
7
|
+
* Horizontal scrollable row of small icon+label shortcuts ("Acciones Rápidas").
|
|
8
|
+
* Each item renders a 48 px icon circle + optional badge + label below.
|
|
9
|
+
* Scroll is horizontal and indicator-free for a clean look.
|
|
10
|
+
*/
|
|
11
|
+
export function QuickActions({ items, title }) {
|
|
12
|
+
const theme = useTheme();
|
|
13
|
+
return (_jsxs(View, { children: [title ? (_jsx(Typography.Text, { semibold: true, style: { color: theme.text.secondary, marginBottom: 10, paddingHorizontal: 16 }, variant: "caption", children: title.toUpperCase() })) : null, _jsx(ScrollView, { contentContainerStyle: { paddingHorizontal: 12, gap: 4 }, horizontal: true, showsHorizontalScrollIndicator: false, children: items.map((item) => (_jsxs(TouchableOpacity, { activeOpacity: 0.7, onPress: item.onPress, style: { alignItems: "center", width: 72, paddingVertical: 4 }, children: [_jsx(View, { style: {
|
|
14
|
+
width: 52,
|
|
15
|
+
height: 52,
|
|
16
|
+
borderRadius: 999,
|
|
17
|
+
backgroundColor: item.color ?? theme.bg.muted,
|
|
18
|
+
alignItems: "center",
|
|
19
|
+
justifyContent: "center",
|
|
20
|
+
borderWidth: 1,
|
|
21
|
+
borderColor: theme.border.default,
|
|
22
|
+
}, children: _jsx(Icon, { color: theme.text.primary, customIcon: item.customIcon, name: item.icon, size: 24, type: item.customIcon ? "custom" : "ionicons" }) }), item.badge != null ? (_jsx(View, { style: {
|
|
23
|
+
position: "absolute",
|
|
24
|
+
top: 2,
|
|
25
|
+
right: 4,
|
|
26
|
+
minWidth: 18,
|
|
27
|
+
height: 18,
|
|
28
|
+
borderRadius: 999,
|
|
29
|
+
backgroundColor: theme.danger,
|
|
30
|
+
alignItems: "center",
|
|
31
|
+
justifyContent: "center",
|
|
32
|
+
paddingHorizontal: 4,
|
|
33
|
+
borderWidth: 2,
|
|
34
|
+
borderColor: theme.bg.card,
|
|
35
|
+
}, children: _jsx(Typography.Text, { style: { color: "#FFFFFF", fontSize: 9, lineHeight: 11 }, children: item.badge }) })) : null, _jsx(Typography.Text, { numberOfLines: 2, style: {
|
|
36
|
+
color: theme.text.primary,
|
|
37
|
+
marginTop: 6,
|
|
38
|
+
textAlign: "center",
|
|
39
|
+
fontSize: 11,
|
|
40
|
+
}, variant: "caption", children: item.label })] }, item.id))) })] }));
|
|
41
|
+
}
|
package/dist/widgets/index.d.ts
CHANGED
|
@@ -2,6 +2,16 @@ export { CircleButton } from "../widgets/CircleButton";
|
|
|
2
2
|
export { default as GeoPermissionCard } from "../widgets/GeoPermissionCard";
|
|
3
3
|
export { HomeHeader } from "../widgets/HomeHeader";
|
|
4
4
|
export { MenuCard } from "../widgets/MenuCard";
|
|
5
|
-
export type {
|
|
5
|
+
export type { MenuGridItem, MenuGridProps } from "../widgets/MenuGrid";
|
|
6
|
+
/** @deprecated Renamed to `MenuGridItem`. */
|
|
7
|
+
export type { MenuGridItem as MenuItem } from "../widgets/MenuGrid";
|
|
6
8
|
export { MenuGrid } from "../widgets/MenuGrid";
|
|
9
|
+
export type { MenuSectionProps } from "../widgets/MenuSection";
|
|
10
|
+
export { MenuSection } from "../widgets/MenuSection";
|
|
11
|
+
export type { PromoBannerItem, PromoBannerProps, } from "../widgets/PromoBanner";
|
|
12
|
+
export { PromoBanner } from "../widgets/PromoBanner";
|
|
13
|
+
export type { PromoModalProps } from "../widgets/PromoModal";
|
|
14
|
+
export { PromoModal } from "../widgets/PromoModal";
|
|
15
|
+
export type { QuickActionItem, QuickActionsProps, } from "../widgets/QuickActions";
|
|
16
|
+
export { QuickActions } from "../widgets/QuickActions";
|
|
7
17
|
export { TimeZoneSelector } from "../widgets/TimeZoneSelector";
|