@sincpro/mobile-ui 0.7.2 → 1.1.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.
Files changed (313) hide show
  1. package/README.md +575 -230
  2. package/dist/Actions/Actions.Button.d.ts +98 -93
  3. package/dist/Actions/Actions.Button.js +58 -52
  4. package/dist/Actions/Actions.FAB.d.ts +3 -1
  5. package/dist/Actions/Actions.FAB.js +12 -8
  6. package/dist/Actions/Actions.FilterButton.d.ts +10 -2
  7. package/dist/Actions/Actions.FilterButton.js +23 -8
  8. package/dist/Actions/Actions.IconButton.d.ts +36 -33
  9. package/dist/Actions/Actions.IconButton.js +10 -6
  10. package/dist/Actions/index.d.ts +12 -12
  11. package/dist/Actions/index.js +6 -6
  12. package/dist/Dialog/BottomSheet/BottomSheet.Root.js +1 -1
  13. package/dist/Dialog/BottomSheet/index.d.ts +1 -1
  14. package/dist/Dialog/BottomSheet/index.js +1 -1
  15. package/dist/Dialog/Confirmation.context.js +3 -3
  16. package/dist/Dialog/Dialog.ActionSheet.d.ts +2 -1
  17. package/dist/Dialog/Dialog.ActionSheet.js +19 -9
  18. package/dist/Dialog/Dialog.Confirmation.js +7 -7
  19. package/dist/Dialog/Dialog.EditValue.js +4 -4
  20. package/dist/Dialog/Dialog.NativeSheet.d.ts +10 -0
  21. package/dist/Dialog/Dialog.NativeSheet.js +21 -0
  22. package/dist/Dialog/Dialog.Sheet.d.ts +5 -1
  23. package/dist/Dialog/Dialog.Sheet.js +19 -11
  24. package/dist/Dialog/index.d.ts +5 -5
  25. package/dist/Dialog/index.js +5 -5
  26. package/dist/Display/Display.Accordion.js +5 -5
  27. package/dist/Display/Display.Avatar.d.ts +30 -30
  28. package/dist/Display/Display.Avatar.js +2 -2
  29. package/dist/Display/Display.AvatarGroup.js +3 -3
  30. package/dist/Display/Display.Badge.d.ts +3 -3
  31. package/dist/Display/Display.Badge.js +1 -1
  32. package/dist/Display/Display.Card.d.ts +15 -15
  33. package/dist/Display/Display.Card.js +4 -4
  34. package/dist/Display/Display.Carousel.js +2 -2
  35. package/dist/Display/Display.Chip.d.ts +3 -3
  36. package/dist/Display/Display.Chip.js +12 -12
  37. package/dist/Display/Display.CircleButton.d.ts +1 -1
  38. package/dist/Display/Display.CircleButton.js +3 -3
  39. package/dist/Display/Display.CopyableText.d.ts +9 -2
  40. package/dist/Display/Display.CopyableText.js +76 -8
  41. package/dist/Display/Display.CountRecords.js +2 -2
  42. package/dist/Display/Display.DataTable.js +2 -2
  43. package/dist/Display/Display.Date.d.ts +1 -1
  44. package/dist/Display/Display.Date.js +5 -5
  45. package/dist/Display/Display.Divider.d.ts +24 -24
  46. package/dist/Display/Display.Divider.js +1 -1
  47. package/dist/Display/Display.GradientSurface.d.ts +58 -39
  48. package/dist/Display/Display.GradientSurface.js +31 -15
  49. package/dist/Display/Display.Icon.d.ts +1 -1
  50. package/dist/Display/Display.Icon.js +2 -1
  51. package/dist/Display/Display.IconBadge.js +3 -3
  52. package/dist/Display/Display.Image.js +4 -4
  53. package/dist/Display/Display.KeyValue.d.ts +11 -4
  54. package/dist/Display/Display.KeyValue.js +8 -6
  55. package/dist/Display/Display.ListGroup.d.ts +23 -0
  56. package/dist/Display/Display.ListGroup.js +17 -0
  57. package/dist/Display/Display.ListItem.d.ts +16 -2
  58. package/dist/Display/Display.ListItem.js +29 -12
  59. package/dist/Display/Display.Logo.d.ts +3 -3
  60. package/dist/Display/Display.Logo.js +2 -2
  61. package/dist/Display/Display.MediaCard.js +4 -4
  62. package/dist/Display/Display.MediaEmbed.js +7 -7
  63. package/dist/Display/Display.MenuButton.d.ts +4 -4
  64. package/dist/Display/Display.MenuButton.js +6 -6
  65. package/dist/Display/Display.MenuCard.d.ts +1 -1
  66. package/dist/Display/Display.MenuCard.js +3 -3
  67. package/dist/Display/Display.MenuGrid.d.ts +1 -1
  68. package/dist/Display/Display.MenuGrid.js +1 -1
  69. package/dist/Display/Display.Monetary.d.ts +1 -1
  70. package/dist/Display/Display.Monetary.js +2 -2
  71. package/dist/Display/Display.Pattern.d.ts +33 -12
  72. package/dist/Display/Display.Pattern.js +60 -14
  73. package/dist/Display/Display.PriceTag.js +2 -2
  74. package/dist/Display/Display.ProductCard.js +7 -7
  75. package/dist/Display/Display.Rating.js +3 -3
  76. package/dist/Display/Display.SearchHistory.js +6 -6
  77. package/dist/Display/Display.SectionHeader.d.ts +11 -1
  78. package/dist/Display/Display.SectionHeader.js +14 -5
  79. package/dist/Display/Display.Stat.js +2 -2
  80. package/dist/Display/Display.StatCard.js +4 -4
  81. package/dist/Display/Display.StatusDot.js +3 -3
  82. package/dist/Display/Display.Story.js +3 -3
  83. package/dist/Display/Display.StoryTray.js +5 -5
  84. package/dist/Display/Display.StoryViewer.js +4 -4
  85. package/dist/Display/Display.SwipeableRow.d.ts +3 -1
  86. package/dist/Display/Display.SwipeableRow.js +7 -7
  87. package/dist/Display/Display.Tag.js +2 -2
  88. package/dist/Display/Display.Timeline.js +4 -4
  89. package/dist/Display/Display.Tooltip.js +3 -3
  90. package/dist/Display/index.d.ts +49 -45
  91. package/dist/Display/index.js +44 -42
  92. package/dist/Feedback/ErrorBoundary.d.ts +1 -1
  93. package/dist/Feedback/ErrorBoundary.js +1 -1
  94. package/dist/Feedback/Feedback.Banner.d.ts +3 -3
  95. package/dist/Feedback/Feedback.Banner.js +6 -6
  96. package/dist/Feedback/Feedback.DomainSplashScreen.js +5 -4
  97. package/dist/Feedback/Feedback.Empty.js +3 -3
  98. package/dist/Feedback/Feedback.EmptyState.d.ts +2 -1
  99. package/dist/Feedback/Feedback.EmptyState.js +7 -7
  100. package/dist/Feedback/Feedback.Error.d.ts +3 -1
  101. package/dist/Feedback/Feedback.Error.js +7 -6
  102. package/dist/Feedback/Feedback.Loading.d.ts +1 -1
  103. package/dist/Feedback/Feedback.Loading.js +2 -2
  104. package/dist/Feedback/Feedback.PermissionCard.js +5 -5
  105. package/dist/Feedback/Feedback.Progress.js +2 -2
  106. package/dist/Feedback/Feedback.ProgressCircle.js +1 -1
  107. package/dist/Feedback/Feedback.Skeleton.js +2 -2
  108. package/dist/Feedback/Feedback.Spinner.js +3 -3
  109. package/dist/Feedback/Feedback.Splash.d.ts +1 -1
  110. package/dist/Feedback/Feedback.Splash.js +7 -6
  111. package/dist/Feedback/Toast.context.js +7 -7
  112. package/dist/Feedback/index.d.ts +13 -13
  113. package/dist/Feedback/index.js +13 -13
  114. package/dist/Form/Form.Button.d.ts +2 -2
  115. package/dist/Form/Form.Button.js +1 -1
  116. package/dist/Form/Form.Checkbox.d.ts +4 -1
  117. package/dist/Form/Form.Checkbox.js +5 -5
  118. package/dist/Form/Form.ControlledCheckbox.js +1 -1
  119. package/dist/Form/Form.ControlledInput.js +1 -1
  120. package/dist/Form/Form.ControlledMonetaryInput.js +1 -1
  121. package/dist/Form/Form.ControlledRadioButton.js +1 -1
  122. package/dist/Form/Form.DatePicker.d.ts +2 -1
  123. package/dist/Form/Form.DatePicker.js +8 -7
  124. package/dist/Form/Form.Dropdown.js +7 -7
  125. package/dist/Form/Form.FAB.d.ts +2 -2
  126. package/dist/Form/Form.FAB.js +1 -1
  127. package/dist/Form/Form.FilterButton.d.ts +2 -2
  128. package/dist/Form/Form.FilterButton.js +1 -1
  129. package/dist/Form/Form.FractionalQuantityInput.js +4 -4
  130. package/dist/Form/Form.IconButton.d.ts +2 -2
  131. package/dist/Form/Form.IconButton.js +1 -1
  132. package/dist/Form/Form.Input.d.ts +5 -3
  133. package/dist/Form/Form.Input.js +5 -5
  134. package/dist/Form/Form.InputField.d.ts +1 -1
  135. package/dist/Form/Form.InputField.js +3 -3
  136. package/dist/Form/Form.KeyboardForm.d.ts +11 -0
  137. package/dist/Form/Form.KeyboardForm.js +9 -0
  138. package/dist/Form/Form.KeyboardToolbar.d.ts +21 -0
  139. package/dist/Form/Form.KeyboardToolbar.js +70 -0
  140. package/dist/Form/Form.MonetaryInput.js +5 -4
  141. package/dist/Form/Form.PasswordInput.d.ts +1 -1
  142. package/dist/Form/Form.PasswordInput.js +3 -3
  143. package/dist/Form/Form.PinInput.js +5 -5
  144. package/dist/Form/Form.QuantitySelector.js +3 -3
  145. package/dist/Form/Form.RadioButton.js +4 -4
  146. package/dist/Form/Form.SearchBar.js +4 -4
  147. package/dist/Form/Form.Select.d.ts +3 -1
  148. package/dist/Form/Form.Select.js +27 -14
  149. package/dist/Form/Form.Slider.js +3 -3
  150. package/dist/Form/Form.Switch.js +4 -4
  151. package/dist/Form/Form.TextInput.js +3 -3
  152. package/dist/Form/index.d.ts +33 -27
  153. package/dist/Form/index.js +29 -25
  154. package/dist/Navigation/Navigation.AppBar.d.ts +11 -6
  155. package/dist/Navigation/Navigation.AppBar.js +16 -16
  156. package/dist/Navigation/Navigation.BottomNav.d.ts +4 -2
  157. package/dist/Navigation/Navigation.BottomNav.js +34 -21
  158. package/dist/Navigation/Navigation.CollapsingHeader.d.ts +1 -1
  159. package/dist/Navigation/Navigation.CollapsingHeader.js +3 -3
  160. package/dist/Navigation/Navigation.FloatingBar.js +2 -2
  161. package/dist/Navigation/Navigation.Header.js +6 -6
  162. package/dist/Navigation/Navigation.HeaderToolbar.js +5 -5
  163. package/dist/Navigation/Navigation.Menu.js +6 -6
  164. package/dist/Navigation/Navigation.MenuSection.js +2 -2
  165. package/dist/Navigation/Navigation.RowItem.d.ts +2 -2
  166. package/dist/Navigation/Navigation.RowItem.js +4 -4
  167. package/dist/Navigation/Navigation.SearchBar.d.ts +6 -1
  168. package/dist/Navigation/Navigation.SearchBar.js +33 -12
  169. package/dist/Navigation/Navigation.SearchSuggestions.d.ts +14 -0
  170. package/dist/Navigation/Navigation.SearchSuggestions.js +7 -0
  171. package/dist/Navigation/Navigation.SegmentedControl.d.ts +3 -1
  172. package/dist/Navigation/Navigation.SegmentedControl.js +6 -5
  173. package/dist/Navigation/Navigation.Steps.js +5 -5
  174. package/dist/Navigation/Navigation.TabIcon.js +2 -2
  175. package/dist/Navigation/Navigation.TabItem.js +2 -2
  176. package/dist/Navigation/Navigation.Tabs.js +5 -5
  177. package/dist/Navigation/index.d.ts +23 -19
  178. package/dist/Navigation/index.js +17 -15
  179. package/dist/Typography/Typography.Heading.d.ts +1 -1
  180. package/dist/Typography/Typography.Heading.js +2 -2
  181. package/dist/Typography/Typography.SelectableText.d.ts +10 -0
  182. package/dist/Typography/Typography.SelectableText.js +16 -0
  183. package/dist/Typography/Typography.Text.d.ts +2 -2
  184. package/dist/Typography/Typography.Text.js +5 -19
  185. package/dist/Typography/index.d.ts +5 -2
  186. package/dist/Typography/index.js +5 -2
  187. package/dist/branding.d.ts +22 -0
  188. package/dist/branding.js +20 -3
  189. package/dist/icons/AddItemIcon.d.ts +1 -1
  190. package/dist/icons/ArrangeCircle.d.ts +1 -1
  191. package/dist/icons/ArrowDownIcon.d.ts +1 -1
  192. package/dist/icons/ArrowUpIcon.d.ts +1 -1
  193. package/dist/icons/BoxIcon.d.ts +1 -1
  194. package/dist/icons/BoxTimeIcon.d.ts +1 -1
  195. package/dist/icons/CalendarIcon.d.ts +1 -1
  196. package/dist/icons/CardIcon.d.ts +1 -1
  197. package/dist/icons/CashierIcon.d.ts +1 -1
  198. package/dist/icons/DuoIcon.d.ts +1 -1
  199. package/dist/icons/HomeIcon.d.ts +1 -1
  200. package/dist/icons/HomeIconOutlined.d.ts +1 -1
  201. package/dist/icons/LogoIcon.d.ts +1 -1
  202. package/dist/icons/MoneyReceiveIcon.d.ts +1 -1
  203. package/dist/icons/PinIcon.d.ts +1 -1
  204. package/dist/icons/PrinterIcon.d.ts +1 -1
  205. package/dist/icons/ProfileIcon.d.ts +1 -1
  206. package/dist/icons/SettingsIcon.d.ts +1 -1
  207. package/dist/icons/SinpeIcon.d.ts +1 -1
  208. package/dist/icons/ToggleOffIcon.d.ts +1 -1
  209. package/dist/icons/WalletMoneyIcon.d.ts +1 -1
  210. package/dist/index.d.ts +24 -23
  211. package/dist/index.js +26 -24
  212. package/dist/layouts/AuthContainer.d.ts +9 -3
  213. package/dist/layouts/AuthContainer.js +8 -8
  214. package/dist/layouts/Container.js +1 -1
  215. package/dist/layouts/GradientContainer.js +1 -1
  216. package/dist/layouts/ScrollContainer.js +1 -1
  217. package/dist/layouts/TabNavigatorLayout.js +4 -4
  218. package/dist/primitives/AspectRatio.js +1 -1
  219. package/dist/primitives/BaseButton.d.ts +92 -87
  220. package/dist/primitives/BaseButton.js +52 -54
  221. package/dist/primitives/Box.js +1 -1
  222. package/dist/primitives/Pressable.js +1 -1
  223. package/dist/primitives/Row.js +1 -1
  224. package/dist/primitives/Stack.js +1 -1
  225. package/dist/primitives/index.d.ts +6 -6
  226. package/dist/primitives/index.js +6 -6
  227. package/dist/theme/active.d.ts +1 -1
  228. package/dist/theme/active.js +14 -1
  229. package/dist/theme/build.d.ts +33 -0
  230. package/dist/theme/build.js +118 -0
  231. package/dist/theme/color.d.ts +26 -0
  232. package/dist/theme/color.js +109 -0
  233. package/dist/theme/components/index.d.ts +1 -1
  234. package/dist/theme/components/index.js +1 -1
  235. package/dist/theme/contrast.d.ts +29 -0
  236. package/dist/theme/contrast.js +57 -0
  237. package/dist/theme/css-vars.d.ts +3 -1
  238. package/dist/theme/css-vars.js +29 -3
  239. package/dist/theme/dark.d.ts +3 -4
  240. package/dist/theme/dark.js +91 -48
  241. package/dist/theme/default.d.ts +5 -1
  242. package/dist/theme/default.js +89 -41
  243. package/dist/theme/define.d.ts +4 -1
  244. package/dist/theme/define.js +4 -1
  245. package/dist/theme/globals.css +61 -46
  246. package/dist/theme/index.d.ts +14 -10
  247. package/dist/theme/index.js +13 -9
  248. package/dist/theme/theme.d.ts +1 -1
  249. package/dist/theme/theme.js +2 -2
  250. package/dist/theme/types.d.ts +77 -16
  251. package/dist/theme/types.js +13 -3
  252. package/dist/theme/typography.d.ts +19 -4
  253. package/dist/theme/typography.js +45 -28
  254. package/dist/theme/useTheme.d.ts +1 -1
  255. package/dist/theme/useTheme.js +1 -1
  256. package/dist/theme/validate.d.ts +16 -0
  257. package/dist/theme/validate.js +200 -0
  258. package/dist/tokens/index.d.ts +2 -2
  259. package/dist/tokens/index.js +2 -2
  260. package/dist/utils/criteria.d.ts +56 -0
  261. package/dist/utils/criteria.js +99 -0
  262. package/dist/utils/reorder.d.ts +4 -0
  263. package/dist/utils/reorder.js +32 -0
  264. package/dist/views/AppSplashView.d.ts +2 -2
  265. package/dist/views/AppSplashView.js +3 -3
  266. package/dist/views/AuthFormView.d.ts +5 -2
  267. package/dist/views/AuthFormView.js +5 -5
  268. package/dist/views/FormViewV2.d.ts +9 -4
  269. package/dist/views/FormViewV2.js +44 -25
  270. package/dist/views/ListViewV2.d.ts +12 -9
  271. package/dist/views/ListViewV2.js +49 -36
  272. package/dist/views/Wizard/Wizard.context.js +1 -1
  273. package/dist/views/Wizard/Wizard.d.ts +1 -1
  274. package/dist/views/Wizard/Wizard.js +1 -1
  275. package/dist/views/Wizard/index.d.ts +4 -4
  276. package/dist/views/Wizard/index.js +2 -2
  277. package/dist/views/types/IFormView.d.ts +1 -1
  278. package/dist/views/types/IListView.d.ts +1 -1
  279. package/dist/widgets/CircleButton.d.ts +2 -2
  280. package/dist/widgets/CircleButton.js +1 -1
  281. package/dist/widgets/CollectionOptions.d.ts +15 -0
  282. package/dist/widgets/CollectionOptions.js +127 -0
  283. package/dist/widgets/FilterBar.d.ts +21 -0
  284. package/dist/widgets/FilterBar.js +14 -0
  285. package/dist/widgets/FilterBuilder.d.ts +10 -0
  286. package/dist/widgets/FilterBuilder.js +115 -0
  287. package/dist/widgets/GeoPermissionCard.js +3 -3
  288. package/dist/widgets/HomeHeader.js +3 -3
  289. package/dist/widgets/JSONViewer.js +2 -2
  290. package/dist/widgets/MenuCard.d.ts +2 -2
  291. package/dist/widgets/MenuCard.js +1 -1
  292. package/dist/widgets/MenuGrid.d.ts +3 -3
  293. package/dist/widgets/MenuGrid.js +1 -1
  294. package/dist/widgets/MenuSection.d.ts +2 -2
  295. package/dist/widgets/MenuSection.js +1 -1
  296. package/dist/widgets/PromoBanner.js +3 -3
  297. package/dist/widgets/PromoModal.js +3 -3
  298. package/dist/widgets/QueryChoice.d.ts +10 -0
  299. package/dist/widgets/QueryChoice.js +13 -0
  300. package/dist/widgets/QuickActions.js +3 -3
  301. package/dist/widgets/ReorderableList.d.ts +51 -0
  302. package/dist/widgets/ReorderableList.js +138 -0
  303. package/dist/widgets/ScreenHeader.js +2 -2
  304. package/dist/widgets/TimeZoneSelector.d.ts +1 -1
  305. package/dist/widgets/TimeZoneSelector.js +4 -4
  306. package/dist/widgets/TimeZoneSelectorModal.d.ts +1 -1
  307. package/dist/widgets/TimeZoneSelectorModal.js +5 -5
  308. package/dist/widgets/index.d.ts +20 -16
  309. package/dist/widgets/index.js +13 -10
  310. package/package.json +70 -50
  311. package/tailwind.preset.js +19 -0
  312. package/dist/icons/icon_getters.d.ts +0 -6
  313. package/dist/icons/icon_getters.js +0 -23
@@ -1,5 +1,6 @@
1
- import type { AppBarBackground } from "../Navigation/Navigation.AppBar";
2
- import { type SegmentedControlProps } from "../Navigation/Navigation.SegmentedControl";
1
+ import { type KeyboardFormProps } from "../Form/Form.KeyboardForm.js";
2
+ import type { AppBarBackground } from "../Navigation/Navigation.AppBar.js";
3
+ import { type SegmentedControlProps } from "../Navigation/Navigation.SegmentedControl.js";
3
4
  import React, { ReactNode } from "react";
4
5
  import { type ImageSourcePropType } from "react-native";
5
6
  interface FormViewProps<T> {
@@ -12,12 +13,14 @@ interface FormViewProps<T> {
12
13
  errorMessage?: string;
13
14
  readonly?: boolean;
14
15
  onRefresh?: () => Promise<void>;
16
+ onRefreshError?: (error: unknown) => void;
15
17
  onRetry?: () => void;
16
18
  onBack?: () => void;
17
19
  withContainer?: boolean;
18
20
  children: ReactNode;
19
21
  }
20
- declare function FormViewRoot<T>({ name, description, item, isLoading, isEmpty, hasError, errorMessage, readonly, onRefresh, onRetry, onBack, withContainer, children, }: FormViewProps<T>): React.JSX.Element;
22
+ export declare function refreshFormData(onRefresh: (() => Promise<void>) | undefined, onRefreshError: ((error: unknown) => void) | undefined, setShowRefreshing: (value: boolean) => void): Promise<void>;
23
+ declare function FormViewRoot<T>({ name, description, item, isLoading, isEmpty, hasError, errorMessage, readonly, onRefresh, onRefreshError, onRetry, onBack, withContainer, children, }: FormViewProps<T>): React.JSX.Element;
21
24
  interface HeaderProps {
22
25
  /** AppBar display variant. `large` = big title (list/index screens). `center` = modal/detail. */
23
26
  variant?: "default" | "large" | "center";
@@ -53,8 +56,10 @@ declare function HeaderActionsBar({ children }: {
53
56
  * Use as a child of `<FormViewV2.Header>` — it lands in the AppBar subheader slot.
54
57
  */
55
58
  declare function HeaderSegmented<T extends string>(props: SegmentedControlProps<T>): React.JSX.Element;
56
- declare function Content({ withMargin, children, }: {
59
+ declare function Content({ withMargin, keyboardToolbar, keyboardFormProps, children, }: {
57
60
  withMargin?: boolean;
61
+ keyboardToolbar?: boolean;
62
+ keyboardFormProps?: Omit<KeyboardFormProps, "children" | "toolbar">;
58
63
  children: ReactNode;
59
64
  }): React.JSX.Element;
60
65
  /**
@@ -1,22 +1,41 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "nativewind/jsx-runtime";
2
- import { Display } from "../Display";
3
- import { ErrorBoundary, Feedback } from "../Feedback";
4
- import { useBottomInset } from "../layouts/BottomInset";
5
- import Container from "../layouts/Container";
6
- import { AppBar } from "../Navigation/Navigation.AppBar";
7
- import { MenuSection } from "../Navigation/Navigation.MenuSection";
8
- import { SegmentedControl, } from "../Navigation/Navigation.SegmentedControl";
9
- import { useTheme } from "../theme";
10
- import { FormViewProvider, useFormView } from "../views/FormViewV2.context";
2
+ import { Display } from "../Display/index.js";
3
+ import { ErrorBoundary, Feedback } from "../Feedback/index.js";
4
+ import KeyboardForm from "../Form/Form.KeyboardForm.js";
5
+ import { useBottomInset } from "../layouts/BottomInset.js";
6
+ import Container from "../layouts/Container.js";
7
+ import { AppBar } from "../Navigation/Navigation.AppBar.js";
8
+ import { MenuSection } from "../Navigation/Navigation.MenuSection.js";
9
+ import { SegmentedControl, } from "../Navigation/Navigation.SegmentedControl.js";
10
+ import { useTheme } from "../theme/index.js";
11
+ import { FormViewProvider, useFormView } from "./FormViewV2.context.js";
11
12
  import React from "react";
12
13
  import { RefreshControl, View } from "react-native";
13
- import { KeyboardAwareScrollView } from "react-native-keyboard-controller";
14
- function FormViewRoot({ name, description, item, isLoading = false, isEmpty = false, hasError = false, errorMessage, readonly = false, onRefresh, onRetry, onBack, withContainer = true, children, }) {
14
+ const RefreshErrorContext = React.createContext(undefined);
15
+ export async function refreshFormData(onRefresh, onRefreshError, setShowRefreshing) {
16
+ setShowRefreshing(true);
17
+ try {
18
+ await onRefresh?.();
19
+ }
20
+ catch (error) {
21
+ console.error("[FormViewV2] Refresh failed", error);
22
+ try {
23
+ onRefreshError?.(error);
24
+ }
25
+ catch (callbackError) {
26
+ console.error("[FormViewV2] onRefreshError callback failed", callbackError);
27
+ }
28
+ }
29
+ finally {
30
+ setShowRefreshing(false);
31
+ }
32
+ }
33
+ function FormViewRoot({ name, description, item, isLoading = false, isEmpty = false, hasError = false, errorMessage, readonly = false, onRefresh, onRefreshError, onRetry, onBack, withContainer = true, children, }) {
15
34
  const Wrapper = withContainer ? Container : View;
16
35
  const wrapperProps = withContainer
17
36
  ? { edges: ["bottom", "left", "right"] }
18
37
  : { style: { flex: 1 } };
19
- return (_jsx(FormViewProvider, { description: description, errorMessage: errorMessage, hasError: hasError, isEmpty: isEmpty, isLoading: isLoading, item: item, name: name, onBack: onBack, onRefresh: onRefresh, onRetry: onRetry, readonly: readonly, children: _jsx(ErrorBoundary, { children: _jsx(Wrapper, { ...wrapperProps, children: children }) }) }));
38
+ return (_jsx(FormViewProvider, { description: description, errorMessage: errorMessage, hasError: hasError, isEmpty: isEmpty, isLoading: isLoading, item: item, name: name, onBack: onBack, onRefresh: onRefresh, onRetry: onRetry, readonly: readonly, children: _jsx(RefreshErrorContext.Provider, { value: onRefreshError, children: _jsx(ErrorBoundary, { children: _jsx(Wrapper, { ...wrapperProps, children: children }) }) }) }));
20
39
  }
21
40
  function Header({ variant = "default", tone, actions, children, topSpacing, background, }) {
22
41
  const { name, description, onBack } = useFormView();
@@ -36,24 +55,24 @@ function HeaderActionsBar({ children }) {
36
55
  function HeaderSegmented(props) {
37
56
  return _jsx(SegmentedControl, { ...props });
38
57
  }
39
- function Content({ withMargin = false, children, }) {
58
+ function Content({ withMargin = false, keyboardToolbar = false, keyboardFormProps, children, }) {
40
59
  const { name, isLoading, isEmpty, hasError, errorMessage, item, onRefresh, onRetry, onBack, showRefreshing, setShowRefreshing, } = useFormView();
41
60
  const bottomInset = useBottomInset();
42
61
  const theme = useTheme();
62
+ const onRefreshError = React.useContext(RefreshErrorContext);
43
63
  const handleRefresh = React.useCallback(async () => {
44
- setShowRefreshing(true);
45
- if (onRefresh) {
46
- await onRefresh();
47
- }
48
- setShowRefreshing(false);
49
- }, [onRefresh, setShowRefreshing]);
64
+ await refreshFormData(onRefresh, onRefreshError, setShowRefreshing);
65
+ }, [onRefresh, onRefreshError, setShowRefreshing]);
50
66
  const isCenteredContent = isLoading || isEmpty || !item || hasError;
51
- return (_jsx(KeyboardAwareScrollView, { bottomOffset: 20, contentContainerStyle: {
52
- flexGrow: 1,
53
- justifyContent: isCenteredContent ? "center" : "flex-start",
54
- alignItems: isCenteredContent ? "center" : "stretch",
55
- paddingBottom: bottomInset,
56
- }, keyboardShouldPersistTaps: "handled", refreshControl: _jsx(RefreshControl, { colors: [theme.primary], onRefresh: handleRefresh, refreshing: showRefreshing }), style: { flex: 1, backgroundColor: theme.bg.page }, children: isCenteredContent ? (_jsx(_Fragment, { children: isLoading ? (_jsx(Feedback.Loading, { message: `Cargando ${name}...` })) : hasError ? (_jsx(Feedback.Error, { message: errorMessage, onBack: onBack, onRetry: onRetry })) : (_jsx(Feedback.Empty, {})) })) : (_jsx(View, { style: withMargin ? { paddingHorizontal: 16 } : undefined, children: children })) }));
67
+ return (_jsx(KeyboardForm, { ...keyboardFormProps, contentContainerStyle: [
68
+ {
69
+ flexGrow: 1,
70
+ justifyContent: isCenteredContent ? "center" : "flex-start",
71
+ alignItems: isCenteredContent ? "center" : "stretch",
72
+ paddingBottom: bottomInset,
73
+ },
74
+ keyboardFormProps?.contentContainerStyle,
75
+ ], keyboardShouldPersistTaps: keyboardFormProps?.keyboardShouldPersistTaps ?? "handled", refreshControl: keyboardFormProps?.refreshControl ?? (_jsx(RefreshControl, { colors: [theme.primary], onRefresh: handleRefresh, refreshing: showRefreshing })), style: [{ flex: 1, backgroundColor: theme.bg.page }, keyboardFormProps?.style], toolbar: keyboardToolbar, children: isCenteredContent ? (_jsx(_Fragment, { children: isLoading ? (_jsx(Feedback.Loading, { message: `Cargando ${name}...` })) : hasError ? (_jsx(Feedback.Error, { message: errorMessage, onBack: onBack, onRetry: onRetry })) : (_jsx(Feedback.Empty, {})) })) : (_jsx(View, { style: withMargin ? { paddingHorizontal: 16 } : undefined, children: children })) }));
57
76
  }
58
77
  /**
59
78
  * @deprecated Content already handles isEmpty/!item by rendering Feedback.Empty internally.
@@ -1,8 +1,8 @@
1
- import { type SearchHistoryProps } from "../Display/Display.SearchHistory";
2
- import type { AppBarBackground } from "../Navigation/Navigation.AppBar";
3
- import { type SegmentedControlProps } from "../Navigation/Navigation.SegmentedControl";
1
+ import { type SearchHistoryProps } from "../Display/Display.SearchHistory.js";
2
+ import type { AppBarBackground } from "../Navigation/Navigation.AppBar.js";
3
+ import { type SegmentedControlProps } from "../Navigation/Navigation.SegmentedControl.js";
4
4
  import React, { ReactNode } from "react";
5
- import { StyleProp, ViewStyle } from "react-native";
5
+ import { type ScrollViewProps, StyleProp, ViewStyle } from "react-native";
6
6
  interface ListViewProps<T> {
7
7
  name: string;
8
8
  description?: string;
@@ -12,6 +12,7 @@ interface ListViewProps<T> {
12
12
  errorMessage?: string;
13
13
  readonly?: boolean;
14
14
  onRefresh?: () => Promise<void>;
15
+ onRefreshError?: (error: unknown) => void;
15
16
  onRetry?: () => void;
16
17
  onPressItem?: (item: T) => void;
17
18
  onDeleteItem?: (item: T) => void;
@@ -25,7 +26,8 @@ interface ListViewProps<T> {
25
26
  withContainer?: boolean;
26
27
  children: ReactNode;
27
28
  }
28
- declare function ListViewRoot<T>({ name, description, items, isLoading, hasError, errorMessage, readonly, onRefresh, onRetry, onPressItem, onDeleteItem, onSearch, onBack, onLoadMore, loadingMore, backgroundColor, withContainer, children, }: ListViewProps<T>): React.JSX.Element;
29
+ export declare function refreshListData(onRefresh: (() => Promise<void>) | undefined, onRefreshError: ((error: unknown) => void) | undefined, setShowRefreshing: (value: boolean) => void): Promise<void>;
30
+ declare function ListViewRoot<T>({ name, description, items, isLoading, hasError, errorMessage, readonly, onRefresh, onRefreshError, onRetry, onPressItem, onDeleteItem, onSearch, onBack, onLoadMore, loadingMore, backgroundColor, withContainer, children, }: ListViewProps<T>): React.JSX.Element;
29
31
  interface HeaderProps {
30
32
  /** AppBar display variant. `large` = big title (list/index). `center` = modal/detail. */
31
33
  variant?: "default" | "large" | "center";
@@ -79,14 +81,15 @@ declare function FilterChip({ label, active, onPress }: FilterChipProps): React.
79
81
  declare function FilterChips({ children }: {
80
82
  children: ReactNode;
81
83
  }): React.JSX.Element;
82
- declare function Content({ children, withMargin, }: {
84
+ type ListScrollProps = Pick<ScrollViewProps, "keyboardShouldPersistTaps" | "keyboardDismissMode" | "testID">;
85
+ declare function Content({ children, withMargin, keyboardShouldPersistTaps, keyboardDismissMode, testID, }: {
83
86
  children?: (item: any) => ReactNode;
84
87
  withMargin?: boolean;
85
- }): React.JSX.Element;
86
- declare function ContentList({ children, contentWithMargin, }: {
88
+ } & ListScrollProps): React.JSX.Element;
89
+ declare function ContentList({ children, contentWithMargin, keyboardShouldPersistTaps, keyboardDismissMode, testID, }: {
87
90
  children?: (item: any) => ReactNode;
88
91
  contentWithMargin: boolean;
89
- }): React.JSX.Element;
92
+ } & ListScrollProps): React.JSX.Element;
90
93
  declare function Footer({ children }: {
91
94
  children: ReactNode;
92
95
  }): React.JSX.Element | null;
@@ -1,25 +1,44 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "nativewind/jsx-runtime";
2
- import { Display } from "../Display";
3
- import SearchHistory from "../Display/Display.SearchHistory";
4
- import { ErrorBoundary, Feedback } from "../Feedback";
5
- import { useBottomInset } from "../layouts/BottomInset";
6
- import Container from "../layouts/Container";
7
- import { Navigation } from "../Navigation";
8
- import { SegmentedControl, } from "../Navigation/Navigation.SegmentedControl";
9
- import { useTheme } from "../theme";
10
- import { cn, tv } from "../theme/tw";
11
- import { Typography } from "../Typography";
12
- import { ListViewProvider, useListView } from "../views/ListViewV2.context";
13
- import { toRowItems } from "../views/types/IListView";
14
- import { useCallback, useEffect, useMemo, useState } from "react";
2
+ import { Display } from "../Display/index.js";
3
+ import SearchHistory from "../Display/Display.SearchHistory.js";
4
+ import { ErrorBoundary, Feedback } from "../Feedback/index.js";
5
+ import { useBottomInset } from "../layouts/BottomInset.js";
6
+ import Container from "../layouts/Container.js";
7
+ import { Navigation } from "../Navigation/index.js";
8
+ import { SegmentedControl, } from "../Navigation/Navigation.SegmentedControl.js";
9
+ import { useTheme } from "../theme/index.js";
10
+ import { cn, tv } from "../theme/tw.js";
11
+ import { Typography } from "../Typography/index.js";
12
+ import { ListViewProvider, useListView } from "./ListViewV2.context.js";
13
+ import { toRowItems } from "./types/IListView.js";
14
+ import { createContext, useCallback, useContext, useEffect, useMemo, useState, } from "react";
15
15
  import { FlatList, RefreshControl, ScrollView, TouchableOpacity, View, } from "react-native";
16
- function ListViewRoot({ name, description, items, isLoading = false, hasError = false, errorMessage, readonly = false, onRefresh, onRetry, onPressItem, onDeleteItem, onSearch, onBack, onLoadMore, loadingMore = false, backgroundColor, withContainer = true, children, }) {
16
+ const RefreshErrorContext = createContext(undefined);
17
+ export async function refreshListData(onRefresh, onRefreshError, setShowRefreshing) {
18
+ setShowRefreshing(true);
19
+ try {
20
+ await onRefresh?.();
21
+ }
22
+ catch (error) {
23
+ console.error("[ListViewV2] Refresh failed", error);
24
+ try {
25
+ onRefreshError?.(error);
26
+ }
27
+ catch (callbackError) {
28
+ console.error("[ListViewV2] onRefreshError callback failed", callbackError);
29
+ }
30
+ }
31
+ finally {
32
+ setShowRefreshing(false);
33
+ }
34
+ }
35
+ function ListViewRoot({ name, description, items, isLoading = false, hasError = false, errorMessage, readonly = false, onRefresh, onRefreshError, onRetry, onPressItem, onDeleteItem, onSearch, onBack, onLoadMore, loadingMore = false, backgroundColor, withContainer = true, children, }) {
17
36
  const Wrapper = withContainer ? Container : View;
18
37
  const wrapperProps = withContainer
19
38
  ? { edges: ["bottom", "left", "right"] }
20
39
  : { className: "flex-1 bg-bg-page" };
21
40
  // Propagate contentWithMargin to ContentList via context
22
- return (_jsx(ListViewProvider, { description: description, errorMessage: errorMessage, hasError: hasError, isLoading: isLoading, items: items, loadingMore: loadingMore, name: name, onBack: onBack, onDeleteItem: onDeleteItem, onLoadMore: onLoadMore, onPressItem: onPressItem, onRefresh: onRefresh, onRetry: onRetry, onSearch: onSearch, readonly: readonly, children: _jsx(ErrorBoundary, { children: _jsx(Wrapper, { ...wrapperProps, children: children }) }) }));
41
+ return (_jsx(ListViewProvider, { description: description, errorMessage: errorMessage, hasError: hasError, isLoading: isLoading, items: items, loadingMore: loadingMore, name: name, onBack: onBack, onDeleteItem: onDeleteItem, onLoadMore: onLoadMore, onPressItem: onPressItem, onRefresh: onRefresh, onRetry: onRetry, onSearch: onSearch, readonly: readonly, children: _jsx(RefreshErrorContext.Provider, { value: onRefreshError, children: _jsx(ErrorBoundary, { children: _jsx(Wrapper, { ...wrapperProps, children: children }) }) }) }));
23
42
  }
24
43
  function Header({ variant = "large", tone, actions, children, background, topSpacing, }) {
25
44
  const { name, description, onBack } = useListView();
@@ -69,12 +88,12 @@ function HeaderSearchHistory(props) {
69
88
  function HeaderFilters({ children }) {
70
89
  return _jsx(View, { className: "px-4 py-2 items-center", children: children });
71
90
  }
72
- // Modern filter pills (2026): rounded-full, active = accent (green), inactive = muted track.
91
+ // Active filter uses the action color. The capsule is a pill; the rest of the chrome is not.
73
92
  const filterChip = tv({
74
93
  base: "py-1.5 px-3.5 items-center justify-center rounded-full",
75
94
  variants: {
76
95
  active: {
77
- true: "bg-accent",
96
+ true: "bg-primary",
78
97
  false: "bg-bg-muted",
79
98
  },
80
99
  },
@@ -83,7 +102,7 @@ const filterChip = tv({
83
102
  const filterChipText = tv({
84
103
  variants: {
85
104
  active: {
86
- true: "text-text-inverse font-semibold",
105
+ true: "text-text-on-primary font-semibold",
87
106
  false: "text-text-secondary",
88
107
  },
89
108
  },
@@ -95,17 +114,14 @@ function FilterChip({ label, active = false, onPress }) {
95
114
  function FilterChips({ children }) {
96
115
  return (_jsx(ScrollView, { contentContainerStyle: { paddingHorizontal: 16, gap: 8 }, horizontal: true, showsHorizontalScrollIndicator: false, style: { flexGrow: 0 }, children: children }));
97
116
  }
98
- function Content({ children, withMargin = true, }) {
117
+ function Content({ children, withMargin = true, keyboardShouldPersistTaps = "handled", keyboardDismissMode = "none", testID, }) {
99
118
  const { name, items, isLoading, hasError, errorMessage, onRefresh, onRetry, onBack, showRefreshing, setShowRefreshing, } = useListView();
100
119
  const bottomInset = useBottomInset();
101
120
  const theme = useTheme();
121
+ const onRefreshError = useContext(RefreshErrorContext);
102
122
  const handleRefresh = useCallback(async () => {
103
- setShowRefreshing(true);
104
- if (onRefresh) {
105
- await onRefresh();
106
- }
107
- setShowRefreshing(false);
108
- }, [onRefresh, setShowRefreshing]);
123
+ await refreshListData(onRefresh, onRefreshError, setShowRefreshing);
124
+ }, [onRefresh, onRefreshError, setShowRefreshing]);
109
125
  if (isLoading) {
110
126
  return _jsx(Feedback.Loading, { message: `Cargando ${name}...` });
111
127
  }
@@ -115,7 +131,7 @@ function Content({ children, withMargin = true, }) {
115
131
  justifyContent: "center",
116
132
  alignItems: "center",
117
133
  paddingBottom: bottomInset,
118
- }, refreshControl: _jsx(RefreshControl, { colors: [theme.primary], onRefresh: handleRefresh, refreshing: showRefreshing }), style: { backgroundColor: theme.bg.page }, children: _jsx(Feedback.Error, { message: errorMessage, onBack: onBack, onRetry: onRetry }) }));
134
+ }, keyboardDismissMode: keyboardDismissMode, keyboardShouldPersistTaps: keyboardShouldPersistTaps, refreshControl: _jsx(RefreshControl, { colors: [theme.primary], onRefresh: handleRefresh, refreshing: showRefreshing }), style: { backgroundColor: theme.bg.page }, testID: testID, children: _jsx(Feedback.Error, { message: errorMessage, onBack: onBack, onRetry: onRetry }) }));
119
135
  }
120
136
  if (items.length === 0) {
121
137
  return (_jsx(ScrollView, { contentContainerStyle: {
@@ -123,22 +139,19 @@ function Content({ children, withMargin = true, }) {
123
139
  justifyContent: "center",
124
140
  alignItems: "center",
125
141
  paddingBottom: bottomInset,
126
- }, refreshControl: _jsx(RefreshControl, { colors: [theme.primary], onRefresh: handleRefresh, refreshing: showRefreshing }), style: { backgroundColor: theme.bg.page }, children: _jsx(Feedback.Empty, {}) }));
142
+ }, keyboardDismissMode: keyboardDismissMode, keyboardShouldPersistTaps: keyboardShouldPersistTaps, refreshControl: _jsx(RefreshControl, { colors: [theme.primary], onRefresh: handleRefresh, refreshing: showRefreshing }), style: { backgroundColor: theme.bg.page }, testID: testID, children: _jsx(Feedback.Empty, {}) }));
127
143
  }
128
- return (_jsxs(View, { style: { flex: 1, backgroundColor: theme.bg.page }, children: [_jsx(Display.CountRecords, { count: items.length || 0, name: name }), _jsx(ContentList, { contentWithMargin: withMargin, children: children })] }));
144
+ return (_jsxs(View, { style: { flex: 1, backgroundColor: theme.bg.page }, children: [_jsx(Display.CountRecords, { count: items.length || 0, name: name }), _jsx(ContentList, { contentWithMargin: withMargin, keyboardDismissMode: keyboardDismissMode, keyboardShouldPersistTaps: keyboardShouldPersistTaps, testID: testID, children: children })] }));
129
145
  }
130
- function ContentList({ children, contentWithMargin, }) {
146
+ function ContentList({ children, contentWithMargin, keyboardShouldPersistTaps, keyboardDismissMode, testID, }) {
131
147
  const { items, onRefresh, showRefreshing, setShowRefreshing, onPressItem, onDeleteItem, readonly, onLoadMore, loadingMore, } = useListView();
132
148
  const bottomInset = useBottomInset();
133
149
  const theme = useTheme();
134
150
  const rowItems = useMemo(() => toRowItems(items), [items]);
151
+ const onRefreshError = useContext(RefreshErrorContext);
135
152
  const handleRefresh = useCallback(async () => {
136
- setShowRefreshing(true);
137
- if (onRefresh) {
138
- await onRefresh();
139
- }
140
- setShowRefreshing(false);
141
- }, [onRefresh, setShowRefreshing]);
153
+ await refreshListData(onRefresh, onRefreshError, setShowRefreshing);
154
+ }, [onRefresh, onRefreshError, setShowRefreshing]);
142
155
  const renderItem = useCallback(({ item }) => {
143
156
  if (children) {
144
157
  return _jsx(_Fragment, { children: children(item) });
@@ -153,7 +166,7 @@ function ContentList({ children, contentWithMargin, }) {
153
166
  marginTop: 2,
154
167
  paddingHorizontal: contentWithMargin ? 4 : 0,
155
168
  backgroundColor: theme.bg.page,
156
- }, children: _jsx(FlatList, { contentContainerStyle: bottomInset ? { paddingBottom: bottomInset } : undefined, data: rowItems, keyExtractor: (item) => String(item.index), ListFooterComponent: loadingMore ? (_jsx(View, { className: "py-4", children: _jsx(Feedback.Spinner, { size: "small" }) })) : null, onEndReached: onLoadMore ? () => onLoadMore() : undefined, onEndReachedThreshold: 0.5, refreshControl: _jsx(RefreshControl, { colors: [theme.primary], onRefresh: handleRefresh, refreshing: showRefreshing }), renderItem: renderItem, scrollEnabled: true, showsVerticalScrollIndicator: false }) }));
169
+ }, children: _jsx(FlatList, { contentContainerStyle: bottomInset ? { paddingBottom: bottomInset } : undefined, data: rowItems, keyboardDismissMode: keyboardDismissMode, keyboardShouldPersistTaps: keyboardShouldPersistTaps, keyExtractor: (item) => String(item.index), ListFooterComponent: loadingMore ? (_jsx(View, { className: "py-4", children: _jsx(Feedback.Spinner, { size: "small" }) })) : undefined, onEndReached: onLoadMore ? () => onLoadMore() : undefined, onEndReachedThreshold: 0.5, refreshControl: _jsx(RefreshControl, { colors: [theme.primary], onRefresh: handleRefresh, refreshing: showRefreshing }), renderItem: renderItem, scrollEnabled: true, showsVerticalScrollIndicator: false, testID: testID }) }));
157
170
  }
158
171
  function Footer({ children }) {
159
172
  const { items } = useListView();
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
2
- import { ErrorBoundary } from "../../Feedback";
2
+ import { ErrorBoundary } from "../../Feedback/index.js";
3
3
  import { createContext, useCallback, useContext, useMemo, useState } from "react";
4
4
  import { ActivityIndicator, Text, View } from "react-native";
5
5
  const WizardContext = createContext(null);
@@ -1,4 +1,4 @@
1
- import type { WizardContextValue, WizardProviderProps, WizardStepId } from "../../views/Wizard/Wizard.context";
1
+ import type { WizardContextValue, WizardProviderProps, WizardStepId } from "./Wizard.context.js";
2
2
  import type { FC, ReactNode } from "react";
3
3
  export interface WizardStepGuard {
4
4
  canEnter?: () => boolean | Promise<boolean>;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment } from "nativewind/jsx-runtime";
2
- import { useWizard, WizardProvider } from "../../views/Wizard/Wizard.context";
2
+ import { useWizard, WizardProvider } from "./Wizard.context.js";
3
3
  import { useEffect } from "react";
4
4
  import { TouchableOpacity } from "react-native";
5
5
  const WizardRoot = (props) => {
@@ -1,4 +1,4 @@
1
- export type { WizardBackProps, WizardGoProps, WizardGuardProps, WizardStepGuard, WizardStepLifecycle, WizardStepProps, } from "../../views/Wizard/Wizard";
2
- export { Wizard } from "../../views/Wizard/Wizard";
3
- export type { WizardContextValue, WizardProviderProps, WizardStepId, } from "../../views/Wizard/Wizard.context";
4
- export { useWizard } from "../../views/Wizard/Wizard.context";
1
+ export type { WizardBackProps, WizardGoProps, WizardGuardProps, WizardStepGuard, WizardStepLifecycle, WizardStepProps, } from "./Wizard.js";
2
+ export { Wizard } from "./Wizard.js";
3
+ export type { WizardContextValue, WizardProviderProps, WizardStepId, } from "./Wizard.context.js";
4
+ export { useWizard } from "./Wizard.context.js";
@@ -1,2 +1,2 @@
1
- export { Wizard } from "../../views/Wizard/Wizard";
2
- export { useWizard } from "../../views/Wizard/Wizard.context";
1
+ export { Wizard } from "./Wizard.js";
2
+ export { useWizard } from "./Wizard.context.js";
@@ -1,4 +1,4 @@
1
- import { UIItem } from "../../views/types/UIItem";
1
+ import { UIItem } from "./UIItem.js";
2
2
  import { ReactNode } from "react";
3
3
  export interface IFormView<T> extends UIItem {
4
4
  name: string;
@@ -1,4 +1,4 @@
1
- import { UICollectionItem, UIItem } from "../../views/types/UIItem";
1
+ import { UICollectionItem, UIItem } from "./UIItem.js";
2
2
  import { ReactNode } from "react";
3
3
  export type IRowItem<T> = T & UIItem & {
4
4
  id: string | number;
@@ -1,3 +1,3 @@
1
1
  /** @deprecated Import from `@sincpro/mobile-ui/Display` → `Display.CircleButton` instead. */
2
- export type { CircleButtonProps } from "../Display/Display.CircleButton";
3
- export { CircleButton } from "../Display/Display.CircleButton";
2
+ export type { CircleButtonProps } from "../Display/Display.CircleButton.js";
3
+ export { CircleButton } from "../Display/Display.CircleButton.js";
@@ -1 +1 @@
1
- export { CircleButton } from "../Display/Display.CircleButton";
1
+ export { CircleButton } from "../Display/Display.CircleButton.js";
@@ -0,0 +1,15 @@
1
+ import { type CollectionField, type CollectionQuery, type CriteriaField, type SavedCollectionQuery } from "../utils/criteria.js";
2
+ export interface CollectionOptionsProps {
3
+ visible: boolean;
4
+ value: CollectionQuery;
5
+ fields: readonly CriteriaField[];
6
+ sortFields?: readonly CollectionField[];
7
+ groupFields?: readonly CollectionField[];
8
+ savedQueries?: readonly SavedCollectionQuery[];
9
+ onApply: (query: CollectionQuery) => void;
10
+ onClose: () => void;
11
+ onSave?: (label: string, query: CollectionQuery) => void | Promise<void>;
12
+ title?: string;
13
+ testID?: string;
14
+ }
15
+ export default function CollectionOptions(props: CollectionOptionsProps): import("react").JSX.Element | null;
@@ -0,0 +1,127 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "nativewind/jsx-runtime";
2
+ import Button from "../Actions/Actions.Button.js";
3
+ import IconButton from "../Actions/Actions.IconButton.js";
4
+ import Input from "../Form/Form.Input.js";
5
+ import KeyboardForm from "../Form/Form.KeyboardForm.js";
6
+ import Pressable from "../primitives/Pressable.js";
7
+ import { themeToVars, useTheme } from "../theme/index.js";
8
+ import { Typography } from "../Typography/index.js";
9
+ import { describeCriteria, moveCollectionEntry, validateCriteria, } from "../utils/criteria.js";
10
+ import FilterBuilder from "./FilterBuilder.js";
11
+ import QueryChoice from "./QueryChoice.js";
12
+ import { vars } from "nativewind";
13
+ import { useState } from "react";
14
+ import { Keyboard, Modal, View } from "react-native";
15
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
16
+ export default function CollectionOptions(props) {
17
+ return props.visible ? _jsx(OptionsEditor, { ...props }) : null;
18
+ }
19
+ const sections = [
20
+ { id: "filter", label: "Filtros" },
21
+ { id: "sort", label: "Ordenar" },
22
+ { id: "group", label: "Agrupar" },
23
+ { id: "saved", label: "Guardados" },
24
+ ];
25
+ function OptionsEditor({ value, fields, sortFields = [], groupFields = [], savedQueries = [], onApply, onClose, onSave, title = "Configurar colección", testID, }) {
26
+ const theme = useTheme();
27
+ const insets = useSafeAreaInsets();
28
+ const [draft, setDraft] = useState(value);
29
+ const [section, setSection] = useState("filter");
30
+ const [editing, setEditing] = useState(false);
31
+ const [label, setLabel] = useState("");
32
+ const [error, setError] = useState();
33
+ const [status, setStatus] = useState();
34
+ const [saving, setSaving] = useState(false);
35
+ const problem = () => validateCriteria(draft.filter, fields) ??
36
+ (draft.sort.some((sort) => !sortFields.some((field) => field.id === sort.field))
37
+ ? "El orden contiene un campo no disponible."
38
+ : undefined) ??
39
+ (draft.groupBy.some((id) => !groupFields.some((field) => field.id === id))
40
+ ? "El agrupado contiene un campo no disponible."
41
+ : undefined);
42
+ const close = () => {
43
+ if (!saving) {
44
+ Keyboard.dismiss();
45
+ onClose();
46
+ }
47
+ };
48
+ const ordered = section === "sort" ? draft.sort.map((entry) => entry.field) : draft.groupBy;
49
+ const available = section === "sort" ? sortFields : groupFields;
50
+ const updateOrder = (next) => setDraft((current) => section === "sort"
51
+ ? {
52
+ ...current,
53
+ sort: next.map((field) => current.sort.find((entry) => entry.field === field) ?? {
54
+ field,
55
+ direction: "asc",
56
+ }),
57
+ }
58
+ : { ...current, groupBy: next });
59
+ return (_jsx(Modal, { animationType: "slide", onRequestClose: close, presentationStyle: "fullScreen", visible: true, children: _jsxs(View, { accessibilityViewIsModal: true, onAccessibilityEscape: close, style: [
60
+ vars(themeToVars(theme)),
61
+ {
62
+ flex: 1,
63
+ backgroundColor: theme.bg.page,
64
+ paddingTop: insets.top,
65
+ paddingBottom: insets.bottom,
66
+ },
67
+ ], testID: testID, children: [_jsxs(View, { className: "flex-row items-center justify-between gap-3 px-4", children: [_jsx(Typography.Text, { accessibilityRole: "header", semibold: true, style: { flex: 1, minWidth: 0 }, variant: "bodyReadable", children: title }), _jsx(IconButton, { accessibilityLabel: "Cancelar configuraci\u00F3n", accessibleSizing: true, disabled: saving, icon: "close", onPress: close })] }), _jsx(View, { accessibilityRole: "tablist", className: "flex-row flex-wrap px-4 gap-2", children: sections.map((item) => (_jsx(Pressable, { accessibilityLabel: item.label, accessibilityRole: "tab", accessibilityState: {
68
+ selected: item.id === section,
69
+ disabled: editing || saving,
70
+ }, disabled: editing || saving, onPress: () => {
71
+ Keyboard.dismiss();
72
+ setSection(item.id);
73
+ setError(undefined);
74
+ setStatus(undefined);
75
+ }, style: { minHeight: 48, justifyContent: "center", paddingHorizontal: 8 }, children: _jsx(Typography.Text, { className: section === item.id ? "text-text-accent" : "text-text-secondary", semibold: section === item.id, variant: "bodyLarge", children: item.label }) }, item.id))) }), _jsxs(KeyboardForm, { contentContainerStyle: { padding: 16, gap: 16 }, children: [!editing ? (_jsx(Typography.Text, { className: "text-text-secondary", variant: "bodyLarge", children: describeCriteria(draft.filter, fields) })) : null, section === "filter" ? (_jsx(FilterBuilder, { fields: fields, onChange: (filter) => {
76
+ setError(undefined);
77
+ setDraft({ ...draft, filter });
78
+ }, onEditingChange: setEditing, value: draft.filter })) : section === "saved" ? (_jsxs(_Fragment, { children: [_jsx(Typography.Text, { variant: "bodyReadable", children: "Una configuraci\u00F3n incluye b\u00FAsqueda, condiciones, orden y niveles de agrupaci\u00F3n. Cargarla todav\u00EDa no modifica la colecci\u00F3n." }), !savedQueries.length ? (_jsx(Typography.Text, { children: "No hay configuraciones guardadas." })) : (savedQueries.map((saved) => (_jsx(Button, { accessibleSizing: true, disabled: saving, onPress: () => {
79
+ setDraft(saved.query);
80
+ setError(undefined);
81
+ setStatus(`Configuración ${saved.label} cargada. Pulsa Aplicar configuración.`);
82
+ }, title: `Cargar ${saved.label}`, variant: "secondary" }, saved.id)))), onSave ? (_jsxs(_Fragment, { children: [_jsx(Input, { accessibleSizing: true, editable: !saving, label: "Nombre de la configuraci\u00F3n", onChangeText: setLabel, testID: "collection-query-name", value: label }), _jsx(Button, { accessibleSizing: true, loading: saving, onPress: () => {
83
+ const invalid = problem();
84
+ if (invalid || !label.trim()) {
85
+ setError(invalid ?? "Escribe un nombre para guardar.");
86
+ return;
87
+ }
88
+ setError(undefined);
89
+ setStatus(undefined);
90
+ setSaving(true);
91
+ Promise.resolve()
92
+ .then(() => onSave(label.trim(), draft))
93
+ .then(() => {
94
+ setStatus("Configuración guardada. Pulsa Aplicar configuración para usarla.");
95
+ }, (cause) => {
96
+ console.error("[CollectionOptions] Save failed", cause);
97
+ setError("No se pudo guardar. Conservamos la configuración para reintentar.");
98
+ })
99
+ .finally(() => setSaving(false));
100
+ }, title: "Guardar configuraci\u00F3n" })] })) : null] })) : (_jsxs(_Fragment, { children: [_jsx(Typography.Text, { variant: "bodyReadable", children: section === "sort"
101
+ ? "El primer campo tiene prioridad; los siguientes resuelven empates."
102
+ : "Los grupos se anidan en este orden. La app aplica los niveles al conjunto completo." }), !ordered.length ? (_jsx(Typography.Text, { children: section === "sort" ? "Sin orden configurado." : "Sin agrupación." })) : null, ordered.map((id, index) => {
103
+ const field = available.find((item) => item.id === id);
104
+ const sort = draft.sort.find((entry) => entry.field === id);
105
+ return (_jsxs(View, { className: "gap-2 border-b border-border-light pb-3", children: [_jsxs(Typography.Text, { semibold: true, variant: "bodyReadable", children: [index + 1, ". ", field?.label ?? `${id} (no disponible)`] }), section === "sort" ? (_jsx(Button, { accessibleSizing: true, onPress: () => setDraft({
106
+ ...draft,
107
+ sort: draft.sort.map((entry) => entry.field === id
108
+ ? {
109
+ ...entry,
110
+ direction: entry.direction === "asc" ? "desc" : "asc",
111
+ }
112
+ : entry),
113
+ }), title: `${field?.label ?? id}: ${sort?.direction === "asc" ? (field?.ascLabel ?? "Ascendente") : (field?.descLabel ?? "Descendente")}`, variant: "secondary" })) : null, _jsxs(View, { className: "flex-row flex-wrap gap-2", children: [_jsx(Button, { accessibilityLabel: `Subir ${field?.label ?? id}`, accessibleSizing: true, disabled: index === 0, onPress: () => updateOrder(moveCollectionEntry(ordered, index, -1)), title: "Subir", variant: "link" }), _jsx(Button, { accessibilityLabel: `Bajar ${field?.label ?? id}`, accessibleSizing: true, disabled: index === ordered.length - 1, onPress: () => updateOrder(moveCollectionEntry(ordered, index, 1)), title: "Bajar", variant: "link" }), _jsx(Button, { accessibilityLabel: `Quitar ${field?.label ?? id}`, accessibleSizing: true, onPress: () => updateOrder(ordered.filter((key) => key !== id)), title: "Quitar", variant: "link" })] })] }, id));
114
+ }), available.some((field) => !ordered.includes(field.id)) ? (_jsx(QueryChoice, { label: section === "sort"
115
+ ? "Añadir criterio de orden"
116
+ : "Añadir nivel de agrupación", onChange: (id) => updateOrder([...ordered, id]), options: available
117
+ .filter((field) => !ordered.includes(field.id))
118
+ .map((field) => ({ label: field.label, value: field.id })), value: undefined })) : null] })), status ? (_jsx(Typography.Text, { accessibilityLiveRegion: "polite", children: status })) : null, error ? (_jsx(Typography.Text, { accessibilityLiveRegion: "polite", className: "text-danger", children: error })) : null] }), _jsxs(View, { className: "px-4 py-3 border-t border-border-light gap-2", children: [editing ? (_jsx(Typography.Text, { children: "Guarda o cancela la condici\u00F3n antes de aplicar." })) : null, _jsx(Button, { accessibleSizing: true, disabled: editing || saving, onPress: () => {
119
+ const invalid = problem();
120
+ if (invalid) {
121
+ setError(invalid);
122
+ return;
123
+ }
124
+ Keyboard.dismiss();
125
+ onApply(draft);
126
+ }, title: "Aplicar configuraci\u00F3n" })] })] }) }));
127
+ }
@@ -0,0 +1,21 @@
1
+ import { type SearchBarProps } from "../Navigation/Navigation.SearchBar.js";
2
+ export interface FilterBarOption {
3
+ id: string;
4
+ label: string;
5
+ selected: boolean;
6
+ disabled?: boolean;
7
+ }
8
+ export interface FilterBarProps {
9
+ filters: readonly FilterBarOption[];
10
+ onFilterPress: (id: string) => void;
11
+ search?: Omit<SearchBarProps, "accessibleSizing">;
12
+ onOpenFilters?: () => void;
13
+ filtersLabel?: string;
14
+ onClearFilters?: () => void;
15
+ clearLabel?: string;
16
+ resultsLabel?: string;
17
+ layout?: "auto" | "scroll" | "wrap";
18
+ className?: string;
19
+ testID?: string;
20
+ }
21
+ export declare function FilterBar({ filters, onFilterPress, search, onOpenFilters, filtersLabel, onClearFilters, clearLabel, resultsLabel, layout, className, testID, }: FilterBarProps): import("react").JSX.Element;
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
2
+ import { FilterButton, FilterButtonGroup, } from "../Actions/Actions.FilterButton.js";
3
+ import IconButton from "../Actions/Actions.IconButton.js";
4
+ import SearchBar from "../Navigation/Navigation.SearchBar.js";
5
+ import Pressable from "../primitives/Pressable.js";
6
+ import { cn } from "../theme/tw.js";
7
+ import { Typography } from "../Typography/index.js";
8
+ import { useWindowDimensions, View } from "react-native";
9
+ export function FilterBar({ filters, onFilterPress, search, onOpenFilters, filtersLabel = "Más filtros", onClearFilters, clearLabel = "Limpiar filtros", resultsLabel, layout = "auto", className, testID, }) {
10
+ const { fontScale } = useWindowDimensions();
11
+ const selectedCount = filters.filter((filter) => filter.selected).length;
12
+ const filterLayout = layout === "auto" ? (fontScale > 1.3 ? "wrap" : "scroll") : layout;
13
+ return (_jsxs(View, { className: cn("gap-2", className), testID: testID, children: [search || onOpenFilters ? (_jsxs(View, { className: "flex-row items-center gap-2", children: [search ? (_jsx(View, { className: "flex-1 min-w-0", children: _jsx(SearchBar, { ...search, accessibleSizing: true }) })) : null, onOpenFilters ? (_jsx(IconButton, { accessibilityLabel: filtersLabel, accessibleSizing: true, icon: "sliders", onPress: onOpenFilters })) : null] })) : null, _jsx(FilterButtonGroup, { className: "p-0", layout: filterLayout, testID: testID ? `${testID}-options` : undefined, children: filters.map((filter) => (_jsx(FilterButton, { active: filter.selected, disabled: filter.disabled, onPress: () => onFilterPress(filter.id), testID: testID ? `${testID}-${filter.id}` : undefined, title: filter.label, variant: "mobile" }, filter.id))) }), resultsLabel || (selectedCount > 0 && onClearFilters) ? (_jsxs(View, { className: "flex-row flex-wrap items-center justify-between gap-x-3", children: [resultsLabel ? (_jsx(Typography.Text, { accessibilityLiveRegion: "polite", className: "text-text-secondary", variant: "bodyLarge", children: resultsLabel })) : null, selectedCount > 0 && onClearFilters ? (_jsx(Pressable, { accessibilityLabel: clearLabel, accessibilityRole: "button", onPress: onClearFilters, style: { minHeight: 48, minWidth: 48, justifyContent: "center" }, children: _jsx(Typography.Text, { className: "text-text-accent", variant: "bodyLarge", children: clearLabel }) })) : null] })) : null] }));
14
+ }
@@ -0,0 +1,10 @@
1
+ import { type CriteriaField, type CriteriaGroup } from "../utils/criteria.js";
2
+ export interface FilterBuilderProps {
3
+ fields: readonly CriteriaField[];
4
+ value: CriteriaGroup;
5
+ onChange: (value: CriteriaGroup) => void;
6
+ onEditingChange?: (editing: boolean) => void;
7
+ className?: string;
8
+ testID?: string;
9
+ }
10
+ export default function FilterBuilder({ fields, value, onChange, onEditingChange, className, testID, }: FilterBuilderProps): import("react").JSX.Element;