@sincpro/mobile-ui 0.5.0 → 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 +56 -1
- package/dist/Navigation/Navigation.AppBar.js +43 -12
- 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 +7 -6
- 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 +18 -6
- package/dist/views/FormViewV2.js +14 -11
- package/dist/views/ListViewV2.d.ts +12 -1
- package/dist/views/ListViewV2.js +16 -10
- 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
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { type GradientPreset } from "../Display/Display.GradientSurface";
|
|
2
|
+
import { type PatternKind } from "../Display/Display.Pattern";
|
|
3
|
+
import type { LinearGradientPoint } from "expo-linear-gradient";
|
|
1
4
|
import type { ReactNode } from "react";
|
|
2
5
|
export interface AppBarActionProps {
|
|
3
6
|
/** Ionicon name. Optional when `label` is set (text-only CTA). */
|
|
@@ -44,16 +47,68 @@ export interface AppBarProps {
|
|
|
44
47
|
border?: boolean;
|
|
45
48
|
/** Reserves the status-bar space (insets.top). `false` to embed/demo. */
|
|
46
49
|
safeArea?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* [large variant] Extra top padding (px) above the large title row.
|
|
52
|
+
* Default is 8. Use ~16–24 on root/home screens without a back button.
|
|
53
|
+
*/
|
|
54
|
+
topSpacing?: number;
|
|
55
|
+
/**
|
|
56
|
+
* Decorative gradient + texture surface. When set, automatically renders white text/icons
|
|
57
|
+
* (no need to also set `tone="dark"`). Overrides the solid `tone` background.
|
|
58
|
+
*
|
|
59
|
+
* Preset: `background={{ surface: "mesh" }}`
|
|
60
|
+
* Custom: `background={{ colors: ["#0B1410", "#10B981", "#1E1B8A"] }}`
|
|
61
|
+
* With texture: `background={{ surface: "night-green", pattern: "dots" }}`
|
|
62
|
+
*/
|
|
63
|
+
background?: AppBarBackground;
|
|
64
|
+
/**
|
|
65
|
+
* Visual treatment at the bottom edge of the AppBar.
|
|
66
|
+
* - `"line"` — hairline border separator (default for light-surface variants)
|
|
67
|
+
* - `"shadow"` — drop-shadow only, no border (floating/elevated feel)
|
|
68
|
+
* - `"rounded"` — rounded bottom corners (24 px); gradient is clipped inside
|
|
69
|
+
* - `"wave"` — inverse-arc cutout: page-bg arch at the bottom creates a wave illusion
|
|
70
|
+
* - `"none"` — hard edge, no decoration
|
|
71
|
+
*/
|
|
72
|
+
bottomDivider?: "none" | "line" | "shadow" | "rounded" | "wave";
|
|
47
73
|
className?: string;
|
|
48
74
|
testID?: string;
|
|
49
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Gradient + texture surface descriptor for AppBar headers.
|
|
78
|
+
* Pass as the `background` prop — white text/icons are activated automatically.
|
|
79
|
+
*/
|
|
80
|
+
export interface AppBarBackground {
|
|
81
|
+
/** Named gradient preset: `"mesh"` (dark aurora), `"night-green"`, `"neon-teal"`, `"emerald"`. */
|
|
82
|
+
surface?: GradientPreset;
|
|
83
|
+
/** Custom color stops — overrides `surface`. Minimum 2 colors. */
|
|
84
|
+
colors?: readonly [string, string, ...string[]];
|
|
85
|
+
/** Gradient start point. Default: top-left `{ x: 0, y: 0 }`. */
|
|
86
|
+
start?: LinearGradientPoint;
|
|
87
|
+
/** Gradient end point. Default: bottom-right `{ x: 1, y: 1 }`. */
|
|
88
|
+
end?: LinearGradientPoint;
|
|
89
|
+
/** SVG texture overlay kind. */
|
|
90
|
+
pattern?: PatternKind;
|
|
91
|
+
/** Texture opacity (0–1). Default 0.18. */
|
|
92
|
+
patternOpacity?: number;
|
|
93
|
+
/**
|
|
94
|
+
* Text and icon color rendered over this gradient surface.
|
|
95
|
+
* Defaults to `"#FFFFFF"` since gradient AppBar surfaces are typically dark.
|
|
96
|
+
* Pass a dark color (e.g. `theme.text.primary`) for light-colored gradients.
|
|
97
|
+
*/
|
|
98
|
+
textColor?: string;
|
|
99
|
+
/**
|
|
100
|
+
* SVG texture pattern tint color. Defaults to `"#FFFFFF"`.
|
|
101
|
+
* Override when using a light gradient that needs a dark dot/grid texture.
|
|
102
|
+
*/
|
|
103
|
+
patternColor?: string;
|
|
104
|
+
}
|
|
50
105
|
/**
|
|
51
106
|
* Flat, modern top bar (merge of Material 3 + iOS 26): tokenized surface, left-aligned
|
|
52
107
|
* title + subtitle, **contained** icon-buttons (back and actions with a circular area),
|
|
53
108
|
* a `subheader` slot (for SearchBar/Segmented below the title), and a `large` variant.
|
|
54
109
|
* Replaces the gradient look of `Navigation.Header`/`ScreenHeader`.
|
|
55
110
|
*/
|
|
56
|
-
declare function AppBar({ title, subtitle, onBack, leading, actions, subheader, variant, tone, accentBar, backVariant, border, safeArea, className, testID, }: AppBarProps): import("react").JSX.Element;
|
|
111
|
+
declare function AppBar({ title, subtitle, onBack, leading, actions, subheader, variant, tone, accentBar, backVariant, border, safeArea, topSpacing, background, bottomDivider, className, testID, }: AppBarProps): import("react").JSX.Element;
|
|
57
112
|
declare const AppBarWithAction: typeof AppBar & {
|
|
58
113
|
Action: typeof AppBarAction;
|
|
59
114
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
2
|
import GradientSurface from "../Display/Display.GradientSurface";
|
|
3
3
|
import Icon from "../Display/Display.Icon";
|
|
4
|
+
import { Pattern } from "../Display/Display.Pattern";
|
|
4
5
|
import Pressable from "../primitives/Pressable";
|
|
5
|
-
import {
|
|
6
|
+
import { useTheme } from "../theme";
|
|
6
7
|
import { cn } from "../theme/tw";
|
|
7
8
|
import { Typography } from "../Typography";
|
|
8
9
|
import { StyleSheet, View } from "react-native";
|
|
@@ -15,6 +16,7 @@ const HERO_DARK_FALLBACK = "#0E1714";
|
|
|
15
16
|
* With `label`, renders a text pill CTA instead (for "Editar"/"Nuevo"/"Guardar").
|
|
16
17
|
*/
|
|
17
18
|
function AppBarAction({ icon, label, onPress, badge, accessibilityLabel, tone = "plain", onDark = false, bare = false, testID, }) {
|
|
19
|
+
const theme = useTheme();
|
|
18
20
|
const bg = bare
|
|
19
21
|
? "transparent"
|
|
20
22
|
: onDark
|
|
@@ -25,7 +27,7 @@ function AppBarAction({ icon, label, onPress, badge, accessibilityLabel, tone =
|
|
|
25
27
|
const iconColor = tone === "tinted"
|
|
26
28
|
? theme.text.onAccent // dark token on green surface
|
|
27
29
|
: onDark
|
|
28
|
-
?
|
|
30
|
+
? "#FFFFFF" // always white on tone="dark"/gradient surfaces; icon.inverse flips dark in dark-mode
|
|
29
31
|
: theme.icon.primary;
|
|
30
32
|
// Plain (white) squircle gets a hairline so it reads as a contained button on a light bar.
|
|
31
33
|
const showBorder = !bare && !onDark && tone !== "tinted";
|
|
@@ -54,39 +56,68 @@ function AppBarAction({ icon, label, onPress, badge, accessibilityLabel, tone =
|
|
|
54
56
|
* a `subheader` slot (for SearchBar/Segmented below the title), and a `large` variant.
|
|
55
57
|
* Replaces the gradient look of `Navigation.Header`/`ScreenHeader`.
|
|
56
58
|
*/
|
|
57
|
-
function AppBar({ title, subtitle, onBack, leading, actions, subheader, variant = "default", tone = "default", accentBar = false, backVariant = "contained", border = true, safeArea = true, className, testID, }) {
|
|
59
|
+
function AppBar({ title, subtitle, onBack, leading, actions, subheader, variant = "default", tone = "default", accentBar = false, backVariant = "contained", border = true, safeArea = true, topSpacing, background, bottomDivider, className, testID, }) {
|
|
60
|
+
const theme = useTheme();
|
|
58
61
|
const insets = useSafeAreaInsets();
|
|
59
62
|
const centered = variant === "center";
|
|
60
63
|
const large = variant === "large";
|
|
61
64
|
const dark = tone === "dark";
|
|
62
65
|
const gradient = tone === "gradient";
|
|
66
|
+
const hasBackground = !!background;
|
|
63
67
|
// Large variant: back/leading + actions all live ON the big-title row (single cohesive
|
|
64
68
|
// block — no separate top toolbar that would push the title to a new line). The compact
|
|
65
69
|
// top toolbar is only for default/center.
|
|
66
70
|
const largeHasNav = large && (!!onBack || !!leading);
|
|
67
71
|
const showTopBar = !large;
|
|
68
|
-
//
|
|
69
|
-
const colored = dark || gradient;
|
|
70
|
-
|
|
72
|
+
// Colored = any rich surface. `background` alone activates colored mode (white text/icons).
|
|
73
|
+
const colored = dark || gradient || hasBackground;
|
|
74
|
+
// gradient (neon green) → dark text via onAccent. background → textColor prop (default white, since
|
|
75
|
+
// gradient surfaces are dark). dark tone → white always. text.inverse is NOT used here: it flips to
|
|
76
|
+
// near-black in dark-mode themes (semantic: "text on light surfaces"), wrong for dark gradient AppBars.
|
|
77
|
+
const onColoredText = gradient && !hasBackground
|
|
78
|
+
? theme.text.onAccent
|
|
79
|
+
: hasBackground
|
|
80
|
+
? (background?.textColor ?? "#FFFFFF")
|
|
81
|
+
: "#FFFFFF";
|
|
71
82
|
const titleStyle = colored ? { color: onColoredText } : undefined;
|
|
72
|
-
const subtitleStyle = gradient
|
|
83
|
+
const subtitleStyle = gradient && !hasBackground
|
|
73
84
|
? { color: theme.text.onAccent, opacity: 0.72 }
|
|
74
|
-
:
|
|
85
|
+
: colored
|
|
75
86
|
? { color: "rgba(255,255,255,0.7)" }
|
|
76
87
|
: undefined;
|
|
77
88
|
// Large variant on a plain surface should feel like the page itself (no card surface, no
|
|
78
89
|
// hairline). Compact variants (default/center) keep the card surface for detail screens.
|
|
79
90
|
const largePlain = large && !colored;
|
|
80
|
-
|
|
91
|
+
// bottomDivider controls the bottom edge decoration. When not set, fall back to the
|
|
92
|
+
// legacy border prop (hairline for default/center on plain surfaces).
|
|
93
|
+
const showBorder = bottomDivider
|
|
94
|
+
? bottomDivider === "line"
|
|
95
|
+
: !colored && !largePlain && border;
|
|
96
|
+
const showRounded = bottomDivider === "rounded";
|
|
97
|
+
const showShadow = bottomDivider === "shadow";
|
|
98
|
+
const showWave = bottomDivider === "wave";
|
|
99
|
+
return (_jsxs(View, { className: cn(colored ? "" : largePlain ? "bg-bg-page" : "bg-bg-card", showBorder && "border-b border-border-light", className), style: {
|
|
81
100
|
paddingTop: safeArea ? insets.top : 0,
|
|
82
|
-
|
|
83
|
-
|
|
101
|
+
// dark tone without a background → solid inverse bg; background prop → GradientSurface handles it
|
|
102
|
+
...(dark && !hasBackground
|
|
103
|
+
? { backgroundColor: theme.bg.inverse ?? HERO_DARK_FALLBACK }
|
|
104
|
+
: null),
|
|
105
|
+
...(showRounded
|
|
106
|
+
? { borderBottomLeftRadius: 24, borderBottomRightRadius: 24, overflow: "hidden" }
|
|
107
|
+
: null),
|
|
108
|
+
...(showShadow ? theme.shadow.md : null),
|
|
109
|
+
}, testID: testID, children: [hasBackground ? (_jsx(GradientSurface, { colors: background.colors, end: background.end, padding: "none", preset: background.surface ?? "neon-teal", radius: "none", start: background.start, style: StyleSheet.absoluteFill })) : gradient ? (_jsx(GradientSurface, { colors: theme.gradient.accent, padding: "none", radius: "none", style: StyleSheet.absoluteFill })) : null, background?.pattern ? (_jsx(Pattern, { color: background.patternColor ?? "#FFFFFF", kind: background.pattern, opacity: background.patternOpacity ?? 0.18 })) : null, showTopBar ? (_jsxs(View, { className: "flex-row items-center px-3 gap-2 min-h-[56px]", children: [_jsxs(View, { className: "flex-row items-center gap-2", style: { minWidth: 38 }, children: [onBack ? (_jsx(AppBarAction, { accessibilityLabel: "Volver", bare: backVariant === "plain", icon: "chevron-back", onDark: dark || gradient || hasBackground, onPress: onBack })) : null, leading] }), _jsxs(View, { className: cn("flex-1", centered && "items-center"), children: [title ? (_jsx(Typography.Text, { className: colored ? "" : "text-text-primary", numberOfLines: 1, semibold: true, style: titleStyle, variant: "subtitle", children: title })) : null, subtitle ? (_jsx(Typography.Text, { className: colored ? "" : "text-text-secondary", numberOfLines: 1, style: subtitleStyle, variant: "caption", children: subtitle })) : null] }), _jsx(View, { className: "flex-row items-center justify-end gap-2", style: { minWidth: 38 }, children: actions })] })) : null, large && title ? (_jsxs(View, { className: cn("flex-row px-4 pb-3", largeHasNav ? "items-center gap-2" : ""), style: { paddingTop: topSpacing != null ? topSpacing : 8 }, children: [onBack ? (_jsx(AppBarAction, { accessibilityLabel: "Volver", bare: backVariant === "plain", icon: "chevron-back", onDark: dark || gradient || hasBackground, onPress: onBack })) : null, leading, accentBar && !largeHasNav ? (_jsx(View, { style: {
|
|
84
110
|
width: 4,
|
|
85
111
|
marginRight: 10,
|
|
86
112
|
marginVertical: 2,
|
|
87
113
|
borderRadius: 999,
|
|
88
114
|
backgroundColor: theme.accent,
|
|
89
|
-
} })) : null, _jsxs(View, { className: "flex-1", children: [_jsx(Typography.Text, { className: colored ? "" : "text-text-primary", style: titleStyle, variant: "h2", children: title }), subtitle ? (_jsx(Typography.Text, { className: colored ? "" : "text-text-secondary", style: subtitleStyle, variant: "bodySmall", children: subtitle })) : null] }), actions ? (_jsx(View, { className: cn("flex-row items-center justify-end gap-2 pl-2", largeHasNav ? "" : "self-center"), children: actions })) : null] })) : null, subheader ? _jsx(View, { className: "px-3 pb-3 pt-0.5", children: subheader }) : null
|
|
115
|
+
} })) : null, _jsxs(View, { className: "flex-1", children: [_jsx(Typography.Text, { className: colored ? "" : "text-text-primary", style: titleStyle, variant: "h2", children: title }), subtitle ? (_jsx(Typography.Text, { className: colored ? "" : "text-text-secondary", style: subtitleStyle, variant: "bodySmall", children: subtitle })) : null] }), actions ? (_jsx(View, { className: cn("flex-row items-center justify-end gap-2 pl-2", largeHasNav ? "" : "self-center"), children: actions })) : null] })) : null, subheader ? _jsx(View, { className: "px-3 pb-3 pt-0.5", children: subheader }) : null, showWave ? (_jsx(View, { style: {
|
|
116
|
+
height: 24,
|
|
117
|
+
backgroundColor: theme.bg.page,
|
|
118
|
+
borderTopLeftRadius: 24,
|
|
119
|
+
borderTopRightRadius: 24,
|
|
120
|
+
} })) : null] }));
|
|
90
121
|
}
|
|
91
122
|
const AppBarWithAction = Object.assign(AppBar, { Action: AppBarAction });
|
|
92
123
|
export default AppBarWithAction;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "nativewind/jsx-runtime";
|
|
2
2
|
import Icon from "../Display/Display.Icon";
|
|
3
3
|
import Pressable from "../primitives/Pressable";
|
|
4
|
-
import {
|
|
4
|
+
import { useTheme } from "../theme";
|
|
5
5
|
import { cn } from "../theme/tw";
|
|
6
6
|
import { Typography } from "../Typography";
|
|
7
7
|
import { View } from "react-native";
|
|
@@ -14,6 +14,7 @@ const DARK_SURFACE = "#15181B";
|
|
|
14
14
|
*/
|
|
15
15
|
function BottomNav({ items, value, onChange, showLabels = true, centerAction, safeArea = true, shape = "bar", tone = "light", indicator = "none", bordered = true, activeColor = "primary", className, testID, }) {
|
|
16
16
|
const insets = useSafeAreaInsets();
|
|
17
|
+
const theme = useTheme();
|
|
17
18
|
const dark = tone === "dark";
|
|
18
19
|
const rounded = shape === "floating" || dark;
|
|
19
20
|
const bottomPad = rounded ? 6 : safeArea ? insets.bottom : 0;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
-
import
|
|
2
|
+
import Icon from "../Display/Display.Icon";
|
|
3
|
+
import Logo from "../Display/Display.Logo";
|
|
3
4
|
import GradientContainer from "../layouts/GradientContainer";
|
|
4
5
|
import { theme } from "../theme";
|
|
5
6
|
import { cn } from "../theme/tw";
|
|
@@ -11,6 +12,6 @@ import { TouchableOpacity, View } from "react-native";
|
|
|
11
12
|
*/
|
|
12
13
|
const Header = ({ title, logo, logoSource, backButton, handleBackButton, className, }) => {
|
|
13
14
|
const onBackPress = handleBackButton ?? (() => { });
|
|
14
|
-
return (_jsx(GradientContainer, { className: cn("pt-10 pb-3.5 px-4", className), children: _jsxs(View, { className: "relative items-center justify-center", children: [backButton && (_jsx(TouchableOpacity, { className: "absolute top-0 left-0 z-10 border border-white p-1.5 rounded", onPress: onBackPress, children: _jsx(
|
|
15
|
+
return (_jsx(GradientContainer, { className: cn("pt-10 pb-3.5 px-4", className), children: _jsxs(View, { className: "relative items-center justify-center", children: [backButton && (_jsx(TouchableOpacity, { className: "absolute top-0 left-0 z-10 border border-white p-1.5 rounded", onPress: onBackPress, children: _jsx(Icon, { color: theme.text.inverse, name: "chevron-back", size: 25, type: "ionicons" }) })), _jsxs(View, { className: "items-center justify-center", children: [logo || _jsx(Logo, { size: "medium", source: logoSource }), title && (_jsx(Typography.Text, { className: "text-white", variant: "h4", children: title }))] })] }) }));
|
|
15
16
|
};
|
|
16
17
|
export default Header;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
2
|
import Icon from "../Display/Display.Icon";
|
|
3
3
|
import Pressable from "../primitives/Pressable";
|
|
4
|
-
import {
|
|
4
|
+
import { useTheme } from "../theme";
|
|
5
5
|
import { cn } from "../theme/tw";
|
|
6
6
|
import { Typography } from "../Typography";
|
|
7
|
-
import { useRef, useState } from "react";
|
|
7
|
+
import { cloneElement, useRef, useState } from "react";
|
|
8
8
|
import { Dimensions, Modal, Pressable as RNPressable, View } from "react-native";
|
|
9
9
|
function Menu({ items, trigger, menuWidth = 220, testID }) {
|
|
10
|
+
const theme = useTheme();
|
|
10
11
|
const triggerRef = useRef(null);
|
|
11
12
|
const [anchor, setAnchor] = useState(null);
|
|
12
13
|
const open = () => {
|
|
@@ -18,7 +19,9 @@ function Menu({ items, trigger, menuWidth = 220, testID }) {
|
|
|
18
19
|
const screen = Dimensions.get("window");
|
|
19
20
|
const right = anchor ? Math.max(8, screen.width - (anchor.x + anchor.width)) : 8;
|
|
20
21
|
const top = anchor ? anchor.y + anchor.height + 4 : 0;
|
|
21
|
-
return (_jsxs(View, { collapsable: false, ref: triggerRef, testID: testID, children: [
|
|
22
|
+
return (_jsxs(View, { collapsable: false, ref: triggerRef, testID: testID, children: [trigger ? (
|
|
23
|
+
// eslint-disable-next-line react-hooks/refs
|
|
24
|
+
cloneElement(trigger, { onPress: open })) : (_jsx(Pressable, { accessibilityLabel: "M\u00E1s opciones", accessibilityRole: "button", onPress: open, children: _jsx(Icon, { color: theme.icon.secondary, name: "ellipsis-vertical", size: 22 }) })), _jsx(Modal, { animationType: "fade", onRequestClose: close, transparent: true, visible: anchor !== null, children: _jsx(RNPressable, { onPress: close, style: { flex: 1 }, children: _jsx(View, { className: "rounded-lg py-1", style: {
|
|
22
25
|
position: "absolute",
|
|
23
26
|
top,
|
|
24
27
|
right,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
export interface MenuSectionProps {
|
|
3
|
+
/** Section heading above the card. */
|
|
4
|
+
title?: string;
|
|
5
|
+
/** Footer note below the card (hints, disclaimers). */
|
|
6
|
+
footer?: string;
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Titled card that groups `Display.MenuButton` rows into a visual section.
|
|
11
|
+
* Mirrors iOS grouped-table-view style: title above, card surface, optional footer note.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* <MenuSection title="General">
|
|
15
|
+
* <Display.MenuButton label="Impresora" icon={PrinterIcon} onPress={...} />
|
|
16
|
+
* <Display.MenuButton label="Ajustes" icon={SettingsIcon} onPress={...} showDivider={false} />
|
|
17
|
+
* </MenuSection>
|
|
18
|
+
*/
|
|
19
|
+
export declare function MenuSection({ title, footer, children }: MenuSectionProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
+
import { useTheme } from "../theme";
|
|
3
|
+
import { Typography } from "../Typography";
|
|
4
|
+
import { View } from "react-native";
|
|
5
|
+
/**
|
|
6
|
+
* Titled card that groups `Display.MenuButton` rows into a visual section.
|
|
7
|
+
* Mirrors iOS grouped-table-view style: title above, card surface, optional footer note.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* <MenuSection title="General">
|
|
11
|
+
* <Display.MenuButton label="Impresora" icon={PrinterIcon} onPress={...} />
|
|
12
|
+
* <Display.MenuButton label="Ajustes" icon={SettingsIcon} onPress={...} showDivider={false} />
|
|
13
|
+
* </MenuSection>
|
|
14
|
+
*/
|
|
15
|
+
export function MenuSection({ title, footer, children }) {
|
|
16
|
+
const theme = useTheme();
|
|
17
|
+
return (_jsxs(View, { style: { marginHorizontal: 16, marginBottom: 20 }, children: [title ? (_jsx(Typography.Text, { semibold: true, style: { color: theme.text.secondary, marginBottom: 6, paddingHorizontal: 4 }, variant: "caption", children: title.toUpperCase() })) : null, _jsx(View, { style: {
|
|
18
|
+
backgroundColor: theme.bg.card,
|
|
19
|
+
borderRadius: 14,
|
|
20
|
+
borderWidth: 1,
|
|
21
|
+
borderColor: theme.border.default,
|
|
22
|
+
overflow: "hidden",
|
|
23
|
+
...theme.shadow.sm,
|
|
24
|
+
}, children: children }), footer ? (_jsx(Typography.Text, { style: { color: theme.text.tertiary, marginTop: 6, paddingHorizontal: 4 }, variant: "caption", children: footer })) : null] }));
|
|
25
|
+
}
|
|
@@ -1,14 +1,28 @@
|
|
|
1
|
+
import { ComponentType } from "react";
|
|
1
2
|
export interface SegmentedOption<T extends string> {
|
|
2
3
|
label: string;
|
|
3
4
|
value: T;
|
|
5
|
+
/** Ionicon name rendered above (or before) the label. */
|
|
6
|
+
icon?: string;
|
|
7
|
+
/** Custom icon component — takes precedence over `icon`. */
|
|
8
|
+
customIcon?: ComponentType<{
|
|
9
|
+
size?: number;
|
|
10
|
+
color?: string;
|
|
11
|
+
}>;
|
|
4
12
|
}
|
|
5
13
|
export interface SegmentedControlProps<T extends string> {
|
|
6
14
|
options: SegmentedOption<T>[];
|
|
7
15
|
value: T;
|
|
8
16
|
onChange: (value: T) => void;
|
|
17
|
+
/**
|
|
18
|
+
* Icon layout when options have icons:
|
|
19
|
+
* - `"top"` (default) — icon stacked above the label (taller pill).
|
|
20
|
+
* - `"left"` — icon inline left of the label (compact, single-line).
|
|
21
|
+
*/
|
|
22
|
+
iconLayout?: "top" | "left";
|
|
9
23
|
className?: string;
|
|
10
24
|
testID?: string;
|
|
11
25
|
}
|
|
12
|
-
declare function SegmentedControl<T extends string>({ options, value, onChange, className, testID, }: SegmentedControlProps<T>): import("react").JSX.Element;
|
|
26
|
+
declare function SegmentedControl<T extends string>({ options, value, onChange, iconLayout, className, testID, }: SegmentedControlProps<T>): import("react").JSX.Element;
|
|
13
27
|
export default SegmentedControl;
|
|
14
28
|
export { SegmentedControl };
|
|
@@ -1,12 +1,30 @@
|
|
|
1
|
-
import { jsx as _jsx } from "nativewind/jsx-runtime";
|
|
2
|
-
import
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
+
import Icon from "../Display/Display.Icon";
|
|
3
|
+
import { useTheme } from "../theme";
|
|
3
4
|
import { cn } from "../theme/tw";
|
|
4
5
|
import { Typography } from "../Typography";
|
|
5
6
|
import { TouchableOpacity, View } from "react-native";
|
|
6
|
-
function SegmentedControl({ options, value, onChange, className, testID, }) {
|
|
7
|
+
function SegmentedControl({ options, value, onChange, iconLayout = "top", className, testID, }) {
|
|
8
|
+
const theme = useTheme();
|
|
9
|
+
const hasIcons = options.some((o) => o.icon || o.customIcon);
|
|
7
10
|
return (_jsx(View, { accessibilityRole: "tablist", className: cn("flex-row bg-bg-muted rounded-lg p-1 gap-1", className), testID: testID, children: options.map((option) => {
|
|
8
11
|
const selected = option.value === value;
|
|
9
|
-
|
|
12
|
+
const iconColor = selected ? theme.text.primary : theme.text.secondary;
|
|
13
|
+
const hasIcon = !!(option.icon || option.customIcon);
|
|
14
|
+
const inline = hasIcons && iconLayout === "left";
|
|
15
|
+
return (_jsxs(TouchableOpacity, { accessibilityLabel: option.label, accessibilityRole: "tab", accessibilityState: { selected }, activeOpacity: 0.7, onPress: () => onChange(option.value), style: {
|
|
16
|
+
flex: 1,
|
|
17
|
+
flexDirection: inline ? "row" : "column",
|
|
18
|
+
alignItems: "center",
|
|
19
|
+
justifyContent: "center",
|
|
20
|
+
gap: hasIcon ? 4 : 0,
|
|
21
|
+
paddingVertical: hasIcons && !inline ? 8 : 8,
|
|
22
|
+
paddingHorizontal: 4,
|
|
23
|
+
borderRadius: 8,
|
|
24
|
+
...(selected
|
|
25
|
+
? { backgroundColor: theme.bg.card, ...theme.shadow.sm }
|
|
26
|
+
: undefined),
|
|
27
|
+
}, children: [hasIcon ? (_jsx(Icon, { color: iconColor, customIcon: option.customIcon, name: option.icon, size: 16, type: option.customIcon ? "custom" : "ionicons" })) : null, _jsx(Typography.Text, { numberOfLines: 1, semibold: selected, style: { color: iconColor, fontSize: 12 }, variant: "caption", children: option.label })] }, option.value));
|
|
10
28
|
}) }));
|
|
11
29
|
}
|
|
12
30
|
export default SegmentedControl;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "nativewind/jsx-runtime";
|
|
2
|
-
import
|
|
2
|
+
import Icon from "../Display/Display.Icon";
|
|
3
3
|
import { cn } from "../theme/tw";
|
|
4
4
|
import { View } from "react-native";
|
|
5
|
-
const Icon = Display.Icon;
|
|
6
5
|
/**
|
|
7
6
|
* @deprecated Orphan tab-bar icon piece (unused). Use `Navigation.BottomNav` (single source
|
|
8
7
|
* of truth for the bottom tab bar). Kept for backwards compatibility; removed in the next major.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "nativewind/jsx-runtime";
|
|
2
|
-
import
|
|
2
|
+
import Icon from "../Display/Display.Icon";
|
|
3
3
|
import { cn } from "../theme/tw";
|
|
4
4
|
import { View } from "react-native";
|
|
5
5
|
/**
|
|
@@ -8,6 +8,6 @@ import { View } from "react-native";
|
|
|
8
8
|
* compatibility; removed in the next major.
|
|
9
9
|
*/
|
|
10
10
|
const TabIcon = ({ focused, size = 24, customIcon, type = "custom", name, className, }) => {
|
|
11
|
-
return (_jsx(View, { className: cn("justify-center items-center w-12 h-12 rounded-full", focused ? "bg-primary shadow-md" : "bg-transparent", className), children: _jsx(
|
|
11
|
+
return (_jsx(View, { className: cn("justify-center items-center w-12 h-12 rounded-full", focused ? "bg-primary shadow-md" : "bg-transparent", className), children: _jsx(Icon, { color: focused ? "#FFFFFF" : "#6B7280", customIcon: customIcon, name: name, size: size, type: type }) }));
|
|
12
12
|
};
|
|
13
13
|
export default TabIcon;
|
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
|
+
type TabsVariant = "underline" | "filled";
|
|
2
3
|
export interface TabsProps {
|
|
3
4
|
value?: string;
|
|
4
5
|
defaultValue?: string;
|
|
5
6
|
onValueChange?: (value: string) => void;
|
|
7
|
+
variant?: TabsVariant;
|
|
6
8
|
className?: string;
|
|
7
9
|
children: ReactNode;
|
|
8
10
|
}
|
|
9
|
-
declare function TabsRoot({ value, defaultValue, onValueChange, className, children }: TabsProps): import("react").JSX.Element;
|
|
11
|
+
declare function TabsRoot({ value, defaultValue, onValueChange, variant, className, children, }: TabsProps): import("react").JSX.Element;
|
|
10
12
|
declare function TabsList({ children, className }: {
|
|
11
13
|
children: ReactNode;
|
|
12
14
|
className?: string;
|
|
13
15
|
}): import("react").JSX.Element;
|
|
14
|
-
|
|
16
|
+
export interface TabsTriggerProps {
|
|
15
17
|
value: string;
|
|
16
18
|
children: ReactNode;
|
|
17
|
-
|
|
19
|
+
icon?: string;
|
|
20
|
+
iconLayout?: "top" | "left";
|
|
21
|
+
}
|
|
22
|
+
declare function TabsTrigger({ value, children, icon, iconLayout }: TabsTriggerProps): import("react").JSX.Element;
|
|
18
23
|
declare function TabsContent({ value, children }: {
|
|
19
24
|
value: string;
|
|
20
25
|
children: ReactNode;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
-
import
|
|
2
|
+
import Icon from "../Display/Display.Icon";
|
|
3
|
+
import { useTheme } from "../theme";
|
|
3
4
|
import { cn } from "../theme/tw";
|
|
4
5
|
import { Typography } from "../Typography";
|
|
5
6
|
import { createContext, useCallback, useContext, useState } from "react";
|
|
@@ -12,7 +13,7 @@ function useTabs() {
|
|
|
12
13
|
}
|
|
13
14
|
return ctx;
|
|
14
15
|
}
|
|
15
|
-
function TabsRoot({ value, defaultValue, onValueChange, className, children }) {
|
|
16
|
+
function TabsRoot({ value, defaultValue, onValueChange, variant = "underline", className, children, }) {
|
|
16
17
|
const [internal, setInternal] = useState(defaultValue ?? "");
|
|
17
18
|
const current = value ?? internal;
|
|
18
19
|
const setValue = useCallback((next) => {
|
|
@@ -20,15 +21,27 @@ function TabsRoot({ value, defaultValue, onValueChange, className, children }) {
|
|
|
20
21
|
setInternal(next);
|
|
21
22
|
onValueChange?.(next);
|
|
22
23
|
}, [value, onValueChange]);
|
|
23
|
-
return (_jsx(TabsContext.Provider, { value: { value: current, setValue }, children: _jsx(View, { className: cn("flex-1", className), children: children }) }));
|
|
24
|
+
return (_jsx(TabsContext.Provider, { value: { value: current, setValue, variant }, children: _jsx(View, { className: cn("flex-1", className), children: children }) }));
|
|
24
25
|
}
|
|
25
26
|
function TabsList({ children, className }) {
|
|
27
|
+
const { variant } = useTabs();
|
|
28
|
+
if (variant === "filled") {
|
|
29
|
+
return (_jsx(View, { accessibilityRole: "tablist", className: cn("flex-row rounded-xl p-1", className), style: { backgroundColor: "#E5E7EB" }, children: children }));
|
|
30
|
+
}
|
|
26
31
|
return (_jsx(View, { accessibilityRole: "tablist", className: cn("flex-row border-b border-border-default", className), children: children }));
|
|
27
32
|
}
|
|
28
|
-
function TabsTrigger({ value, children }) {
|
|
29
|
-
const
|
|
33
|
+
function TabsTrigger({ value, children, icon, iconLayout = "left" }) {
|
|
34
|
+
const theme = useTheme();
|
|
35
|
+
const { value: active, setValue, variant } = useTabs();
|
|
30
36
|
const selected = active === value;
|
|
31
|
-
|
|
37
|
+
const iconColor = selected ? theme.primary : theme.text.secondary;
|
|
38
|
+
if (variant === "filled") {
|
|
39
|
+
return (_jsx(TouchableOpacity, { accessibilityRole: "tab", accessibilityState: { selected }, activeOpacity: 0.7, className: "flex-1 items-center justify-center rounded-lg py-2", onPress: () => setValue(value), style: selected ? { backgroundColor: theme.bg.card, ...theme.shadow.sm } : {}, children: _jsxs(View, { className: cn("items-center", iconLayout === "left" && icon ? "flex-row gap-1.5" : "gap-1"), children: [icon && iconLayout === "top" && _jsx(Icon, { color: iconColor, name: icon, size: 16 }), icon && iconLayout === "left" && _jsx(Icon, { color: iconColor, name: icon, size: 14 }), _jsx(Typography.Text, { semibold: selected, style: { color: iconColor }, variant: "bodySmall", children: children })] }) }));
|
|
40
|
+
}
|
|
41
|
+
// underline variant
|
|
42
|
+
return (_jsxs(TouchableOpacity, { accessibilityRole: "tab", accessibilityState: { selected }, activeOpacity: 0.7, className: "flex-1 items-center", onPress: () => setValue(value), children: [_jsxs(View, { className: cn("py-3", iconLayout === "top" && icon
|
|
43
|
+
? "items-center gap-1"
|
|
44
|
+
: "flex-row items-center gap-1.5"), children: [icon && iconLayout === "top" && _jsx(Icon, { color: iconColor, name: icon, size: 18 }), icon && iconLayout === "left" && _jsx(Icon, { color: iconColor, name: icon, size: 14 }), _jsx(Typography.Text, { semibold: selected, style: { color: iconColor }, children: children })] }), _jsx(View, { className: "h-0.5 w-full", style: { backgroundColor: selected ? theme.primary : "transparent" } })] }));
|
|
32
45
|
}
|
|
33
46
|
function TabsContent({ value, children }) {
|
|
34
47
|
const { value: active } = useTabs();
|
|
@@ -3,13 +3,16 @@ import CollapsingHeader from "../Navigation/Navigation.CollapsingHeader";
|
|
|
3
3
|
import FloatingBar from "../Navigation/Navigation.FloatingBar";
|
|
4
4
|
import HeaderToolbar from "../Navigation/Navigation.HeaderToolbar";
|
|
5
5
|
import Menu from "../Navigation/Navigation.Menu";
|
|
6
|
+
import { MenuSection } from "../Navigation/Navigation.MenuSection";
|
|
6
7
|
import RowItem from "../Navigation/Navigation.RowItem";
|
|
7
8
|
import SearchBar from "../Navigation/Navigation.SearchBar";
|
|
8
9
|
import SegmentedControl from "../Navigation/Navigation.SegmentedControl";
|
|
9
10
|
import Steps from "../Navigation/Navigation.Steps";
|
|
10
11
|
import TabIcon from "../Navigation/Navigation.TabIcon";
|
|
12
|
+
export type { AppBarBackground } from "../Navigation/Navigation.AppBar";
|
|
13
|
+
export type { MenuSectionProps } from "../Navigation/Navigation.MenuSection";
|
|
11
14
|
export declare const Navigation: {
|
|
12
|
-
AppBar: (({ title, subtitle, onBack, leading, actions, subheader, variant, tone, accentBar, backVariant, border, safeArea, className, testID, }: import("../Navigation/Navigation.AppBar").AppBarProps) => import("react").JSX.Element) & {
|
|
15
|
+
AppBar: (({ title, subtitle, onBack, leading, actions, subheader, variant, tone, accentBar, backVariant, border, safeArea, topSpacing, background, bottomDivider, className, testID, }: import("../Navigation/Navigation.AppBar").AppBarProps) => import("react").JSX.Element) & {
|
|
13
16
|
Action: ({ icon, label, onPress, badge, accessibilityLabel, tone, onDark, bare, testID, }: import("../Navigation/Navigation.AppBar").AppBarActionProps) => import("react").JSX.Element;
|
|
14
17
|
};
|
|
15
18
|
BottomNav: typeof BottomNav;
|
|
@@ -22,21 +25,19 @@ export declare const Navigation: {
|
|
|
22
25
|
TabIcon: typeof TabIcon;
|
|
23
26
|
RowItem: typeof RowItem;
|
|
24
27
|
SegmentedControl: typeof SegmentedControl;
|
|
25
|
-
Tabs: (({ value, defaultValue, onValueChange, className, children }: import("../Navigation/Navigation.Tabs").TabsProps) => import("react").JSX.Element) & {
|
|
28
|
+
Tabs: (({ value, defaultValue, onValueChange, variant, className, children, }: import("../Navigation/Navigation.Tabs").TabsProps) => import("react").JSX.Element) & {
|
|
26
29
|
List: ({ children, className }: {
|
|
27
30
|
children: import("react").ReactNode;
|
|
28
31
|
className?: string;
|
|
29
32
|
}) => import("react").JSX.Element;
|
|
30
|
-
Trigger: ({ value, children }:
|
|
31
|
-
value: string;
|
|
32
|
-
children: import("react").ReactNode;
|
|
33
|
-
}) => import("react").JSX.Element;
|
|
33
|
+
Trigger: ({ value, children, icon, iconLayout }: import("../Navigation/Navigation.Tabs").TabsTriggerProps) => import("react").JSX.Element;
|
|
34
34
|
Content: ({ value, children }: {
|
|
35
35
|
value: string;
|
|
36
36
|
children: import("react").ReactNode;
|
|
37
37
|
}) => import("react").JSX.Element | null;
|
|
38
38
|
};
|
|
39
39
|
Menu: typeof Menu;
|
|
40
|
+
MenuSection: typeof MenuSection;
|
|
40
41
|
Steps: typeof Steps;
|
|
41
42
|
};
|
|
42
43
|
export default Navigation;
|
package/dist/Navigation/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import FloatingBar from "../Navigation/Navigation.FloatingBar";
|
|
|
5
5
|
import Header from "../Navigation/Navigation.Header";
|
|
6
6
|
import HeaderToolbar from "../Navigation/Navigation.HeaderToolbar";
|
|
7
7
|
import Menu from "../Navigation/Navigation.Menu";
|
|
8
|
+
import { MenuSection } from "../Navigation/Navigation.MenuSection";
|
|
8
9
|
import RowItem from "../Navigation/Navigation.RowItem";
|
|
9
10
|
import SearchBar from "../Navigation/Navigation.SearchBar";
|
|
10
11
|
import SegmentedControl from "../Navigation/Navigation.SegmentedControl";
|
|
@@ -26,6 +27,7 @@ export const Navigation = {
|
|
|
26
27
|
SegmentedControl,
|
|
27
28
|
Tabs,
|
|
28
29
|
Menu,
|
|
30
|
+
MenuSection,
|
|
29
31
|
Steps,
|
|
30
32
|
};
|
|
31
33
|
export default Navigation;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { Actions } from "./Actions";
|
|
1
2
|
export { Dialog } from "./Dialog";
|
|
2
3
|
export { Display } from "./Display";
|
|
3
4
|
export { Feedback } from "./Feedback";
|
|
@@ -8,6 +9,7 @@ export { Box, Row, Stack } from "./primitives";
|
|
|
8
9
|
export { type BrandingConfig, getBrandingLogo, setBranding, } from "./branding";
|
|
9
10
|
export { cn, tv, type VariantProps } from "./theme/tw";
|
|
10
11
|
export { fontFamilies, fontSizes, fontWeights, letterSpacing, lineHeights, typographyVariants, } from "./theme/typography";
|
|
12
|
+
export { BottomInsetContext } from "./layouts/BottomInset";
|
|
11
13
|
export { default as Container } from "./layouts/Container";
|
|
12
14
|
export { default as GradientContainer } from "./layouts/GradientContainer";
|
|
13
15
|
export { default as PlainLayout } from "./layouts/PlainLayout";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Design System - Compound Components
|
|
2
|
+
export { Actions } from "./Actions";
|
|
2
3
|
export { Dialog } from "./Dialog";
|
|
3
4
|
export { Display } from "./Display";
|
|
4
5
|
export { Feedback } from "./Feedback";
|
|
@@ -13,6 +14,7 @@ export { getBrandingLogo, setBranding, } from "./branding";
|
|
|
13
14
|
export { cn, tv } from "./theme/tw";
|
|
14
15
|
export { fontFamilies, fontSizes, fontWeights, letterSpacing, lineHeights, typographyVariants, } from "./theme/typography";
|
|
15
16
|
// Layouts
|
|
17
|
+
export { BottomInsetContext } from "./layouts/BottomInset";
|
|
16
18
|
export { default as Container } from "./layouts/Container";
|
|
17
19
|
export { default as GradientContainer } from "./layouts/GradientContainer";
|
|
18
20
|
export { default as PlainLayout } from "./layouts/PlainLayout";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extra bottom inset for scroll views, provided by the host app when a floating
|
|
3
|
+
* element (e.g. position:absolute tab bar) sits above the native safe area.
|
|
4
|
+
*
|
|
5
|
+
* FormViewV2.Content and ListViewV2.Content add this value as extra
|
|
6
|
+
* `contentContainerStyle.paddingBottom` so content can scroll fully above the bar.
|
|
7
|
+
*
|
|
8
|
+
* Usage in the host app:
|
|
9
|
+
* <BottomInsetContext.Provider value={72}>
|
|
10
|
+
* <Tabs.Navigator ...>
|
|
11
|
+
*
|
|
12
|
+
* Default: 0 — no extra inset (backwards compatible).
|
|
13
|
+
* The native safe-area inset is already handled by Container (SafeAreaView edges=["bottom"]).
|
|
14
|
+
*/
|
|
15
|
+
export declare const BottomInsetContext: import("react").Context<number>;
|
|
16
|
+
export declare const useBottomInset: () => number;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Extra bottom inset for scroll views, provided by the host app when a floating
|
|
4
|
+
* element (e.g. position:absolute tab bar) sits above the native safe area.
|
|
5
|
+
*
|
|
6
|
+
* FormViewV2.Content and ListViewV2.Content add this value as extra
|
|
7
|
+
* `contentContainerStyle.paddingBottom` so content can scroll fully above the bar.
|
|
8
|
+
*
|
|
9
|
+
* Usage in the host app:
|
|
10
|
+
* <BottomInsetContext.Provider value={72}>
|
|
11
|
+
* <Tabs.Navigator ...>
|
|
12
|
+
*
|
|
13
|
+
* Default: 0 — no extra inset (backwards compatible).
|
|
14
|
+
* The native safe-area inset is already handled by Container (SafeAreaView edges=["bottom"]).
|
|
15
|
+
*/
|
|
16
|
+
export const BottomInsetContext = createContext(0);
|
|
17
|
+
export const useBottomInset = () => useContext(BottomInsetContext);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "nativewind/jsx-runtime";
|
|
2
|
-
import
|
|
2
|
+
import DisplayIcon from "../Display/Display.Icon";
|
|
3
3
|
import Container from "../layouts/Container";
|
|
4
4
|
import { Typography } from "../Typography";
|
|
5
5
|
import { Children, isValidElement } from "react";
|
|
6
6
|
import { TouchableOpacity, View } from "react-native";
|
|
7
7
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
8
8
|
function TabIcon({ focused, Icon }) {
|
|
9
|
-
return (_jsxs(View, { className: "justify-center items-center w-10 h-10", children: [focused && _jsx(View, { className: "absolute w-10 h-10 rounded-full bg-primary" }), _jsx(
|
|
9
|
+
return (_jsxs(View, { className: "justify-center items-center w-10 h-10", children: [focused && _jsx(View, { className: "absolute w-10 h-10 rounded-full bg-primary" }), _jsx(DisplayIcon, { color: focused ? "#FFFFFF" : "#6B7280", customIcon: Icon, size: 24, type: "custom" })] }));
|
|
10
10
|
}
|
|
11
11
|
function TabNavigator({ items, currentPath, onTabPress, }) {
|
|
12
12
|
const insets = useSafeAreaInsets();
|