@sincpro/mobile-ui 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/README.md +75 -20
  2. package/dist/Dialog/BottomSheet/BottomSheet.Root.d.ts +13 -9
  3. package/dist/Dialog/BottomSheet/BottomSheet.Root.js +6 -2
  4. package/dist/Dialog/Confirmation.context.d.ts +1 -1
  5. package/dist/Dialog/Dialog.ActionSheet.d.ts +17 -0
  6. package/dist/Dialog/Dialog.ActionSheet.js +16 -0
  7. package/dist/Dialog/Dialog.Confirmation.js +5 -1
  8. package/dist/Dialog/Dialog.EditValue.d.ts +1 -1
  9. package/dist/Dialog/Dialog.EditValue.js +1 -1
  10. package/dist/Dialog/Dialog.Sheet.d.ts +26 -0
  11. package/dist/Dialog/Dialog.Sheet.js +55 -0
  12. package/dist/Dialog/index.d.ts +9 -7
  13. package/dist/Dialog/index.js +2 -0
  14. package/dist/Display/Display.Accordion.d.ts +18 -0
  15. package/dist/Display/Display.Accordion.js +22 -0
  16. package/dist/Display/Display.AvatarGroup.d.ts +12 -0
  17. package/dist/Display/Display.AvatarGroup.js +23 -0
  18. package/dist/Display/Display.Badge.d.ts +1 -1
  19. package/dist/Display/Display.Card.d.ts +46 -0
  20. package/dist/Display/Display.Card.js +36 -0
  21. package/dist/Display/Display.Carousel.d.ts +13 -0
  22. package/dist/Display/Display.Carousel.js +19 -0
  23. package/dist/Display/Display.Chip.d.ts +105 -0
  24. package/dist/Display/Display.Chip.js +45 -0
  25. package/dist/Display/Display.CopyableText.d.ts +1 -1
  26. package/dist/Display/Display.CountRecords.d.ts +1 -1
  27. package/dist/Display/Display.DataTable.d.ts +19 -0
  28. package/dist/Display/Display.DataTable.js +22 -0
  29. package/dist/Display/Display.Date.d.ts +15 -2
  30. package/dist/Display/Display.Date.js +34 -4
  31. package/dist/Display/Display.Divider.d.ts +1 -1
  32. package/dist/Display/Display.GradientSurface.d.ts +116 -0
  33. package/dist/Display/Display.GradientSurface.js +62 -0
  34. package/dist/Display/Display.IconBadge.d.ts +13 -0
  35. package/dist/Display/Display.IconBadge.js +30 -0
  36. package/dist/Display/Display.Image.d.ts +15 -0
  37. package/dist/Display/Display.Image.js +17 -0
  38. package/dist/Display/Display.KeyValue.d.ts +10 -0
  39. package/dist/Display/Display.KeyValue.js +9 -0
  40. package/dist/Display/Display.ListItem.d.ts +17 -0
  41. package/dist/Display/Display.ListItem.js +18 -0
  42. package/dist/Display/Display.Logo.js +3 -1
  43. package/dist/Display/Display.MediaCard.d.ts +17 -0
  44. package/dist/Display/Display.MediaCard.js +12 -0
  45. package/dist/Display/Display.MediaEmbed.d.ts +19 -0
  46. package/dist/Display/Display.MediaEmbed.js +39 -0
  47. package/dist/Display/Display.MenuButton.d.ts +1 -1
  48. package/dist/Display/Display.Monetary.d.ts +1 -1
  49. package/dist/Display/Display.Monetary.js +1 -1
  50. package/dist/Display/Display.Pattern.d.ts +26 -0
  51. package/dist/Display/Display.Pattern.js +27 -0
  52. package/dist/Display/Display.PriceTag.d.ts +10 -0
  53. package/dist/Display/Display.PriceTag.js +23 -0
  54. package/dist/Display/Display.ProductCard.d.ts +17 -0
  55. package/dist/Display/Display.ProductCard.js +13 -0
  56. package/dist/Display/Display.Rating.d.ts +11 -0
  57. package/dist/Display/Display.Rating.js +16 -0
  58. package/dist/Display/Display.SearchHistory.d.ts +12 -0
  59. package/dist/Display/Display.SearchHistory.js +13 -0
  60. package/dist/Display/Display.SectionHeader.d.ts +13 -0
  61. package/dist/Display/Display.SectionHeader.js +9 -0
  62. package/dist/Display/Display.Stat.d.ts +10 -0
  63. package/dist/Display/Display.Stat.js +9 -0
  64. package/dist/Display/Display.StatCard.d.ts +14 -0
  65. package/dist/Display/Display.StatCard.js +13 -0
  66. package/dist/Display/Display.StatusDot.d.ts +11 -0
  67. package/dist/Display/Display.StatusDot.js +28 -0
  68. package/dist/Display/Display.Story.d.ts +15 -0
  69. package/dist/Display/Display.Story.js +43 -0
  70. package/dist/Display/Display.StoryTray.d.ts +26 -0
  71. package/dist/Display/Display.StoryTray.js +43 -0
  72. package/dist/Display/Display.StoryViewer.d.ts +26 -0
  73. package/dist/Display/Display.StoryViewer.js +79 -0
  74. package/dist/Display/Display.SwipeableRow.d.ts +15 -0
  75. package/dist/Display/Display.SwipeableRow.js +28 -0
  76. package/dist/Display/Display.Tag.d.ts +11 -0
  77. package/dist/Display/Display.Tag.js +9 -0
  78. package/dist/Display/Display.Timeline.d.ts +13 -0
  79. package/dist/Display/Display.Timeline.js +19 -0
  80. package/dist/Display/Display.Tooltip.d.ts +10 -0
  81. package/dist/Display/Display.Tooltip.js +24 -0
  82. package/dist/Display/index.d.ts +70 -0
  83. package/dist/Display/index.js +58 -0
  84. package/dist/Feedback/ErrorBoundary.d.ts +1 -1
  85. package/dist/Feedback/Feedback.Banner.d.ts +82 -0
  86. package/dist/Feedback/Feedback.Banner.js +35 -0
  87. package/dist/Feedback/Feedback.DomainSplashScreen.d.ts +2 -1
  88. package/dist/Feedback/Feedback.DomainSplashScreen.js +3 -2
  89. package/dist/Feedback/Feedback.Empty.d.ts +1 -1
  90. package/dist/Feedback/Feedback.EmptyState.d.ts +15 -0
  91. package/dist/Feedback/Feedback.EmptyState.js +11 -0
  92. package/dist/Feedback/Feedback.Error.d.ts +1 -1
  93. package/dist/Feedback/Feedback.Loading.d.ts +8 -1
  94. package/dist/Feedback/Feedback.Loading.js +7 -1
  95. package/dist/Feedback/Feedback.PermissionCard.d.ts +15 -0
  96. package/dist/Feedback/Feedback.PermissionCard.js +11 -0
  97. package/dist/Feedback/Feedback.Progress.d.ts +9 -0
  98. package/dist/Feedback/Feedback.Progress.js +35 -0
  99. package/dist/Feedback/Feedback.ProgressCircle.d.ts +12 -0
  100. package/dist/Feedback/Feedback.ProgressCircle.js +15 -0
  101. package/dist/Feedback/Feedback.Skeleton.d.ts +11 -0
  102. package/dist/Feedback/Feedback.Skeleton.js +29 -0
  103. package/dist/Feedback/Feedback.Spinner.js +2 -1
  104. package/dist/Feedback/Feedback.Splash.d.ts +7 -1
  105. package/dist/Feedback/Feedback.Splash.js +11 -2
  106. package/dist/Feedback/Toast.context.d.ts +42 -0
  107. package/dist/Feedback/Toast.context.js +121 -0
  108. package/dist/Feedback/index.d.ts +15 -0
  109. package/dist/Feedback/index.js +15 -0
  110. package/dist/Form/Form.Button.d.ts +10 -4
  111. package/dist/Form/Form.Button.js +27 -16
  112. package/dist/Form/Form.Checkbox.d.ts +1 -1
  113. package/dist/Form/Form.Checkbox.js +1 -1
  114. package/dist/Form/Form.ControlledCheckbox.d.ts +1 -1
  115. package/dist/Form/Form.ControlledInput.d.ts +1 -1
  116. package/dist/Form/Form.ControlledMonetaryInput.d.ts +1 -1
  117. package/dist/Form/Form.ControlledRadioButton.d.ts +1 -1
  118. package/dist/Form/Form.DatePicker.d.ts +20 -0
  119. package/dist/Form/Form.DatePicker.js +38 -0
  120. package/dist/Form/Form.Dropdown.d.ts +1 -1
  121. package/dist/Form/Form.FAB.d.ts +10 -0
  122. package/dist/Form/Form.FAB.js +17 -0
  123. package/dist/Form/Form.FilterButton.d.ts +1 -1
  124. package/dist/Form/Form.FractionalQuantityInput.d.ts +1 -1
  125. package/dist/Form/Form.IconButton.d.ts +1 -1
  126. package/dist/Form/Form.Input.d.ts +2 -1
  127. package/dist/Form/Form.Input.js +1 -1
  128. package/dist/Form/Form.InputField.js +1 -1
  129. package/dist/Form/Form.MonetaryInput.d.ts +1 -1
  130. package/dist/Form/Form.PinInput.d.ts +12 -0
  131. package/dist/Form/Form.PinInput.js +23 -0
  132. package/dist/Form/Form.QuantitySelector.d.ts +2 -1
  133. package/dist/Form/Form.QuantitySelector.js +1 -1
  134. package/dist/Form/Form.RadioButton.d.ts +1 -1
  135. package/dist/Form/Form.SearchBar.d.ts +6 -1
  136. package/dist/Form/Form.SearchBar.js +4 -0
  137. package/dist/Form/Form.Select.d.ts +17 -0
  138. package/dist/Form/Form.Select.js +26 -0
  139. package/dist/Form/Form.Slider.d.ts +20 -0
  140. package/dist/Form/Form.Slider.js +16 -0
  141. package/dist/Form/Form.Switch.d.ts +10 -0
  142. package/dist/Form/Form.Switch.js +9 -0
  143. package/dist/Form/index.d.ts +12 -0
  144. package/dist/Form/index.js +12 -0
  145. package/dist/Navigation/Navigation.AppBar.d.ts +57 -0
  146. package/dist/Navigation/Navigation.AppBar.js +72 -0
  147. package/dist/Navigation/Navigation.BottomNav.d.ts +57 -0
  148. package/dist/Navigation/Navigation.BottomNav.js +108 -0
  149. package/dist/Navigation/Navigation.CollapsingHeader.d.ts +34 -0
  150. package/dist/Navigation/Navigation.CollapsingHeader.js +47 -0
  151. package/dist/Navigation/Navigation.FloatingBar.d.ts +15 -0
  152. package/dist/Navigation/Navigation.FloatingBar.js +21 -0
  153. package/dist/Navigation/Navigation.Header.d.ts +6 -2
  154. package/dist/Navigation/Navigation.Header.js +4 -0
  155. package/dist/Navigation/Navigation.HeaderToolbar.d.ts +1 -1
  156. package/dist/Navigation/Navigation.Menu.d.ts +21 -0
  157. package/dist/Navigation/Navigation.Menu.js +42 -0
  158. package/dist/Navigation/Navigation.RowItem.d.ts +1 -1
  159. package/dist/Navigation/Navigation.SearchBar.d.ts +18 -0
  160. package/dist/Navigation/Navigation.SearchBar.js +28 -0
  161. package/dist/Navigation/Navigation.SegmentedControl.d.ts +14 -0
  162. package/dist/Navigation/Navigation.SegmentedControl.js +13 -0
  163. package/dist/Navigation/Navigation.Steps.d.ts +8 -0
  164. package/dist/Navigation/Navigation.Steps.js +17 -0
  165. package/dist/Navigation/Navigation.TabIcon.d.ts +5 -1
  166. package/dist/Navigation/Navigation.TabIcon.js +4 -0
  167. package/dist/Navigation/Navigation.TabItem.d.ts +5 -0
  168. package/dist/Navigation/Navigation.TabItem.js +5 -0
  169. package/dist/Navigation/Navigation.Tabs.d.ts +28 -0
  170. package/dist/Navigation/Navigation.Tabs.js +45 -0
  171. package/dist/Navigation/index.d.ts +32 -1
  172. package/dist/Navigation/index.js +18 -0
  173. package/dist/Typography/Typography.Text.d.ts +3 -2
  174. package/dist/Typography/Typography.Text.js +16 -6
  175. package/dist/branding.d.ts +6 -0
  176. package/dist/branding.js +7 -0
  177. package/dist/icons/ArrowDownIcon.d.ts +2 -1
  178. package/dist/icons/ArrowUpIcon.d.ts +2 -1
  179. package/dist/icons/CreditIcon.d.ts +1 -1
  180. package/dist/icons/OdooIcon.d.ts +6 -1
  181. package/dist/icons/OdooIcon.js +5 -0
  182. package/dist/icons/PrinterIcon.d.ts +5 -0
  183. package/dist/icons/PrinterIcon.js +5 -0
  184. package/dist/index.d.ts +1 -0
  185. package/dist/index.js +2 -0
  186. package/dist/layouts/AuthContainer.d.ts +1 -1
  187. package/dist/layouts/AuthContainer.js +2 -2
  188. package/dist/layouts/Container.d.ts +1 -0
  189. package/dist/layouts/Container.js +2 -3
  190. package/dist/layouts/GradientContainer.d.ts +1 -1
  191. package/dist/layouts/PlainLayout.d.ts +1 -1
  192. package/dist/layouts/ScrollContainer.d.ts +2 -2
  193. package/dist/layouts/ScrollContainer.js +1 -1
  194. package/dist/layouts/TabNavigatorLayout.d.ts +2 -2
  195. package/dist/layouts/TabNavigatorLayout.js +4 -0
  196. package/dist/primitives/AspectRatio.d.ts +10 -0
  197. package/dist/primitives/AspectRatio.js +8 -0
  198. package/dist/primitives/Box.d.ts +1 -1
  199. package/dist/primitives/Pressable.d.ts +10 -0
  200. package/dist/primitives/Pressable.js +9 -0
  201. package/dist/primitives/Row.d.ts +1 -1
  202. package/dist/primitives/Spacer.d.ts +8 -0
  203. package/dist/primitives/Spacer.js +9 -0
  204. package/dist/primitives/Stack.d.ts +1 -1
  205. package/dist/primitives/index.d.ts +3 -0
  206. package/dist/primitives/index.js +3 -0
  207. package/dist/theme/active.d.ts +2 -0
  208. package/dist/theme/active.js +13 -0
  209. package/dist/theme/components/ThemedActivityIndicator.d.ts +1 -1
  210. package/dist/theme/components/index.d.ts +1 -1
  211. package/dist/theme/components/index.js +1 -1
  212. package/dist/theme/dark.d.ts +7 -0
  213. package/dist/theme/dark.js +85 -0
  214. package/dist/theme/default.js +1 -0
  215. package/dist/theme/define.d.ts +5 -5
  216. package/dist/theme/define.js +5 -5
  217. package/dist/theme/index.d.ts +4 -1
  218. package/dist/theme/index.js +4 -1
  219. package/dist/theme/theme.d.ts +1 -1
  220. package/dist/theme/theme.js +1 -1
  221. package/dist/theme/types.d.ts +15 -14
  222. package/dist/theme/types.js +2 -2
  223. package/dist/theme/typography.d.ts +117 -60
  224. package/dist/theme/typography.js +115 -29
  225. package/dist/theme/useTheme.d.ts +3 -1
  226. package/dist/theme/useTheme.js +6 -1
  227. package/dist/tokens/index.d.ts +2 -0
  228. package/dist/tokens/index.js +2 -0
  229. package/dist/tokens/motion.d.ts +71 -0
  230. package/dist/tokens/motion.js +25 -0
  231. package/dist/utils/date.d.ts +33 -33
  232. package/dist/utils/date.js +39 -39
  233. package/dist/utils/timezone.d.ts +5 -0
  234. package/dist/views/AuthFormView.d.ts +1 -1
  235. package/dist/views/FormViewV2.context.d.ts +1 -1
  236. package/dist/views/FormViewV2.d.ts +12 -11
  237. package/dist/views/FormViewV2.js +8 -4
  238. package/dist/views/ListViewV2.context.d.ts +6 -2
  239. package/dist/views/ListViewV2.context.js +3 -1
  240. package/dist/views/ListViewV2.d.ts +26 -21
  241. package/dist/views/ListViewV2.js +18 -20
  242. package/dist/views/Wizard/Wizard.context.d.ts +1 -1
  243. package/dist/widgets/CircleButton.d.ts +6 -2
  244. package/dist/widgets/CircleButton.js +4 -0
  245. package/dist/widgets/GeoPermissionCard.d.ts +6 -1
  246. package/dist/widgets/GeoPermissionCard.js +8 -3
  247. package/dist/widgets/HomeHeader.d.ts +4 -0
  248. package/dist/widgets/HomeHeader.js +4 -0
  249. package/dist/widgets/JSONViewer.d.ts +2 -1
  250. package/dist/widgets/JSONViewer.js +9 -12
  251. package/dist/widgets/MenuCard.d.ts +1 -1
  252. package/dist/widgets/ScreenHeader.d.ts +5 -1
  253. package/dist/widgets/ScreenHeader.js +4 -0
  254. package/dist/widgets/TimeZoneSelector.d.ts +6 -1
  255. package/dist/widgets/TimeZoneSelector.js +6 -1
  256. package/dist/widgets/TimeZoneSelectorModal.d.ts +6 -1
  257. package/dist/widgets/TimeZoneSelectorModal.js +8 -3
  258. package/package.json +41 -23
  259. package/tailwind.preset.js +14 -0
  260. package/dist/notifications/index.d.ts +0 -1
  261. package/dist/notifications/index.js +0 -1
  262. package/dist/providers/index.d.ts +0 -1
  263. package/dist/providers/index.js +0 -2
@@ -0,0 +1,57 @@
1
+ import type { CustomIconProps } from "../icons/props";
2
+ import type { ComponentType } from "react";
3
+ export interface BottomNavItem {
4
+ key: string;
5
+ label?: string;
6
+ /** Icon font name (Display.Icon). Provide this OR `customIcon`. */
7
+ icon?: string;
8
+ activeIcon?: string;
9
+ /** Brand/custom SVG icon component. Takes precedence over `icon` (for non-font brand marks). */
10
+ customIcon?: ComponentType<CustomIconProps>;
11
+ badge?: string | number;
12
+ }
13
+ export interface BottomNavCenterAction {
14
+ icon: string;
15
+ onPress: () => void;
16
+ accessibilityLabel?: string;
17
+ }
18
+ /**
19
+ * Active-tab indicator style:
20
+ * - `none`: color only.
21
+ * - `pill`: filled round pill behind the icon.
22
+ * - `pill-text`: extended pill with icon + label inside (inactive = icon only).
23
+ * - `bar`: top accent bar over the active item (label below).
24
+ * - `glow`: glowing dot under the active icon (pairs with `tone="dark"`).
25
+ */
26
+ export type BottomNavIndicator = "none" | "pill" | "pill-text" | "bar" | "glow";
27
+ export interface BottomNavProps {
28
+ items: BottomNavItem[];
29
+ value: string;
30
+ onChange: (key: string) => void;
31
+ /** Show the text label under each icon. `false` = icon-only. */
32
+ showLabels?: boolean;
33
+ /** Elevated center FAB (delivery/social apps). Splits items left/right around it. */
34
+ centerAction?: BottomNavCenterAction;
35
+ /** Reserve the bottom inset (insets.bottom). Auto-disabled for `floating`/`dark`. */
36
+ safeArea?: boolean;
37
+ /** `bar` = full-width docked bar; `floating` = self-contained rounded pill (shadow, margins). */
38
+ shape?: "bar" | "floating";
39
+ /** Surface tone. `dark` renders a dark rounded bar (pairs with `glow`). */
40
+ tone?: "light" | "dark";
41
+ /** Active-tab indicator style (see BottomNavIndicator). */
42
+ indicator?: BottomNavIndicator;
43
+ /** [light bar only] Top hairline + card surface. */
44
+ bordered?: boolean;
45
+ /** Token for the active color. `primary` (default) or `accent` (e.g. green CTA brand). */
46
+ activeColor?: "primary" | "accent";
47
+ className?: string;
48
+ testID?: string;
49
+ }
50
+ /**
51
+ * The single bottom-navigation component. Extensible by props, not by forking:
52
+ * `shape` (bar/floating), `tone` (light/dark), `indicator` (none/pill/pill-text/bar/glow),
53
+ * `showLabels`, `centerAction` (FAB), `activeColor`. Replaces the legacy `TabNavigatorLayout`.
54
+ */
55
+ declare function BottomNav({ items, value, onChange, showLabels, centerAction, safeArea, shape, tone, indicator, bordered, activeColor, className, testID, }: BottomNavProps): import("react").JSX.Element;
56
+ export default BottomNav;
57
+ export { BottomNav };
@@ -0,0 +1,108 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "nativewind/jsx-runtime";
2
+ import Icon from "../Display/Display.Icon";
3
+ import Pressable from "../primitives/Pressable";
4
+ import { theme } from "../theme";
5
+ import { cn } from "../theme/tw";
6
+ import { Typography } from "../Typography";
7
+ import { View } from "react-native";
8
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
9
+ const DARK_SURFACE = "#15181B";
10
+ /**
11
+ * The single bottom-navigation component. Extensible by props, not by forking:
12
+ * `shape` (bar/floating), `tone` (light/dark), `indicator` (none/pill/pill-text/bar/glow),
13
+ * `showLabels`, `centerAction` (FAB), `activeColor`. Replaces the legacy `TabNavigatorLayout`.
14
+ */
15
+ function BottomNav({ items, value, onChange, showLabels = true, centerAction, safeArea = true, shape = "bar", tone = "light", indicator = "none", bordered = true, activeColor = "primary", className, testID, }) {
16
+ const insets = useSafeAreaInsets();
17
+ const dark = tone === "dark";
18
+ const rounded = shape === "floating" || dark;
19
+ const bottomPad = rounded ? 6 : safeArea ? insets.bottom : 0;
20
+ const activeTint = activeColor === "accent" ? theme.accent : theme.primary;
21
+ const onActive = activeColor === "accent" ? theme.text.onAccent : theme.icon.inverse;
22
+ const inactiveColor = dark ? "rgba(255,255,255,0.55)" : theme.icon.secondary;
23
+ const surfaceColor = dark ? DARK_SURFACE : theme.bg.card;
24
+ const containerStyle = rounded
25
+ ? {
26
+ borderRadius: 32,
27
+ paddingBottom: bottomPad,
28
+ paddingTop: 6,
29
+ paddingHorizontal: 6,
30
+ minHeight: 64,
31
+ backgroundColor: surfaceColor,
32
+ ...theme.shadow.lg,
33
+ }
34
+ : {
35
+ paddingBottom: bottomPad,
36
+ minHeight: 56,
37
+ backgroundColor: surfaceColor,
38
+ ...(bordered ? { borderTopWidth: 1, borderTopColor: theme.border.light } : null),
39
+ };
40
+ const renderIconNode = (item, active, color) => {
41
+ const node = item.customIcon ? (_jsx(Icon, { color: color, customIcon: item.customIcon, size: 24, type: "custom" })) : (_jsx(Icon, { color: color, name: (active ? (item.activeIcon ?? item.icon) : item.icon) ?? "", size: 24 }));
42
+ return (_jsxs(View, { children: [node, item.badge != null ? (_jsx(View, { className: "absolute bg-danger rounded-full min-w-[16px] h-4 px-1 items-center justify-center", style: { top: -4, right: -10, borderWidth: 2, borderColor: surfaceColor }, children: _jsx(Typography.Text, { style: { color: theme.text.inverse, fontSize: 9, lineHeight: 11 }, children: item.badge }) })) : null] }));
43
+ };
44
+ const renderItem = (item) => {
45
+ const active = item.key === value;
46
+ // Variant A — extended pill with text (active = horizontal pill, inactive = icon only).
47
+ if (indicator === "pill-text") {
48
+ if (active) {
49
+ return (_jsxs(Pressable, { accessibilityLabel: item.label ?? item.key, accessibilityRole: "tab", accessibilityState: { selected: true }, className: "flex-row items-center px-4 py-2", onPress: () => onChange(item.key), style: { borderRadius: 999, backgroundColor: activeTint }, children: [renderIconNode(item, true, onActive), item.label ? (_jsx(Typography.Text, { semibold: true, style: { color: onActive, fontSize: 13, marginLeft: 8 }, children: item.label })) : null] }, item.key));
50
+ }
51
+ return (_jsx(Pressable, { accessibilityLabel: item.label ?? item.key, accessibilityRole: "tab", className: "items-center justify-center px-3 py-2", onPress: () => onChange(item.key), children: renderIconNode(item, false, inactiveColor) }, item.key));
52
+ }
53
+ // Variants none / pill / bar / glow — vertical icon + optional indicator + optional label.
54
+ const inPill = indicator === "pill" && active;
55
+ const iconColor = inPill
56
+ ? onActive
57
+ : active
58
+ ? indicator === "glow"
59
+ ? activeTint
60
+ : activeTint
61
+ : inactiveColor;
62
+ const labelColor = active ? (dark ? "#FFFFFF" : activeTint) : inactiveColor;
63
+ return (_jsxs(Pressable, { accessibilityLabel: item.label ?? item.key, accessibilityRole: "tab", accessibilityState: { selected: active }, className: "flex-1 items-center justify-center py-1.5", onPress: () => onChange(item.key), children: [indicator === "bar" && active ? (_jsx(View, { style: {
64
+ position: "absolute",
65
+ top: 0,
66
+ width: 26,
67
+ height: 3,
68
+ borderRadius: 999,
69
+ backgroundColor: activeTint,
70
+ } })) : null, _jsx(View, { className: inPill ? "px-5 py-1.5" : undefined, style: inPill ? { borderRadius: 999, backgroundColor: activeTint } : undefined, children: renderIconNode(item, active, iconColor) }), indicator === "glow" && active ? (_jsx(View, { style: {
71
+ width: 5,
72
+ height: 5,
73
+ borderRadius: 999,
74
+ marginTop: 4,
75
+ backgroundColor: activeTint,
76
+ shadowColor: activeTint,
77
+ shadowOpacity: 0.9,
78
+ shadowRadius: 5,
79
+ elevation: 4,
80
+ } })) : null, showLabels && item.label && indicator !== "glow" ? (_jsx(Typography.Text, { numberOfLines: 1, semibold: active, style: { color: labelColor, fontSize: 11, marginTop: 3 }, children: item.label })) : null] }, item.key));
81
+ };
82
+ const renderCenterFab = () => (_jsx(Pressable, { accessibilityLabel: centerAction?.accessibilityLabel ?? "Acción", accessibilityRole: "button", className: "items-center justify-center", onPress: centerAction?.onPress, style: {
83
+ width: 52,
84
+ height: 52,
85
+ borderRadius: 18,
86
+ marginTop: -20,
87
+ marginHorizontal: 6,
88
+ backgroundColor: activeTint,
89
+ // Glow halo en el color de acento (iOS shadow + Android elevation).
90
+ shadowColor: activeTint,
91
+ shadowOffset: { width: 0, height: 4 },
92
+ shadowOpacity: 0.55,
93
+ shadowRadius: 14,
94
+ elevation: 10,
95
+ }, children: _jsx(Icon, { color: onActive, name: centerAction?.icon ?? "add", size: 26 }) }));
96
+ let content;
97
+ if (centerAction) {
98
+ const mid = Math.ceil(items.length / 2);
99
+ content = (_jsxs(_Fragment, { children: [items.slice(0, mid).map(renderItem), renderCenterFab(), items.slice(mid).map(renderItem)] }));
100
+ }
101
+ else {
102
+ content = items.map(renderItem);
103
+ }
104
+ const justify = indicator === "pill-text" ? "justify-around" : "";
105
+ return (_jsx(View, { className: cn("flex-row items-center", justify, className), style: containerStyle, testID: testID, children: content }));
106
+ }
107
+ export default BottomNav;
108
+ export { BottomNav };
@@ -0,0 +1,34 @@
1
+ import { type AppBarActionProps } from "../Navigation/Navigation.AppBar";
2
+ import type { ReactNode } from "react";
3
+ import { Animated } from "react-native";
4
+ export interface CollapsingHeaderProps {
5
+ title: string;
6
+ subtitle?: string;
7
+ scrollY: Animated.Value;
8
+ onBack?: () => void;
9
+ actions?: ReactNode;
10
+ /** Extra height of the collapsing large-title (px). Default 56, or 72 with subtitle. */
11
+ largeHeight?: number;
12
+ /** Reserves the status-bar space (insets.top). `false` to embed/demo. */
13
+ safeArea?: boolean;
14
+ testID?: string;
15
+ }
16
+ /**
17
+ * Header with a large-title that **collapses on scroll** (merge of iOS 26 large title +
18
+ * Material 3 large top app bar). The compact bar stays fixed and its title fades in while
19
+ * scrolling; the large-title fades out and slides up. Controlled by an `Animated.Value`.
20
+ *
21
+ * Usage: pass `scrollY` from your `Animated.ScrollView`. Since the large-title collapses its
22
+ * `height` (not supported by the native driver), use `useNativeDriver: false`:
23
+ * ```tsx
24
+ * const scrollY = useRef(new Animated.Value(0)).current;
25
+ * <CollapsingHeader title="Inicio" scrollY={scrollY} />
26
+ * <Animated.ScrollView
27
+ * onScroll={Animated.event([{ nativeEvent: { contentOffset: { y: scrollY } } }], { useNativeDriver: false })}
28
+ * scrollEventThrottle={16}
29
+ * />
30
+ * ```
31
+ */
32
+ declare function CollapsingHeader({ title, subtitle, scrollY, onBack, actions, largeHeight, safeArea, testID, }: CollapsingHeaderProps): import("react").JSX.Element;
33
+ export type { AppBarActionProps };
34
+ export default CollapsingHeader;
@@ -0,0 +1,47 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
2
+ import AppBar from "../Navigation/Navigation.AppBar";
3
+ import { theme } from "../theme";
4
+ import { Typography } from "../Typography";
5
+ import { Animated, View } from "react-native";
6
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
7
+ /**
8
+ * Header with a large-title that **collapses on scroll** (merge of iOS 26 large title +
9
+ * Material 3 large top app bar). The compact bar stays fixed and its title fades in while
10
+ * scrolling; the large-title fades out and slides up. Controlled by an `Animated.Value`.
11
+ *
12
+ * Usage: pass `scrollY` from your `Animated.ScrollView`. Since the large-title collapses its
13
+ * `height` (not supported by the native driver), use `useNativeDriver: false`:
14
+ * ```tsx
15
+ * const scrollY = useRef(new Animated.Value(0)).current;
16
+ * <CollapsingHeader title="Inicio" scrollY={scrollY} />
17
+ * <Animated.ScrollView
18
+ * onScroll={Animated.event([{ nativeEvent: { contentOffset: { y: scrollY } } }], { useNativeDriver: false })}
19
+ * scrollEventThrottle={16}
20
+ * />
21
+ * ```
22
+ */
23
+ function CollapsingHeader({ title, subtitle, scrollY, onBack, actions, largeHeight = subtitle ? 72 : 56, safeArea = true, testID, }) {
24
+ const insets = useSafeAreaInsets();
25
+ const largeOpacity = scrollY.interpolate({
26
+ inputRange: [0, largeHeight * 0.6],
27
+ outputRange: [1, 0],
28
+ extrapolate: "clamp",
29
+ });
30
+ const largeTranslate = scrollY.interpolate({
31
+ inputRange: [0, largeHeight],
32
+ outputRange: [0, -largeHeight / 2],
33
+ extrapolate: "clamp",
34
+ });
35
+ const largeContainerHeight = scrollY.interpolate({
36
+ inputRange: [0, largeHeight],
37
+ outputRange: [largeHeight, 0],
38
+ extrapolate: "clamp",
39
+ });
40
+ const compactTitleOpacity = scrollY.interpolate({
41
+ inputRange: [largeHeight * 0.6, largeHeight],
42
+ outputRange: [0, 1],
43
+ extrapolate: "clamp",
44
+ });
45
+ return (_jsxs(View, { style: { backgroundColor: theme.bg.card }, testID: testID, children: [_jsx(View, { style: { paddingTop: safeArea ? insets.top : 0 }, children: _jsxs(View, { className: "flex-row items-center px-3 gap-2 min-h-[52px]", children: [_jsx(View, { style: { minWidth: 38 }, children: onBack ? (_jsx(AppBar.Action, { accessibilityLabel: "Volver", icon: "chevron-back", onPress: onBack })) : null }), _jsx(Animated.View, { className: "flex-1", style: { opacity: compactTitleOpacity }, children: _jsx(Typography.Text, { className: "text-text-primary", numberOfLines: 1, semibold: true, variant: "subtitle", children: title }) }), _jsx(View, { className: "flex-row items-center justify-end gap-2", style: { minWidth: 38 }, children: actions })] }) }), _jsx(Animated.View, { style: { height: largeContainerHeight, overflow: "hidden" }, children: _jsxs(Animated.View, { className: "px-4 pb-2", style: { opacity: largeOpacity, transform: [{ translateY: largeTranslate }] }, children: [_jsx(Typography.Text, { className: "text-text-primary", variant: "h2", children: title }), subtitle ? (_jsx(Typography.Text, { className: "text-text-secondary", variant: "bodySmall", children: subtitle })) : null] }) }), _jsx(View, { className: "border-b border-border-light" })] }));
46
+ }
47
+ export default CollapsingHeader;
@@ -0,0 +1,15 @@
1
+ import type { ReactNode } from "react";
2
+ export interface FloatingBarProps {
3
+ children: ReactNode;
4
+ position?: "top" | "bottom";
5
+ inset?: number;
6
+ className?: string;
7
+ testID?: string;
8
+ }
9
+ /**
10
+ * **Rounded floating container** for nav/action bars that float above the content
11
+ * (Snapchat/TikTok/McDonald's 2026 style). Shadowed pill, safe-area aware.
12
+ * Presentational: drop a `BottomNav`, actions, or anything inside.
13
+ */
14
+ declare function FloatingBar({ children, position, inset, className, testID, }: FloatingBarProps): import("react").JSX.Element;
15
+ export default FloatingBar;
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx } from "nativewind/jsx-runtime";
2
+ import { theme } from "../theme";
3
+ import { cn } from "../theme/tw";
4
+ import { View } from "react-native";
5
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
6
+ /**
7
+ * **Rounded floating container** for nav/action bars that float above the content
8
+ * (Snapchat/TikTok/McDonald's 2026 style). Shadowed pill, safe-area aware.
9
+ * Presentational: drop a `BottomNav`, actions, or anything inside.
10
+ */
11
+ function FloatingBar({ children, position = "bottom", inset = 16, className, testID, }) {
12
+ const insets = useSafeAreaInsets();
13
+ const safe = position === "bottom" ? insets.bottom : insets.top;
14
+ return (_jsx(View, { pointerEvents: "box-none", style: {
15
+ position: "absolute",
16
+ left: inset,
17
+ right: inset,
18
+ [position]: safe + inset,
19
+ }, testID: testID, children: _jsx(View, { className: cn("rounded-full bg-bg-card px-2 py-1.5 border border-border-light", className), style: theme.shadow.lg, children: children }) }));
20
+ }
21
+ export default FloatingBar;
@@ -1,4 +1,4 @@
1
- import { ReactNode } from "react";
1
+ import React, { ReactNode } from "react";
2
2
  import { type ImageSourcePropType } from "react-native";
3
3
  export interface HeaderProps {
4
4
  title?: string;
@@ -8,5 +8,9 @@ export interface HeaderProps {
8
8
  handleBackButton?: () => void;
9
9
  className?: string;
10
10
  }
11
- declare const Header: ({ title, logo, logoSource, backButton, handleBackButton, className, }: HeaderProps) => import("react/jsx-runtime").JSX.Element;
11
+ /**
12
+ * @deprecated Legacy style (forced gradient via `GradientContainer`). Use
13
+ * `Navigation.AppBar` (flat, modern, opt-in gradient). Kept for backwards compatibility.
14
+ */
15
+ declare const Header: ({ title, logo, logoSource, backButton, handleBackButton, className, }: HeaderProps) => React.JSX.Element;
12
16
  export default Header;
@@ -5,6 +5,10 @@ import { theme } from "../theme";
5
5
  import { cn } from "../theme/tw";
6
6
  import { Typography } from "../Typography";
7
7
  import { TouchableOpacity, View } from "react-native";
8
+ /**
9
+ * @deprecated Legacy style (forced gradient via `GradientContainer`). Use
10
+ * `Navigation.AppBar` (flat, modern, opt-in gradient). Kept for backwards compatibility.
11
+ */
8
12
  const Header = ({ title, logo, logoSource, backButton, handleBackButton, className, }) => {
9
13
  const onBackPress = handleBackButton ?? (() => { });
10
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(Display.Icon, { color: theme.text.inverse, name: "chevron-back", size: 25, type: "ionicons" }) })), _jsxs(View, { className: "items-center justify-center", children: [logo || _jsx(Display.Logo, { size: "medium", source: logoSource }), title && (_jsx(Typography.Text, { className: "text-white", variant: "h4", children: title }))] })] }) }));
@@ -11,5 +11,5 @@ interface HeaderToolbarProps {
11
11
  withBackground?: boolean;
12
12
  className?: string;
13
13
  }
14
- declare function HeaderToolbar({ title, subtitle, onBack, rightComponent, centerTitle, flat, children, logo, withBackground, className, }: HeaderToolbarProps): import("react/jsx-runtime").JSX.Element;
14
+ declare function HeaderToolbar({ title, subtitle, onBack, rightComponent, centerTitle, flat, children, logo, withBackground, className, }: HeaderToolbarProps): React.JSX.Element;
15
15
  export default HeaderToolbar;
@@ -0,0 +1,21 @@
1
+ import { type ReactNode } from "react";
2
+ export interface MenuItem {
3
+ label: string;
4
+ icon?: string;
5
+ destructive?: boolean;
6
+ disabled?: boolean;
7
+ onPress: () => void;
8
+ }
9
+ export interface MenuSeparator {
10
+ separator: true;
11
+ }
12
+ export type MenuEntry = MenuItem | MenuSeparator;
13
+ export interface MenuProps {
14
+ items: MenuEntry[];
15
+ trigger?: ReactNode;
16
+ menuWidth?: number;
17
+ testID?: string;
18
+ }
19
+ declare function Menu({ items, trigger, menuWidth, testID }: MenuProps): import("react").JSX.Element;
20
+ export default Menu;
21
+ export { Menu };
@@ -0,0 +1,42 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
2
+ import Icon from "../Display/Display.Icon";
3
+ import Pressable from "../primitives/Pressable";
4
+ import { theme } from "../theme";
5
+ import { cn } from "../theme/tw";
6
+ import { Typography } from "../Typography";
7
+ import { useRef, useState } from "react";
8
+ import { Dimensions, Modal, Pressable as RNPressable, View } from "react-native";
9
+ function Menu({ items, trigger, menuWidth = 220, testID }) {
10
+ const triggerRef = useRef(null);
11
+ const [anchor, setAnchor] = useState(null);
12
+ const open = () => {
13
+ triggerRef.current?.measureInWindow((x, y, width, height) => {
14
+ setAnchor({ x, y, width, height });
15
+ });
16
+ };
17
+ const close = () => setAnchor(null);
18
+ const screen = Dimensions.get("window");
19
+ const right = anchor ? Math.max(8, screen.width - (anchor.x + anchor.width)) : 8;
20
+ const top = anchor ? anchor.y + anchor.height + 4 : 0;
21
+ return (_jsxs(View, { collapsable: false, ref: triggerRef, testID: testID, children: [_jsx(Pressable, { accessibilityLabel: "M\u00E1s opciones", accessibilityRole: "button", onPress: open, children: trigger ?? _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
+ position: "absolute",
23
+ top,
24
+ right,
25
+ width: menuWidth,
26
+ backgroundColor: theme.bg.popover,
27
+ borderWidth: 1,
28
+ borderColor: theme.border.light,
29
+ ...theme.shadow.lg,
30
+ }, children: items.map((entry, index) => {
31
+ if ("separator" in entry && entry.separator) {
32
+ return _jsx(View, { className: "my-1 h-px bg-border-default" }, `sep-${index}`);
33
+ }
34
+ const item = entry;
35
+ return (_jsxs(Pressable, { accessibilityRole: "menuitem", accessibilityState: { disabled: item.disabled }, className: "flex-row items-center gap-3 px-4 py-3", disabled: item.disabled, onPress: () => {
36
+ close();
37
+ item.onPress();
38
+ }, children: [item.icon ? (_jsx(Icon, { color: item.destructive ? theme.danger : theme.icon.secondary, name: item.icon, size: 18 })) : null, _jsx(Typography.Text, { className: cn("flex-1 text-sm", item.destructive ? "text-danger" : "text-text-primary", item.disabled && "text-text-disabled"), children: item.label })] }, item.label));
39
+ }) }) }) })] }));
40
+ }
41
+ export default Menu;
42
+ export { Menu };
@@ -1,5 +1,5 @@
1
1
  import { IRowItemProps } from "../views/types/IListView";
2
2
  declare function RowItem({ item, className }: IRowItemProps<any> & {
3
3
  className?: string;
4
- }): import("react/jsx-runtime").JSX.Element;
4
+ }): import("react").JSX.Element;
5
5
  export default RowItem;
@@ -0,0 +1,18 @@
1
+ export interface SearchBarProps {
2
+ value: string;
3
+ onChangeText: (value: string) => void;
4
+ placeholder?: string;
5
+ onSubmit?: (value: string) => void;
6
+ onClear?: () => void;
7
+ autoFocus?: boolean;
8
+ editable?: boolean;
9
+ onPress?: () => void;
10
+ className?: string;
11
+ testID?: string;
12
+ }
13
+ /**
14
+ * **Pill** search bar (rounded-full), 2026 style (merge of Material 3 + iOS 26).
15
+ * Use `editable={false}` + `onPress` for a trigger that navigates to the search screen.
16
+ */
17
+ declare function SearchBar({ value, onChangeText, placeholder, onSubmit, onClear, autoFocus, editable, onPress, className, testID, }: SearchBarProps): import("react").JSX.Element;
18
+ export default SearchBar;
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
2
+ import Icon from "../Display/Display.Icon";
3
+ import Pressable from "../primitives/Pressable";
4
+ import { theme } from "../theme";
5
+ import { cn } from "../theme/tw";
6
+ import { Typography } from "../Typography";
7
+ import { useState } from "react";
8
+ import { TextInput, View } from "react-native";
9
+ /**
10
+ * **Pill** search bar (rounded-full), 2026 style (merge of Material 3 + iOS 26).
11
+ * Use `editable={false}` + `onPress` for a trigger that navigates to the search screen.
12
+ */
13
+ function SearchBar({ value, onChangeText, placeholder = "Buscar", onSubmit, onClear, autoFocus, editable = true, onPress, className, testID, }) {
14
+ const [focused, setFocused] = useState(false);
15
+ const body = (_jsxs(View, { className: cn("flex-row items-center gap-2 rounded-full px-4", focused ? "bg-bg-card" : "bg-bg-muted", className), style: {
16
+ height: 44,
17
+ borderWidth: 1,
18
+ borderColor: focused ? theme.border.focus : "transparent",
19
+ }, children: [_jsx(Icon, { color: focused ? theme.border.focus : theme.icon.tertiary, name: "search", size: 18 }), editable ? (_jsx(TextInput, { autoFocus: autoFocus, className: "flex-1 text-sm text-text-primary", onBlur: () => setFocused(false), onChangeText: onChangeText, onFocus: () => setFocused(true), onSubmitEditing: (e) => onSubmit?.(e.nativeEvent.text), placeholder: placeholder, placeholderTextColor: theme.text.tertiary, returnKeyType: "search", value: value })) : (_jsx(Typography.Text, { className: "flex-1 text-text-tertiary text-sm", numberOfLines: 1, children: value || placeholder })), editable && value.length > 0 ? (_jsx(Pressable, { accessibilityLabel: "Limpiar", hitSlop: 8, onPress: () => {
20
+ onChangeText("");
21
+ onClear?.();
22
+ }, children: _jsx(Icon, { color: theme.icon.tertiary, name: "close-circle", size: 18 }) })) : null] }));
23
+ if (!editable && onPress) {
24
+ return (_jsx(Pressable, { accessibilityLabel: placeholder, accessibilityRole: "search", onPress: onPress, testID: testID, children: body }));
25
+ }
26
+ return _jsx(View, { testID: testID, children: body });
27
+ }
28
+ export default SearchBar;
@@ -0,0 +1,14 @@
1
+ export interface SegmentedOption<T extends string> {
2
+ label: string;
3
+ value: T;
4
+ }
5
+ export interface SegmentedControlProps<T extends string> {
6
+ options: SegmentedOption<T>[];
7
+ value: T;
8
+ onChange: (value: T) => void;
9
+ className?: string;
10
+ testID?: string;
11
+ }
12
+ declare function SegmentedControl<T extends string>({ options, value, onChange, className, testID, }: SegmentedControlProps<T>): import("react").JSX.Element;
13
+ export default SegmentedControl;
14
+ export { SegmentedControl };
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx } from "nativewind/jsx-runtime";
2
+ import { theme } from "../theme";
3
+ import { cn } from "../theme/tw";
4
+ import { Typography } from "../Typography";
5
+ import { TouchableOpacity, View } from "react-native";
6
+ function SegmentedControl({ options, value, onChange, className, testID, }) {
7
+ 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
+ const selected = option.value === value;
9
+ return (_jsx(TouchableOpacity, { accessibilityLabel: option.label, accessibilityRole: "tab", accessibilityState: { selected }, activeOpacity: 0.7, className: "flex-1 items-center justify-center py-2 rounded-md", onPress: () => onChange(option.value), style: selected ? { backgroundColor: theme.bg.card, ...theme.shadow.sm } : undefined, children: _jsx(Typography.Text, { numberOfLines: 1, semibold: selected, style: { color: selected ? theme.text.primary : theme.text.secondary }, children: option.label }) }, option.value));
10
+ }) }));
11
+ }
12
+ export default SegmentedControl;
13
+ export { SegmentedControl };
@@ -0,0 +1,8 @@
1
+ export interface StepsProps {
2
+ steps: string[];
3
+ current: number;
4
+ className?: string;
5
+ testID?: string;
6
+ }
7
+ declare function Steps({ steps, current, className, testID }: StepsProps): import("react").JSX.Element;
8
+ export default Steps;
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
2
+ import Icon from "../Display/Display.Icon";
3
+ import { theme } from "../theme";
4
+ import { cn } from "../theme/tw";
5
+ import { Typography } from "../Typography";
6
+ import { View } from "react-native";
7
+ function Steps({ steps, current, className, testID }) {
8
+ return (_jsx(View, { accessibilityLabel: `Paso ${current + 1} de ${steps.length}`, className: cn("flex-row items-start", className), testID: testID, children: steps.map((label, index) => {
9
+ const done = index < current;
10
+ const active = index === current;
11
+ const circleColor = done || active ? theme.primary : theme.bg.muted;
12
+ const textColor = done || active ? theme.text.inverse : theme.text.tertiary;
13
+ const isLast = index === steps.length - 1;
14
+ return (_jsxs(View, { className: "flex-1 items-center", children: [_jsxs(View, { className: "flex-row items-center w-full", children: [_jsx(View, { className: "flex-1 h-0.5", style: { backgroundColor: "transparent" } }), _jsx(View, { className: "w-7 h-7 rounded-full items-center justify-center", style: { backgroundColor: circleColor }, children: done ? (_jsx(Icon, { color: theme.text.inverse, name: "checkmark", size: 16 })) : (_jsx(Typography.Text, { style: { color: textColor }, variant: "bodySmall", children: index + 1 })) }), _jsx(View, { className: "flex-1 h-0.5", style: { backgroundColor: isLast ? "transparent" : theme.border.default } })] }), _jsx(Typography.Text, { className: "mt-1 text-center", numberOfLines: 1, style: { color: active ? theme.primary : theme.text.tertiary }, variant: "caption", children: label })] }, label));
15
+ }) }));
16
+ }
17
+ export default Steps;
@@ -10,5 +10,9 @@ interface TabIconProps {
10
10
  name?: any;
11
11
  className?: string;
12
12
  }
13
- declare function TabIcon({ focused, size, customIcon, type, name, className, }: TabIconProps): import("react/jsx-runtime").JSX.Element;
13
+ /**
14
+ * @deprecated Orphan tab-bar icon piece (unused). Use `Navigation.BottomNav` (single source
15
+ * of truth for the bottom tab bar). Kept for backwards compatibility; removed in the next major.
16
+ */
17
+ declare function TabIcon({ focused, size, customIcon, type, name, className, }: TabIconProps): import("react").JSX.Element;
14
18
  export default TabIcon;
@@ -3,6 +3,10 @@ import { Display } from "../Display";
3
3
  import { cn } from "../theme/tw";
4
4
  import { View } from "react-native";
5
5
  const Icon = Display.Icon;
6
+ /**
7
+ * @deprecated Orphan tab-bar icon piece (unused). Use `Navigation.BottomNav` (single source
8
+ * of truth for the bottom tab bar). Kept for backwards compatibility; removed in the next major.
9
+ */
6
10
  function TabIcon({ focused, size = 24, customIcon, type = "custom", name, className, }) {
7
11
  return (_jsx(View, { className: cn("justify-center items-center h-9 w-14 rounded-2xl", focused && "bg-primary shadow-sm", className), children: _jsx(Icon, { className: focused ? "text-white" : "text-text-secondary", customIcon: customIcon, name: name, size: size, type: type }) }));
8
12
  }
@@ -10,5 +10,10 @@ export interface TabIconProps {
10
10
  name?: any;
11
11
  className?: string;
12
12
  }
13
+ /**
14
+ * @deprecated Orphan tab-bar icon piece (unused). The bottom tab bar is now the single
15
+ * `Navigation.BottomNav` (configurable shape/indicator/labels/FAB). Kept for backwards
16
+ * compatibility; removed in the next major.
17
+ */
13
18
  declare const TabIcon: FC<TabIconProps>;
14
19
  export default TabIcon;
@@ -2,6 +2,11 @@ import { jsx as _jsx } from "nativewind/jsx-runtime";
2
2
  import { Display } from "../Display";
3
3
  import { cn } from "../theme/tw";
4
4
  import { View } from "react-native";
5
+ /**
6
+ * @deprecated Orphan tab-bar icon piece (unused). The bottom tab bar is now the single
7
+ * `Navigation.BottomNav` (configurable shape/indicator/labels/FAB). Kept for backwards
8
+ * compatibility; removed in the next major.
9
+ */
5
10
  const TabIcon = ({ focused, size = 24, customIcon, type = "custom", name, className, }) => {
6
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(Display.Icon, { color: focused ? "#FFFFFF" : "#6B7280", customIcon: customIcon, name: name, size: size, type: type }) }));
7
12
  };
@@ -0,0 +1,28 @@
1
+ import { type ReactNode } from "react";
2
+ export interface TabsProps {
3
+ value?: string;
4
+ defaultValue?: string;
5
+ onValueChange?: (value: string) => void;
6
+ className?: string;
7
+ children: ReactNode;
8
+ }
9
+ declare function TabsRoot({ value, defaultValue, onValueChange, className, children }: TabsProps): import("react").JSX.Element;
10
+ declare function TabsList({ children, className }: {
11
+ children: ReactNode;
12
+ className?: string;
13
+ }): import("react").JSX.Element;
14
+ declare function TabsTrigger({ value, children }: {
15
+ value: string;
16
+ children: ReactNode;
17
+ }): import("react").JSX.Element;
18
+ declare function TabsContent({ value, children }: {
19
+ value: string;
20
+ children: ReactNode;
21
+ }): import("react").JSX.Element | null;
22
+ declare const Tabs: typeof TabsRoot & {
23
+ List: typeof TabsList;
24
+ Trigger: typeof TabsTrigger;
25
+ Content: typeof TabsContent;
26
+ };
27
+ export default Tabs;
28
+ export { Tabs };
@@ -0,0 +1,45 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
2
+ import { theme } from "../theme";
3
+ import { cn } from "../theme/tw";
4
+ import { Typography } from "../Typography";
5
+ import { createContext, useCallback, useContext, useState } from "react";
6
+ import { TouchableOpacity, View } from "react-native";
7
+ const TabsContext = createContext(null);
8
+ function useTabs() {
9
+ const ctx = useContext(TabsContext);
10
+ if (!ctx) {
11
+ throw new Error("Tabs.* debe usarse dentro de <Tabs>");
12
+ }
13
+ return ctx;
14
+ }
15
+ function TabsRoot({ value, defaultValue, onValueChange, className, children }) {
16
+ const [internal, setInternal] = useState(defaultValue ?? "");
17
+ const current = value ?? internal;
18
+ const setValue = useCallback((next) => {
19
+ if (value === undefined)
20
+ setInternal(next);
21
+ onValueChange?.(next);
22
+ }, [value, onValueChange]);
23
+ return (_jsx(TabsContext.Provider, { value: { value: current, setValue }, children: _jsx(View, { className: cn("flex-1", className), children: children }) }));
24
+ }
25
+ function TabsList({ children, className }) {
26
+ return (_jsx(View, { accessibilityRole: "tablist", className: cn("flex-row border-b border-border-default", className), children: children }));
27
+ }
28
+ function TabsTrigger({ value, children }) {
29
+ const { value: active, setValue } = useTabs();
30
+ const selected = active === value;
31
+ return (_jsxs(TouchableOpacity, { accessibilityRole: "tab", accessibilityState: { selected }, activeOpacity: 0.7, className: "flex-1 items-center", onPress: () => setValue(value), children: [_jsx(View, { className: "py-3", children: _jsx(Typography.Text, { semibold: selected, style: { color: selected ? theme.primary : theme.text.secondary }, children: children }) }), _jsx(View, { className: "h-0.5 w-full", style: { backgroundColor: selected ? theme.primary : "transparent" } })] }));
32
+ }
33
+ function TabsContent({ value, children }) {
34
+ const { value: active } = useTabs();
35
+ if (active !== value)
36
+ return null;
37
+ return _jsx(View, { className: "flex-1", children: children });
38
+ }
39
+ const Tabs = Object.assign(TabsRoot, {
40
+ List: TabsList,
41
+ Trigger: TabsTrigger,
42
+ Content: TabsContent,
43
+ });
44
+ export default Tabs;
45
+ export { Tabs };