@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
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @sincpro/mobile-ui
2
2
 
3
- **Sincpro Mobile Design System** — the UI contract between design and engineering for React Native / Expo SDK 56 applications.
3
+ **Sincpro Mobile Design System** — the UI contract between design and engineering for React Native / Expo SDK 58 applications.
4
4
 
5
5
  This package is maintained by Sincpro as part of the mobile framework ecosystem. Anyone can read the source and use the components. What Sincpro provides is the commitment behind it: stable APIs, predictable behavior, long-term support, and a team that ensures this keeps working as platforms evolve. Build on it knowing it will still be there.
6
6
 
@@ -20,17 +20,14 @@ Wire the Tailwind preset, then import by category:
20
20
  // tailwind.config.js
21
21
  module.exports = {
22
22
  presets: [require("@sincpro/mobile-ui/tailwind.preset")],
23
- content: [
24
- "./App.tsx",
25
- "./src/**/*.{ts,tsx}",
26
- "./node_modules/@sincpro/mobile-ui/**/*.js",
27
- ],
23
+ content: ["./App.tsx", "./src/**/*.{ts,tsx}", "./node_modules/@sincpro/mobile-ui/**/*.js"],
28
24
  };
29
25
  ```
30
26
 
31
27
  ```tsx
28
+ import { Actions } from "@sincpro/mobile-ui/Actions";
32
29
  import { Display } from "@sincpro/mobile-ui/Display";
33
- import { Form } from "@sincpro/mobile-ui/Form";
30
+ import { Form } from "@sincpro/mobile-ui/Form";
34
31
  import { useToast, ToastProvider } from "@sincpro/mobile-ui/Feedback";
35
32
 
36
33
  export default function InvoiceScreen() {
@@ -38,10 +35,12 @@ export default function InvoiceScreen() {
38
35
  return (
39
36
  <Display.Card>
40
37
  <Display.KeyValue label="Invoice #" value="INV-0042" copyable />
41
- <Display.Monetary amount={1500.00} variant="dataLarge" />
42
- <Form.Button onPress={() => toast.success("Invoice sent")}>
43
- Send Invoice
44
- </Form.Button>
38
+ <Display.Monetary value={1500.0} variant="dataLarge" />
39
+ <Actions.Button
40
+ accessibleSizing
41
+ onPress={() => toast.success("Invoice sent")}
42
+ title="Send Invoice"
43
+ />
45
44
  </Display.Card>
46
45
  );
47
46
  }
@@ -80,6 +79,338 @@ Without a design system, every developer makes local decisions: which shade of g
80
79
 
81
80
  ## Philosophy
82
81
 
82
+ **Composable behavior, customizable presentation.** Sincpro defaults are a starting
83
+ point, not a mandatory visual style. Preserve existing appearances while exposing public
84
+ APIs for fonts, sizes, shapes, content and composition. See the
85
+ [permanent design-system manifesto](docs/MANIFESTO.md) for the goal, acceptance criteria
86
+ and current limitations; full customizability is an objective, not a completed audit.
87
+
88
+ The [UX/UI evolution plan](docs/UX-UI-PLAN.md) tracks the rollout. The first native pilot
89
+ is in Storybook under `Patterns/Records/Detail`: list, detail, copy, edit, cancel and
90
+ recoverable error. It uses fictional data and local state, not persistence or a backend.
91
+
92
+ ### Accessible interaction
93
+
94
+ - `Actions.Button` (including `.Icon`), `Actions.IconButton`, `BaseButton`,
95
+ `Feedback.EmptyState`, `Feedback.Error` and `Form.Input` accept `accessibleSizing` to
96
+ opt into a minimum 48-point target. Buttons also allow enlarged, multiline labels in
97
+ this mode. Existing sizing remains the default for compatibility.
98
+ - Supply `accessibilityLabel` for icon-only actions. Loading buttons expose busy/disabled
99
+ state and retain their accessible name.
100
+ - `Display.CopyableText` uses a familiar copy icon: tap a short value to copy it.
101
+ A transient checkmark confirms success without adding a “Copiado” block or shifting
102
+ layout; screen readers receive an announcement. Use `selectable` for longer text:
103
+ native text selection stays independent of the 48-point icon action that copies the
104
+ full value. Failures stay explicit and retryable. It accepts `disabled`, `testID`,
105
+ `accessibilityLabel`, `onCopied` and `onCopyError`. Copy targets intentionally reserve 48 points.
106
+ - `Display.KeyValue copyable` enables copying string/number values (enforced by its type).
107
+ Use `align="stacked"` for long content or `align="auto"` to stack below 360 points or
108
+ above a 1.3 font scale. Existing `align="row"` remains unchanged; React nodes are
109
+ display-only.
110
+ - `KeyValue selectable` also supports native text selection, with or without copying.
111
+ Choose the mode by the purpose of the field, not an automatic character-count threshold.
112
+ - `Typography.SelectableText` provides read-only native range selection without opening
113
+ the keyboard. It preserves typography/tokens and backs the longer-text modes above.
114
+ On iOS, `Text selectable` alone only exposes full-paragraph copying, not range handles.
115
+ - Headings and section titles expose native header semantics.
116
+ - Checkbox/Select announce control state; their `accessibleSizing` mode enlarges targets.
117
+ - Sheet supports accessible escape and `showCloseButton`; `SwipeableRow visibleActions`
118
+ supplies a non-gesture alternative. Keep explicit labels for essential actions.
119
+ - `Dialog/NativeSheet` is an optional Expo 58 native presentation (`@expo/ui` peer);
120
+ import it by subpath, not the root barrel. Use short action sheets for choices and a
121
+ sheet for a scoped task; do not stack sheets. Mobile-task stories demonstrate native
122
+ summaries, cancelable selection, filters applied only on confirmation and archive/undo.
123
+ - Form/List view refresh always clears the busy state on failure and accepts
124
+ `onRefreshError` for application recovery without discarding content.
125
+ - AppBar, BottomNav and SegmentedControl support accessible sizing; banners expose status
126
+ semantics, and confirmation defaults use explicit verbs.
127
+
128
+ The [audit and validation report](docs/UX-AUDIT.md) records scope, evidence and device limits.
129
+
130
+ ### Clean Sincpro grouping and customization
131
+
132
+ `Display.ListGroup` groups related settings or a short list on one surface, with a title,
133
+ optional description/footer/action and hairline separators only between rows. Choose
134
+ `surface="plain"` for grouping by proximity instead of a rounded container.
135
+
136
+ ```tsx
137
+ <Display.ListGroup
138
+ title="Cuenta"
139
+ footer="Puedes cambiar estas preferencias en cualquier momento."
140
+ contentClassName="rounded-lg bg-bg-muted"
141
+ >
142
+ <Display.ListItem
143
+ variant="mobile"
144
+ title="Idioma"
145
+ value="Español"
146
+ chevron
147
+ onPress={openLanguageChoices}
148
+ />
149
+ <Display.ListItem
150
+ variant="mobile"
151
+ title="Avisos importantes"
152
+ trailing={notificationControl}
153
+ />
154
+ </Display.ListGroup>
155
+ ```
156
+
157
+ - `ListItem variant="mobile"` opts into wrapping, a 48-point target,
158
+ tonal row press feedback and adaptive accessories. `layout="auto"` stacks values/controls
159
+ below the text on narrow screens or enlarged text; use `layout="stacked"` for narrow
160
+ embedded containers. Navigation values are also exposed as native accessibility values.
161
+ - New mobile rows default to `density="compact"`: regular 14-point titles/values,
162
+ 13-point supporting text and 8-point vertical padding. `density="comfortable"` restores
163
+ the earlier PR's 17/16-point reading presentation and 12-point padding.
164
+ Legacy rows (`variant="default"`) keep their original appearance.
165
+ - Put a toggle/checkbox in a **non-pressable** row; do not nest a second action inside a
166
+ pressable row. The leading/trailing slots remain consumer-owned.
167
+ - `Typography.Text variant="bodyReadable"` and `Typography.SelectableText` with the same
168
+ variant opt into 17 points while retaining `configureFonts` and system font scaling.
169
+ The 14-point `body` and existing ListItem appearance remain unchanged.
170
+ - Customize per instance with `className`, `contentClassName`, slots, surface and separators.
171
+ Rows also accept `style`, `titleTextProps`, `subtitleTextProps` and `valueTextProps`.
172
+ Text props accept typography variants, weights, font families and native style arrays.
173
+ `ListGroup.headerProps` forwards header styling/text props; `footerTextProps` controls
174
+ string footers. Default groups use a 16-point section heading and 13-point description/footer.
175
+ Group `style`, `contentStyle` and `separatorStyle` control spacing, surface and dividers.
176
+ Headers expose `style`, `contentStyle`, `actionStyle` and `actionTextProps` as well.
177
+ For example, `titleTextProps={{ style: { fontFamily: "MyLoadedFont", fontSize: 15 } }}`
178
+ changes only one row, without copying its focus, accessibility or press behavior.
179
+ Customize branding centrally with `buildThemeFromBrand`/`extendTheme`, `setActiveTheme`
180
+ and `themeToVars` on the host, plus `configureFonts` for already-loaded font families.
181
+ Do not introduce a competing palette or hardcode colors in every screen.
182
+ - This group is not virtualized: use FlatList/SectionList for large or unbounded collections.
183
+
184
+ Stories: `Patterns/Forms/Settings` shows Sincpro defaults, long content, customized
185
+ surfaces and text roles. `Foundations/Typography/CompactHierarchy` and
186
+ `ComfortableHierarchy` show the same content at two densities, not two mandatory screens.
187
+ Customization is not a complete visual approval.
188
+
189
+ ### Compose collections, not a prescribed screen
190
+
191
+ `Patterns/Collections/Browsing` shows the same local data as rows, cards and
192
+ long-label variants. It combines icons, bounded 56-point artwork, readable text, metrics,
193
+ independent open/save actions and a native detail sheet. These are recipes to adapt,
194
+ not new domain-specific screen components or a web toolbar squeezed onto a phone.
195
+
196
+ ```tsx
197
+ import { FilterBar } from "@sincpro/mobile-ui/widgets";
198
+
199
+ <FilterBar
200
+ filters={filterOptions}
201
+ onFilterPress={toggleFilter}
202
+ onClearFilters={clearFilters}
203
+ onOpenFilters={openFilterSheet}
204
+ resultsLabel={resultsLabel}
205
+ search={{
206
+ value: query,
207
+ onChangeText: setQuery,
208
+ accessibilityLabel: "Buscar recursos",
209
+ clearAccessibilityLabel: "Limpiar búsqueda",
210
+ }}
211
+ />;
212
+ ```
213
+
214
+ Each filter supplies `id`, `label`, `selected` and optional `disabled`. State, matching,
215
+ result counts and advanced-filter drafts belong to the host. Clearing filters does not
216
+ silently clear the search query. Search, advanced action, result label and clear action
217
+ are optional; customize labels, `className`, theme and `layout="scroll|wrap|auto"`.
218
+ Auto wraps above font scale 1.3, otherwise it scrolls horizontally. Quick chips apply
219
+ immediately; the recipe's advanced sheet applies only on confirmation.
220
+
221
+ `Actions.FilterButton variant="mobile"` adds readable wrapping labels and 48-point targets.
222
+ `FilterButtonGroup layout="scroll|wrap"` and `Navigation.SearchBar accessibleSizing` are
223
+ additive; legacy filter layout and search sizing remain unchanged.
224
+ When placing these controls in a host ScrollView, use `keyboardShouldPersistTaps="handled"`
225
+ so a filter can act on the first tap while the keyboard is open.
226
+ Use virtualized lists for production-sized collections.
227
+
228
+ Dependencies follow the latest stable version compatible with Expo 58, not unbounded
229
+ upgrades. Validate with `CI=1 npx expo install --check` in addition to the quality gates.
230
+
231
+ ### Controlled reordering without a closed row design
232
+
233
+ Optional import: `@sincpro/mobile-ui/widgets/ReorderableList`. Install
234
+ `react-native-sortables@^1.10.1` in the host; it uses the host's Gesture Handler 3.3+,
235
+ Reanimated 4.7+ and Worklets setup. Wrap the app in `GestureHandlerRootView`.
236
+ The adapter is deliberately **not** in the generic widgets/root barrels: applications
237
+ that do not use drag-and-drop do not need to resolve this optional peer.
238
+
239
+ ```tsx
240
+ import ReorderableList from "@sincpro/mobile-ui/widgets/ReorderableList";
241
+
242
+ <ReorderableList
243
+ items={sections}
244
+ keyExtractor={(item) => item.id}
245
+ getItemLabel={(item) => item.name}
246
+ onChange={(next) => setSections(next)}
247
+ renderItem={({ item }) => <MySectionContent section={item} />}
248
+ itemStyle={{ borderRadius: 16, padding: 8 }}
249
+ />;
250
+ ```
251
+
252
+ - A one-column, **non-virtualized short-list** adapter with variable-height content.
253
+ It does not own screen scrolling, persistence, confirmation or domain rules.
254
+ Do not use it as an unbounded feed, kanban board, file drop zone or cross-app drag API.
255
+ - Only the dedicated handle starts drag. Default arrows and the handle's native
256
+ increment/decrement actions offer alternatives; content can retain buttons, inputs
257
+ or any custom layout. Drag/drop uses insertion, not swapping.
258
+ - `onChange(next, { key, fromIndex, toIndex, source })` delivers an immutable order
259
+ (`source` is `drag` or `button`). Update controlled state synchronously; persist later,
260
+ showing save failures/retry in the host. A drop in the original position emits no change.
261
+ Draft/apply/cancel/undo can be built by owning that state, without replacing the gesture.
262
+ - Keys must be unique non-empty strings, stable across renders, never array indices.
263
+ Content updates with the same keys preserve current objects. Insert/remove/external
264
+ reorder or disabling **during** drag cancels the gesture, retains host data and shows
265
+ an accessible error. `onReorderRejected` reports `data-changed` or `disabled`.
266
+ The gesture engine remounts on rejection; keep persistent item state in the host.
267
+ - `renderItem` controls content. `renderControls` receives `dragHandle`, movement
268
+ callbacks and boundary flags; keep that handle and an accessible non-drag alternative
269
+ when replacing controls. `renderHandleContent` replaces **noninteractive** handle
270
+ contents only, keeping the gesture, accessible name and adjustable actions.
271
+ - Root `className`/`style`, `itemStyle`, `contentStyle`, `controlsStyle`, `handleStyle`
272
+ and `actionStyle` accept local layout/shape/spacing. Child content owns typography.
273
+ `labels` localizes controls, announcements and conflict errors.
274
+ - `sortableProps` forwards engine options such as activation delay, row gap, decorations,
275
+ animation settings and autoscroll, while the adapter owns identity, single-column
276
+ insertion and controlled callbacks. Provide a stable Reanimated `scrollableRef` to
277
+ the **actual Animated.ScrollView** for autoscroll; do not nest another scroll container
278
+ or attach the ref to a different view. Native scroll props/ref belong to the host.
279
+ Custom motion, targets and colors still require accessibility validation.
280
+
281
+ `Patterns/Collections/Reordering` demonstrates default, custom content/controls, long
282
+ rows and an external-update conflict. Only this recipe uses the new dependency;
283
+ existing form/list/query templates keep their behavior.
284
+
285
+ ### Keyboard-aware forms and field navigation
286
+
287
+ Expo 58 does not automatically make arbitrary form layouts keyboard-safe.
288
+ The host must include `react-native-keyboard-controller` and its `KeyboardProvider` at
289
+ the app root. Use a development build when the runtime does not include that native module.
290
+
291
+ ```tsx
292
+ <Form.KeyboardForm contentContainerStyle={{ padding: 16, gap: 16 }}>
293
+ {fields}
294
+ </Form.KeyboardForm>
295
+ ```
296
+
297
+ `KeyboardForm` owns the scroll and scopes editable inputs with `KeyboardToolbar.Group`.
298
+ Its toolbar provides previous/next/dismiss actions, including phone/number keyboards.
299
+ The scroll reserves the measured toolbar height plus 24 points (normally 72 total);
300
+ it grows with enlarged text. Override `bottomOffset` for additional accessories.
301
+ `toolbar={false}` keeps automatic avoidance without the toolbar.
302
+ Customize `toolbarLabels` or compose `Form.KeyboardToolbar` with an existing aware scroll,
303
+ using `onHeightChange` to reserve its measured height. The toolbar compensates for space
304
+ below its parent, such as a safe area or form footer, instead of floating over the caret.
305
+ The default toolbar uses compact icons; `toolbarProps={{ showDoneLabel: true }}` opts into
306
+ a text dismiss action. `toolbarProps` also accepts `className`, `style`, `actionStyle`,
307
+ `labelStyle`, `iconSize` and `renderActionContent(action, { label, disabled })`.
308
+ The content slot replaces only non-interactive content: the toolbar retains focus actions,
309
+ accessible labels and disabled states. `toolbarLabels` remains supported;
310
+ `toolbarProps` takes precedence. Font size/family and shape can be changed without
311
+ reimplementing keyboard behavior.
312
+ Do not nest this component inside another vertical ScrollView.
313
+
314
+ For existing templates, opt into `FormViewV2.Content keyboardToolbar` or
315
+ `AuthFormView keyboardToolbar` / `AuthContainer keyboardToolbar`; defaults stay unchanged.
316
+ `Form.Input` forwards its native ref for explicit return-key navigation:
317
+ `onSubmitEditing={() => nextRef.current?.focus()}` with `submitBehavior="submit"`.
318
+ `KeyboardForm` forwards its ref to the native aware scroll for methods such as
319
+ `assureFocusedInputVisible()` after validation/layout changes.
320
+ The three templates accept `keyboardFormProps` (excluding `children` and `toolbar`) for
321
+ the same ref, offsets, toolbar customization, scroll callbacks and content styling.
322
+ `keyboardToolbar` remains the explicit opt-in; omitting it preserves the original
323
+ template layout without a toolbar.
324
+ Multiline Return remains a newline; dismissing the keyboard does not submit the form.
325
+ Story: `Patterns/Forms/Keyboard navigation`.
326
+
327
+ `ListViewV2.Content` accepts native `keyboardShouldPersistTaps` and `keyboardDismissMode`
328
+ across populated, empty and error states. Handled row/retry actions receive the first tap
329
+ while search has focus (`"handled"` by default); pass `"never"` for the old dismiss-first
330
+ behavior. Drag-dismiss remains opt-in (`keyboardDismissMode="on-drag"`).
331
+ This changes interaction, not the list's typography or layout.
332
+
333
+ ```tsx
334
+ <FormViewV2.Content
335
+ keyboardToolbar
336
+ keyboardFormProps={{
337
+ ref: scrollRef,
338
+ toolbarProps: {
339
+ style: { borderRadius: 16 },
340
+ iconSize: 18,
341
+ showDoneLabel: true,
342
+ labelStyle: { fontFamily: "MyFont", fontSize: 13 },
343
+ },
344
+ }}
345
+ >
346
+ {fields}
347
+ </FormViewV2.Content>
348
+ ```
349
+
350
+ Default list rows now honor the template's `onPressItem` and `readonly` settings;
351
+ direct `Navigation.RowItem` usage can still supply the legacy callback on `item`.
352
+
353
+ ### Structured queries, not just quick chips
354
+
355
+ `widgets.FilterBuilder` edits a controlled `CriteriaGroup`: nested `all`/`any`/`none`
356
+ groups and configured conditions. Supply fields with their label, type, permitted
357
+ operators and arity (`none`, `one`, `range`); choice values are explicit. Numbers remain
358
+ editable strings until validated/committed, date fields use the native picker, and invalid
359
+ conditions produce visible errors. The mobile editor opens one group at a time instead of
360
+ squeezing an arbitrarily indented desktop tree into the screen.
361
+
362
+ `widgets.CollectionOptions` is a full-screen, keyboard-aware workspace:
363
+
364
+ ```tsx
365
+ <CollectionOptions
366
+ visible={open}
367
+ value={query}
368
+ fields={filterFields}
369
+ sortFields={sortFields}
370
+ groupFields={groupFields}
371
+ savedQueries={savedQueries}
372
+ onApply={applyQuery}
373
+ onClose={closeOptions}
374
+ onSave={saveQuery}
375
+ />
376
+ ```
377
+
378
+ `CollectionQuery` contains `search`, `filter`, ordered `sort` entries and ordered
379
+ `groupBy` field IDs. Order and grouping priorities have explicit move/remove actions;
380
+ dragging is not required. Loading a saved configuration changes the draft only;
381
+ Apply commits all dimensions together, Cancel discards the draft. Save errors keep the
382
+ draft/name for retry. The host owns saving/loading and closes the workspace after Apply.
383
+
384
+ The DS does not fetch models, evaluate filters, sort a page as if it were the full dataset,
385
+ persist favorites or translate this tree into a backend query language. Relational paths,
386
+ remote model discovery and a JSON editor are not implemented here. The web builder is a
387
+ semantic reference, not a component copied into mobile.
388
+
389
+ `Navigation.SearchBar suggestions={{ items, onSelect, loading, error, onRetry }}` shows
390
+ host-supplied autocomplete while focused. Choosing a suggestion calls `onSelect` without
391
+ silently rewriting the query. A host may complete a title or create a field-specific
392
+ condition; it owns matching, request cancellation and stale responses.
393
+
394
+ Story: `Patterns/Collections/Query configuration` exercises actual local filtering,
395
+ multiple sorting priorities, grouping levels and saving/loading configurations.
396
+
397
+ ### Native E2E
398
+
399
+ With Maestro installed and an iOS simulator running Expo Go, start an isolated test server:
400
+
401
+ ```bash
402
+ EXPO_PUBLIC_STORYBOOK_TEST=1 npx expo start --port 8082
403
+ make storybook-e2e
404
+ ```
405
+
406
+ This disables Storybook's on-device chrome for tests without changing the normal server.
407
+ The flows verify copy, edit, cancel, failed-save recovery and long-content/dark interaction.
408
+ `STORYBOOK_URL` can override the default `exp://127.0.0.1:8082`.
409
+ Maestro analytics are disabled by the Makefile target. These flows target Expo Go on iOS;
410
+ Android needs a connected device and its appropriate app ID/host configuration.
411
+ Tests stop/relaunch Expo Go and switch stories; run them on a dedicated test simulator.
412
+ Enlarged-text screenshots are accessibility stress tests, not the default typography.
413
+
83
414
  ### Maintained for the long term
84
415
 
85
416
  Enterprise software lives for years. The screens built with this DS will be in production long after the initial project is delivered. Sincpro's commitment is to maintain API stability, patch what breaks on platform upgrades, and evolve the system without forcing rewrites on consumers.
@@ -133,7 +464,7 @@ Queued toast system with promise support — covers the full loading → success
133
464
  import { ToastProvider, useToast } from "@sincpro/mobile-ui/Feedback";
134
465
 
135
466
  // 1. Wrap the app once (createAppShell does this automatically)
136
- <ToastProvider position="top">{children}</ToastProvider>
467
+ <ToastProvider position="top">{children}</ToastProvider>;
137
468
 
138
469
  // 2. Call from anywhere in the tree
139
470
  const toast = useToast();
@@ -141,7 +472,7 @@ toast.success("Invoice saved");
141
472
  toast.promise(sendInvoice(), {
142
473
  loading: "Sending…",
143
474
  success: "Invoice sent",
144
- error: "Failed to send",
475
+ error: "Failed to send",
145
476
  });
146
477
  ```
147
478
 
@@ -153,8 +484,8 @@ import { ConfirmationProvider, useConfirmationContext } from "@sincpro/mobile-ui
153
484
 
154
485
  // Controlled sheet — built on RN Modal, no native peer deps
155
486
  <Sheet visible={open} onClose={() => setOpen(false)} title="Options">
156
- <Form.Button onPress={confirm}>Confirm</Form.Button>
157
- </Sheet>
487
+ <Actions.Button onPress={confirm}>Confirm</Actions.Button>
488
+ </Sheet>;
158
489
 
159
490
  // Imperative confirmation
160
491
  const { confirm } = useConfirmationContext();
@@ -167,10 +498,16 @@ const agreed = await confirm({ title: "Delete invoice?", message: "This cannot b
167
498
  import { Wizard, useWizard } from "@sincpro/mobile-ui/views/Wizard";
168
499
 
169
500
  <Wizard initialStep="customer">
170
- <Wizard.Step id="customer"><CustomerStep /></Wizard.Step>
171
- <Wizard.Step id="items"><ItemsStep /></Wizard.Step>
172
- <Wizard.Step id="review"><ReviewStep /></Wizard.Step>
173
- </Wizard>
501
+ <Wizard.Step id="customer">
502
+ <CustomerStep />
503
+ </Wizard.Step>
504
+ <Wizard.Step id="items">
505
+ <ItemsStep />
506
+ </Wizard.Step>
507
+ <Wizard.Step id="review">
508
+ <ReviewStep />
509
+ </Wizard.Step>
510
+ </Wizard>;
174
511
 
175
512
  // Inside any step
176
513
  const { go, back } = useWizard();
@@ -196,162 +533,163 @@ import { Display } from "@sincpro/mobile-ui/Display";
196
533
 
197
534
  ### Actions
198
535
 
199
- | Component | Description |
200
- |-----------|-------------|
201
- | `Actions.Button` | Primary action — gradient, outline, flat, link variants; optional confirm dialog |
202
- | `Actions.IconButton` | Icon-only tap target — ghost, primary, secondary, tertiary variants |
203
- | `Actions.FAB` | Floating Action Button — fixed position, optional label |
204
- | `Actions.FilterButton` | Chip-style active/inactive toggle |
205
- | `Actions.FilterButtonGroup` | Horizontal scroll container for filter chips |
536
+ | Component | Description |
537
+ | --------------------------- | -------------------------------------------------------------------------------- |
538
+ | `Actions.Button` | Primary action — gradient, outline, flat, link variants; optional confirm dialog |
539
+ | `Actions.IconButton` | Icon-only tap target — ghost, primary, secondary, tertiary variants |
540
+ | `Actions.FAB` | Floating Action Button — fixed position, optional label |
541
+ | `Actions.FilterButton` | Chip-style active/inactive toggle |
542
+ | `Actions.FilterButtonGroup` | Horizontal scroll container for filter chips |
206
543
 
207
544
  ### Display
208
545
 
209
- | Component | Description |
210
- |-----------|-------------|
211
- | `Display.Badge` | Status badge — success, warning, danger, info, neutral |
212
- | `Display.Card` | Surface container with optional shadow and padding |
213
- | `Display.KeyValue` | Label + value row, optional clipboard copy |
214
- | `Display.Stat` | KPI cell — label, value, optional trend indicator |
215
- | `Display.StatCard` | Card-wrapped KPI |
216
- | `Display.Monetary` | Formatted monetary amount using mono typography |
217
- | `Display.PriceTag` | Currency-formatted price with size options |
218
- | `Display.DataTable` | Scrollable table for structured data |
219
- | `Display.ListItem` | Row with icon, label, sublabel, optional action |
220
- | `Display.Chip` | Compact label tag |
221
- | `Display.Avatar` / `AvatarGroup` | User avatar, stacked group |
222
- | `Display.Icon` | Vector icon wrapper (`@expo/vector-icons`) |
223
- | `Display.StatusDot` | Colored presence / state indicator |
224
- | `Display.Divider` | Horizontal separator |
225
- | `Display.GradientSurface` | Container with linear gradient background |
226
- | `Display.Timeline` | Vertical event timeline |
227
- | `Display.SwipeableRow` | Row with swipe-to-reveal actions |
228
- | `Display.Tooltip` | Overlay tooltip |
229
- | `Display.CopyableText` | Text with one-tap clipboard copy |
230
- | `Display.Logo` | Brand logo (falls back to `setBranding` value) |
231
- | `Display.Accordion` | Collapsible content section |
232
- | `Display.Carousel` | Horizontal swipe carousel |
233
- | `Display.Story` / `StoryTray` / `StoryViewer` | Stories UI pattern |
234
- | `Display.MediaCard` | Card with image or video embed |
235
- | `Display.Pattern` | Decorative background pattern |
546
+ | Component | Description |
547
+ | --------------------------------------------- | ------------------------------------------------------ |
548
+ | `Display.Badge` | Status badge — success, warning, danger, info, neutral |
549
+ | `Display.Card` | Surface container with optional shadow and padding |
550
+ | `Display.KeyValue` | Label + value row, optional clipboard copy |
551
+ | `Display.Stat` | KPI cell — label, value, optional trend indicator |
552
+ | `Display.StatCard` | Card-wrapped KPI |
553
+ | `Display.Monetary` | Formatted monetary amount using mono typography |
554
+ | `Display.PriceTag` | Currency-formatted price with size options |
555
+ | `Display.DataTable` | Scrollable table for structured data |
556
+ | `Display.ListItem` | Row with icon, label, sublabel, optional action |
557
+ | `Display.Chip` | Compact label tag |
558
+ | `Display.Avatar` / `AvatarGroup` | User avatar, stacked group |
559
+ | `Display.Icon` | Vector icon wrapper (`@expo/vector-icons`) |
560
+ | `Display.StatusDot` | Colored presence / state indicator |
561
+ | `Display.Divider` | Horizontal separator |
562
+ | `Display.GradientSurface` | Container with linear gradient background |
563
+ | `Display.Timeline` | Vertical event timeline |
564
+ | `Display.SwipeableRow` | Row with swipe-to-reveal actions |
565
+ | `Display.Tooltip` | Overlay tooltip |
566
+ | `Display.CopyableText` | Text with one-tap clipboard copy |
567
+ | `Display.Logo` | Brand logo (falls back to `setBranding` value) |
568
+ | `Display.Accordion` | Collapsible content section |
569
+ | `Display.Carousel` | Horizontal swipe carousel |
570
+ | `Display.Story` / `StoryTray` / `StoryViewer` | Stories UI pattern |
571
+ | `Display.MediaCard` | Card with image or video embed |
572
+ | `Display.Pattern` | Decorative background pattern |
236
573
 
237
574
  ### Form
238
575
 
239
- | Component | Description |
240
- |-----------|-------------|
241
- | `Form.TextInput` | Text field with label, error, and helper text |
242
- | `Form.PasswordInput` | Text input with show/hide toggle |
243
- | `Form.PinInput` | PIN code entry |
244
- | `Form.MonetaryInput` | Currency input with formatting |
245
- | `Form.QuantitySelector` | Integer increment / decrement |
246
- | `Form.FractionalQuantityInput` | Decimal quantity input |
247
- | `Form.Select` | Dropdown select (modal-based) |
248
- | `Form.Dropdown` | Inline dropdown menu |
249
- | `Form.RadioButton` | Single-select radio option |
250
- | `Form.Checkbox` | Multi-select checkbox |
251
- | `Form.Switch` | Toggle switch |
252
- | `Form.Slider` | Range slider (`@react-native-community/slider` peer) |
253
- | `Form.DatePicker` | Date picker (`@react-native-community/datetimepicker` peer) |
254
- | `Form.SearchBar` | Search input with clear button |
255
- | `Form.ControlledInput` | `TextInput` + react-hook-form |
256
- | `Form.ControlledRadioButton` | `RadioButton` + react-hook-form |
257
- | `Form.ControlledCheckbox` | `Checkbox` + react-hook-form |
258
- | `Form.ControlledDropdown` | `Dropdown` + react-hook-form |
259
- | `Form.ControlledMonetaryInput` | `MonetaryInput` + react-hook-form |
260
- | `Form.Button` / `IconButton` / `FAB` | Action components in Form namespace |
576
+ | Component | Description |
577
+ | --------------------------------------- | ------------------------------------------------------------------- |
578
+ | `Form.TextInput` | Text field with label, error, and helper text |
579
+ | `Form.PasswordInput` | Text input with show/hide toggle |
580
+ | `Form.PinInput` | PIN code entry |
581
+ | `Form.MonetaryInput` | Currency input with formatting |
582
+ | `Form.QuantitySelector` | Integer increment / decrement |
583
+ | `Form.FractionalQuantityInput` | Decimal quantity input |
584
+ | `Form.Select` | Dropdown select (modal-based) |
585
+ | `Form.Dropdown` | Inline dropdown menu |
586
+ | `Form.RadioButton` | Single-select radio option |
587
+ | `Form.Checkbox` | Multi-select checkbox |
588
+ | `Form.Switch` | Toggle switch |
589
+ | `Form.Slider` | Range slider (`@react-native-community/slider` peer) |
590
+ | `Form.DatePicker` | Date picker (`@react-native-community/datetimepicker` peer) |
591
+ | `Form.SearchBar` | Search input with clear button |
592
+ | `Form.ControlledInput` | `TextInput` + react-hook-form |
593
+ | `Form.ControlledRadioButton` | `RadioButton` + react-hook-form |
594
+ | `Form.ControlledCheckbox` | `Checkbox` + react-hook-form |
595
+ | `Form.ControlledDropdown` | `Dropdown` + react-hook-form |
596
+ | `Form.ControlledMonetaryInput` | `MonetaryInput` + react-hook-form |
597
+ | `Actions.Button` / `IconButton` / `FAB` | Action components (preferred over deprecated `Form.Button` aliases) |
261
598
 
262
599
  ### Feedback
263
600
 
264
- | Component | Description |
265
- |-----------|-------------|
266
- | `Feedback.Spinner` | Animated loading spinner |
267
- | `Feedback.Loading` | Full-screen loading overlay |
268
- | `Feedback.Skeleton` | Content placeholder shimmer |
269
- | `Feedback.Progress` | Linear progress bar |
270
- | `Feedback.ProgressCircle` | Circular progress indicator |
271
- | `Feedback.Banner` | Contextual notification banner |
272
- | `Feedback.Empty` / `EmptyState` | Empty list or page placeholder |
273
- | `Feedback.Error` | Error state with optional retry |
274
- | `Feedback.PermissionCard` | Permission request UI |
275
- | `ToastProvider` / `useToast` | Queued toast notification system |
276
- | `ErrorBoundary` | React error boundary wrapper |
601
+ | Component | Description |
602
+ | ------------------------------- | -------------------------------- |
603
+ | `Feedback.Spinner` | Animated loading spinner |
604
+ | `Feedback.Loading` | Full-screen loading overlay |
605
+ | `Feedback.Skeleton` | Content placeholder shimmer |
606
+ | `Feedback.Progress` | Linear progress bar |
607
+ | `Feedback.ProgressCircle` | Circular progress indicator |
608
+ | `Feedback.Banner` | Contextual notification banner |
609
+ | `Feedback.Empty` / `EmptyState` | Empty list or page placeholder |
610
+ | `Feedback.Error` | Error state with optional retry |
611
+ | `Feedback.PermissionCard` | Permission request UI |
612
+ | `ToastProvider` / `useToast` | Queued toast notification system |
613
+ | `ErrorBoundary` | React error boundary wrapper |
277
614
 
278
615
  ### Navigation
279
616
 
280
- | Component | Description |
281
- |-----------|-------------|
282
- | `Navigation.AppBar` | Top navigation bar with action slots |
283
- | `Navigation.BottomNav` | Bottom tab bar |
284
- | `Navigation.Header` | Screen header |
285
- | `Navigation.HeaderToolbar` | Header with left, center, right slots |
286
- | `Navigation.CollapsingHeader` | Header that collapses on scroll |
287
- | `Navigation.FloatingBar` | Floating action bar |
288
- | `Navigation.SearchBar` | Navigation-level search input |
289
- | `Navigation.SegmentedControl` | Segmented control switcher |
290
- | `Navigation.Tabs` | Tab navigation container |
291
- | `Navigation.Steps` | Step indicator / breadcrumb |
292
- | `Navigation.Menu` / `MenuSection` | Dropdown menu with sections |
617
+ | Component | Description |
618
+ | --------------------------------- | ------------------------------------- |
619
+ | `Navigation.AppBar` | Top navigation bar with action slots |
620
+ | `Navigation.BottomNav` | Bottom tab bar |
621
+ | `Navigation.Header` | Screen header |
622
+ | `Navigation.HeaderToolbar` | Header with left, center, right slots |
623
+ | `Navigation.CollapsingHeader` | Header that collapses on scroll |
624
+ | `Navigation.FloatingBar` | Floating action bar |
625
+ | `Navigation.SearchBar` | Navigation-level search input |
626
+ | `Navigation.SegmentedControl` | Segmented control switcher |
627
+ | `Navigation.Tabs` | Tab navigation container |
628
+ | `Navigation.Steps` | Step indicator / breadcrumb |
629
+ | `Navigation.Menu` / `MenuSection` | Dropdown menu with sections |
293
630
 
294
631
  ### Dialog
295
632
 
296
- | Component | Description |
297
- |-----------|-------------|
298
- | `Dialog.BottomSheet` | Bottom drawer (RN Modal, no native peer deps) |
299
- | `Dialog.ActionSheet` | Action sheet with options list |
300
- | `Dialog.Confirmation` | Confirm / cancel modal |
301
- | `Dialog.EditValue` | Inline edit value modal |
302
- | `Sheet` (direct import) | Controlled sheet via `Dialog/Dialog.Sheet` |
303
- | `ConfirmationProvider` / `useConfirmationContext` | Imperative confirmation API |
633
+ | Component | Description |
634
+ | ------------------------------------------------- | --------------------------------------------- |
635
+ | `Dialog.BottomSheet` | Bottom drawer (RN Modal, no native peer deps) |
636
+ | `Dialog.ActionSheet` | Action sheet with options list |
637
+ | `Dialog.Confirmation` | Confirm / cancel modal |
638
+ | `Dialog.EditValue` | Inline edit value modal |
639
+ | `Sheet` (direct import) | Controlled sheet via `Dialog/Dialog.Sheet` |
640
+ | `ConfirmationProvider` / `useConfirmationContext` | Imperative confirmation API |
304
641
 
305
642
  ### Typography
306
643
 
307
- | Component | Description |
308
- |-----------|-------------|
309
- | `Typography.Text` | Main text component — accepts `variant` prop from the full scale |
310
- | `Typography.Heading` | Heading shorthand |
644
+ | Component | Description |
645
+ | -------------------- | ---------------------------------------------------------------- |
646
+ | `Typography.Text` | Main text component — accepts `variant` prop from the full scale |
647
+ | `Typography.Heading` | Heading shorthand |
311
648
 
312
649
  ### Primitives
313
650
 
314
- | Component | Description |
315
- |-----------|-------------|
316
- | `Box` | NativeWind layout container |
317
- | `Row` | Horizontal flex |
318
- | `Stack` | Vertical flex |
319
- | `Spacer` | Flexible space filler |
320
- | `Pressable` | Animated press target |
321
- | `AspectRatio` | Aspect-ratio container |
651
+ | Component | Description |
652
+ | ------------- | --------------------------- |
653
+ | `Box` | NativeWind layout container |
654
+ | `Row` | Horizontal flex |
655
+ | `Stack` | Vertical flex |
656
+ | `Spacer` | Flexible space filler |
657
+ | `Pressable` | Animated press target |
658
+ | `AspectRatio` | Aspect-ratio container |
322
659
 
323
660
  ### Layouts
324
661
 
325
- | Component | Description |
326
- |-----------|-------------|
327
- | `Container` | Padded layout container |
328
- | `ScrollContainer` | Scrollable layout wrapper |
329
- | `GradientContainer` | Container with gradient background |
330
- | `PlainLayout` | Unstyled layout for custom screens |
662
+ | Component | Description |
663
+ | -------------------- | ------------------------------------- |
664
+ | `Container` | Padded layout container |
665
+ | `ScrollContainer` | Scrollable layout wrapper |
666
+ | `GradientContainer` | Container with gradient background |
667
+ | `PlainLayout` | Unstyled layout for custom screens |
331
668
  | `TabNavigatorLayout` | Layout for tab-based screen structure |
332
669
 
333
670
  ### Views
334
671
 
335
- | Component | Description |
336
- |-----------|-------------|
337
- | `ListViewV2` | Paginated list with filtering and empty states |
338
- | `FormViewV2` | Dynamic form view with field management |
339
- | `AuthFormView` | Authentication form layout |
672
+ | Component | Description |
673
+ | ---------------------- | ------------------------------------------------- |
674
+ | `ListViewV2` | Paginated list with filtering and empty states |
675
+ | `FormViewV2` | Dynamic form view with field management |
676
+ | `AuthFormView` | Authentication form layout |
340
677
  | `Wizard` / `useWizard` | Multi-step wizard with guards and lifecycle hooks |
678
+ | `AppSplashView` | Branded splash screen with logo and loading state |
341
679
 
342
680
  ### Widgets
343
681
 
344
- | Component | Description |
345
- |-----------|-------------|
346
- | `ScreenHeader` | Composite screen header widget |
347
- | `MenuGrid` / `MenuCard` | Grid and card-based navigation menus |
348
- | `QuickActions` | Quick action icon grid |
349
- | `PromoBanner` | Swipeable promotional carousel |
350
- | `PromoModal` | Promotional modal overlay |
351
- | `HomeHeader` | Home screen hero header |
352
- | `GeoPermissionCard` | Geolocation permission request card |
353
- | `TimeZoneSelector` | Timezone picker widget |
354
- | `JSONViewer` | Collapsible JSON tree (debug / dev tools) |
682
+ | Component | Description |
683
+ | ----------------------- | ----------------------------------------- |
684
+ | `ScreenHeader` | Composite screen header widget |
685
+ | `MenuGrid` / `MenuCard` | Grid and card-based navigation menus |
686
+ | `QuickActions` | Quick action icon grid |
687
+ | `PromoBanner` | Swipeable promotional carousel |
688
+ | `PromoModal` | Promotional modal overlay |
689
+ | `HomeHeader` | Home screen hero header |
690
+ | `GeoPermissionCard` | Geolocation permission request card |
691
+ | `TimeZoneSelector` | Timezone picker widget |
692
+ | `JSONViewer` | Collapsible JSON tree (debug / dev tools) |
355
693
 
356
694
  ---
357
695
 
@@ -372,7 +710,7 @@ setActiveTheme(MY_DARK_THEME);
372
710
 
373
711
  // Inject CSS variables into a subtree
374
712
  const themeStyle = vars(themeToVars(MY_DARK_THEME));
375
- <View style={themeStyle}>{children}</View>
713
+ <View style={themeStyle}>{children}</View>;
376
714
  ```
377
715
 
378
716
  ### Reading the theme in components
@@ -382,7 +720,9 @@ import { useTheme } from "@sincpro/mobile-ui/theme";
382
720
 
383
721
  function PriceCard() {
384
722
  const theme = useTheme();
385
- return <View style={{ backgroundColor: theme.bg.card, borderColor: theme.border.default }} />;
723
+ return (
724
+ <View style={{ backgroundColor: theme.bg.card, borderColor: theme.border.default }} />
725
+ );
386
726
  }
387
727
  ```
388
728
 
@@ -393,33 +733,33 @@ import { extendTheme } from "@sincpro/mobile-ui/theme";
393
733
 
394
734
  // Deep-merges on top of the DS base theme
395
735
  const MY_THEME = extendTheme({
396
- accent: "#00C357",
397
- primary: "#0B0B0B",
736
+ accent: "#00C357",
737
+ primary: "#0B0B0B",
398
738
  secondary: "#6B6963",
399
739
  bg: {
400
740
  page: "#FAFAFA",
401
741
  card: "#FFFFFF",
402
742
  },
403
743
  text: {
404
- accent: "#006E2E", // text on accent-tinted surfaces
744
+ accent: "#006E2E", // text on accent-tinted surfaces
405
745
  },
406
746
  });
407
747
  ```
408
748
 
409
749
  ### ThemeTokens reference
410
750
 
411
- | Group | Keys |
412
- |-------|------|
413
- | `primary / secondary / accent` | Main brand color scales |
414
- | `bg.*` | `page, card, muted, accent, hover, disabled, popover` |
415
- | `text.*` | `primary, secondary, tertiary, muted, accent, inverse, disabled, onPrimary, onSecondary, onAccent, onDanger, onSuccess` |
416
- | `icon.*` | `primary, secondary, tertiary, inverse, disabled` |
417
- | `border.*` | `default, light, strong, focus` |
418
- | `success / warning / danger / info` | Semantic state colors |
419
- | `*Light` | Tinted backgrounds for each state |
420
- | `ring / input` | Focus ring and input border |
421
- | `gradient.*` | `primary, accent` — arrays of color stops |
422
- | `shadow.*` | `sm, md, lg` — React Native shadow objects |
751
+ | Group | Keys |
752
+ | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
753
+ | `primary / secondary / accent` | Main brand color scales |
754
+ | `bg.*` | `page, card, muted, accent, hover, disabled, popover` |
755
+ | `text.*` | `primary, secondary, tertiary, muted, accent, inverse, disabled, onPrimary, onSecondary, onAccent, onDanger, onSuccess` |
756
+ | `icon.*` | `primary, secondary, tertiary, inverse, disabled` |
757
+ | `border.*` | `default, light, strong, focus` |
758
+ | `success / warning / danger / info` | Semantic state colors |
759
+ | `*Light` | Tinted backgrounds for each state |
760
+ | `ring / input` | Focus ring and input border |
761
+ | `gradient.*` | `primary, accent` — arrays of color stops |
762
+ | `shadow.*` | `sm, md, lg` — React Native shadow objects |
423
763
 
424
764
  ---
425
765
 
@@ -443,16 +783,16 @@ import { Typography } from "@sincpro/mobile-ui/Typography";
443
783
  <Typography.Text variant="button">Action Label</Typography.Text>
444
784
  ```
445
785
 
446
- | Group | Variants |
447
- |-------|----------|
448
- | Display | `display` |
449
- | Headings | `h1` `h2` `h3` `h4` `h5` `h6` |
450
- | Body | `bodyLarge` `body` `bodySmall` |
451
- | Labels | `label` `labelSmall` |
452
- | Data (mono) | `data` `dataLarge` |
453
- | Meta (mono) | `overline` `caption` `captionSmall` |
454
- | Buttons | `button` `buttonSmall` `buttonLarge` |
455
- | Legacy | `title` `subtitle` |
786
+ | Group | Variants |
787
+ | ----------- | ------------------------------------ |
788
+ | Display | `display` |
789
+ | Headings | `h1` `h2` `h3` `h4` `h5` `h6` |
790
+ | Body | `bodyLarge` `body` `bodySmall` |
791
+ | Labels | `label` `labelSmall` |
792
+ | Data (mono) | `data` `dataLarge` |
793
+ | Meta (mono) | `overline` `caption` `captionSmall` |
794
+ | Buttons | `button` `buttonSmall` `buttonLarge` |
795
+ | Legacy | `title` `subtitle` |
456
796
 
457
797
  ### FontRole
458
798
 
@@ -473,9 +813,9 @@ import { configureFonts, resetFonts } from "@sincpro/mobile-ui/theme/typography"
473
813
 
474
814
  configureFonts({
475
815
  titleRegular: "Satoshi-Regular",
476
- titleMedium: "Satoshi-Medium",
477
- title: "Satoshi-Bold",
478
- titleBlack: "Satoshi-Black",
816
+ titleMedium: "Satoshi-Medium",
817
+ title: "Satoshi-Bold",
818
+ titleBlack: "Satoshi-Black",
479
819
  });
480
820
 
481
821
  // Reset to defaults — useful in tests and Storybook stories
@@ -484,15 +824,15 @@ resetFonts();
484
824
 
485
825
  ### Font size scale
486
826
 
487
- | Token | `px` | Token | `px` |
488
- |-------|------|-------|------|
489
- | `xs` | 10 | `4xl` | 28 |
490
- | `sm` | 13 | `5xl` | 32 |
491
- | `base` | 14 | `6xl` | 36 |
492
- | `lg` | 16 | `7xl` | 48 |
493
- | `xl` | 18 | `8xl` | 64 |
494
- | `2xl` | 20 | | |
495
- | `3xl` | 24 | | |
827
+ | Token | `px` | Token | `px` |
828
+ | ------ | ---- | ----- | ---- |
829
+ | `xs` | 10 | `4xl` | 28 |
830
+ | `sm` | 13 | `5xl` | 32 |
831
+ | `base` | 14 | `6xl` | 36 |
832
+ | `lg` | 16 | `7xl` | 48 |
833
+ | `xl` | 18 | `8xl` | 64 |
834
+ | `2xl` | 20 | | |
835
+ | `3xl` | 24 | | |
496
836
 
497
837
  ### Custom text styles
498
838
 
@@ -504,7 +844,7 @@ const errorLabel = createTextStyle("labelSmall", { color: "#FF4D1F" });
504
844
 
505
845
  // Fully custom
506
846
  const amountStyle = createCustomTextStyle("4xl", "monoMedium", {
507
- lineHeight: "none",
847
+ lineHeight: "none",
508
848
  letterSpacing: "tight",
509
849
  });
510
850
  ```
@@ -519,22 +859,22 @@ Centralized animation constants so motion feels consistent across every screen
519
859
  import { duration, easing, spring } from "@sincpro/mobile-ui/tokens";
520
860
 
521
861
  // Durations (ms)
522
- duration.instant // 0 — immediate state swap, no transition
523
- duration.fast // 120 — micro-interactions (button press, toggle)
524
- duration.normal // 200 — standard transitions (modal, drawer)
525
- duration.slow // 320 — large layout shifts
526
- duration.slower // 480 — onboarding, emphasis animations
862
+ duration.instant; // 0 — immediate state swap, no transition
863
+ duration.fast; // 120 — micro-interactions (button press, toggle)
864
+ duration.normal; // 200 — standard transitions (modal, drawer)
865
+ duration.slow; // 320 — large layout shifts
866
+ duration.slower; // 480 — onboarding, emphasis animations
527
867
 
528
868
  // Bezier easing curves
529
- easing.standard // general purpose
530
- easing.decelerate // elements entering the screen
531
- easing.accelerate // elements leaving the screen
532
- easing.emphasized // expressive, attention-drawing transitions
869
+ easing.standard; // general purpose
870
+ easing.decelerate; // elements entering the screen
871
+ easing.accelerate; // elements leaving the screen
872
+ easing.emphasized; // expressive, attention-drawing transitions
533
873
 
534
874
  // Reanimated spring presets
535
- spring.default // balanced bounce
536
- spring.gentle // smooth, no overshoot
537
- spring.snappy // fast with slight bounce
875
+ spring.default; // balanced bounce
876
+ spring.gentle; // smooth, no overshoot
877
+ spring.snappy; // fast with slight bounce
538
878
  ```
539
879
 
540
880
  Usage with Reanimated:
@@ -544,7 +884,7 @@ import { withTiming, withSpring } from "react-native-reanimated";
544
884
  import { duration, easing, spring } from "@sincpro/mobile-ui/tokens";
545
885
 
546
886
  const opacity = withTiming(1, { duration: duration.normal, easing: easing.decelerate });
547
- const scale = withSpring(1, spring.snappy);
887
+ const scale = withSpring(1, spring.snappy);
548
888
  ```
549
889
 
550
890
  ---
@@ -575,19 +915,15 @@ The preset ships the full token class set (`bg-primary`, `text-text-secondary`,
575
915
  ```js
576
916
  module.exports = {
577
917
  presets: [require("@sincpro/mobile-ui/tailwind.preset")],
578
- content: [
579
- "./App.tsx",
580
- "./src/**/*.{ts,tsx}",
581
- "./node_modules/@sincpro/mobile-ui/**/*.js",
582
- ],
918
+ content: ["./App.tsx", "./src/**/*.{ts,tsx}", "./node_modules/@sincpro/mobile-ui/**/*.js"],
583
919
  theme: {
584
920
  extend: {
585
921
  // Override font families to match loaded font names
586
922
  fontFamily: {
587
- light: ["Inter_300Light"],
588
- regular: ["Inter_400Regular"],
589
- medium: ["Inter_500Medium"],
590
- semibold: ["Inter_600SemiBold"],
923
+ light: ["Inter_300Light"],
924
+ regular: ["Inter_400Regular"],
925
+ medium: ["Inter_500Medium"],
926
+ semibold: ["Inter_600SemiBold"],
591
927
  extrabold: ["Inter_800ExtraBold"],
592
928
  },
593
929
  },
@@ -612,13 +948,13 @@ import "@sincpro/mobile-ui/theme/globals.css";
612
948
  Best tree-shaking; makes the component's category visible at the call site:
613
949
 
614
950
  ```tsx
615
- import { Display } from "@sincpro/mobile-ui/Display";
616
- import { Form } from "@sincpro/mobile-ui/Form";
617
- import { Feedback } from "@sincpro/mobile-ui/Feedback";
951
+ import { Display } from "@sincpro/mobile-ui/Display";
952
+ import { Form } from "@sincpro/mobile-ui/Form";
953
+ import { Feedback } from "@sincpro/mobile-ui/Feedback";
618
954
  import { Navigation } from "@sincpro/mobile-ui/Navigation";
619
- import { Dialog } from "@sincpro/mobile-ui/Dialog";
955
+ import { Dialog } from "@sincpro/mobile-ui/Dialog";
620
956
  import { Typography } from "@sincpro/mobile-ui/Typography";
621
- import { Actions } from "@sincpro/mobile-ui/Actions";
957
+ import { Actions } from "@sincpro/mobile-ui/Actions";
622
958
  ```
623
959
 
624
960
  ### Theme and tokens
@@ -634,18 +970,18 @@ For components outside a namespace:
634
970
 
635
971
  ```tsx
636
972
  import Sheet from "@sincpro/mobile-ui/Dialog/Dialog.Sheet";
637
- import { ConfirmationProvider } from "@sincpro/mobile-ui/Dialog";
638
- import { ToastProvider, useToast } from "@sincpro/mobile-ui/Feedback";
639
- import { Wizard, useWizard } from "@sincpro/mobile-ui/views/Wizard";
973
+ import { ConfirmationProvider } from "@sincpro/mobile-ui/Dialog";
974
+ import { ToastProvider, useToast } from "@sincpro/mobile-ui/Feedback";
975
+ import { Wizard, useWizard } from "@sincpro/mobile-ui/views/Wizard";
640
976
  ```
641
977
 
642
978
  ### Layout primitives
643
979
 
644
980
  ```tsx
645
- import { Box, Row, Stack, Spacer } from "@sincpro/mobile-ui/primitives";
646
- import Container from "@sincpro/mobile-ui/layouts/Container";
647
- import PlainLayout from "@sincpro/mobile-ui/layouts/PlainLayout";
648
- import TabNavigatorLayout from "@sincpro/mobile-ui/layouts/TabNavigatorLayout";
981
+ import { Box, Row, Stack, Spacer } from "@sincpro/mobile-ui/primitives";
982
+ import Container from "@sincpro/mobile-ui/layouts/Container";
983
+ import PlainLayout from "@sincpro/mobile-ui/layouts/PlainLayout";
984
+ import TabNavigatorLayout from "@sincpro/mobile-ui/layouts/TabNavigatorLayout";
649
985
  ```
650
986
 
651
987
  ---
@@ -661,26 +997,35 @@ make storybook-android # expo run:android
661
997
 
662
998
  Stories are organized into four groups:
663
999
 
664
- | Group | Contents |
665
- |-------|----------|
666
- | **Foundations** | Tokens, typography scale, color palette, motion |
667
- | **Components** | All compound component namespaces |
668
- | **Patterns** | Composed examples (list screen, form screen, auth flow) |
669
- | **Legacy** | Deprecated components kept for backwards compatibility |
1000
+ | Group | Contents |
1001
+ | --------------- | ------------------------------------------------------- |
1002
+ | **Foundations** | Tokens, typography scale, color palette, motion |
1003
+ | **Components** | All compound component namespaces |
1004
+ | **Patterns** | Composed examples (list screen, form screen, auth flow) |
1005
+ | **Legacy** | Deprecated components kept for backwards compatibility |
670
1006
 
671
1007
  Stories live in `.rnstorybook/stories/**/*.stories.tsx`. The Storybook harness is excluded from the published package (`files: ["dist", ...]`) and never lands in consumer bundles.
672
1008
 
1009
+ UX is a cross-cutting quality, not another catalog category. Component states live with
1010
+ their component (`Actions/Button`, `Data Display/CopyableText`, `Inputs/Select`, `Feedback`);
1011
+ task compositions live under named `Patterns/Forms`, `Patterns/Records`,
1012
+ `Patterns/Collections`, `Patterns/Views` and `Patterns/Profiles`.
1013
+ The former `Patterns/UX`, top-level `Views` and `Templates` story IDs changed;
1014
+ package exports did not. The taxonomy is regression-tested.
1015
+ Stories that own a full-screen scroll set `parameters.ownsScroll = true`; the canvas does
1016
+ not wrap them in a second vertical scroll. Other canvases use keyboard-aware scrolling.
1017
+
673
1018
  ---
674
1019
 
675
1020
  ## Development
676
1021
 
677
- | Command | What it does |
678
- |---------|-------------|
679
- | `make build` | `tsc` + `tsc-alias` → `dist/` (JS + type declarations) |
680
- | `make format` | Auto-fix: ESLint + Prettier + type-check |
681
- | `make verify-format` | CI gate — runs `format`, fails if any file changed |
682
- | `make storybook` | Start Expo dev server for Storybook |
683
- | `make publish` | Bump version + `npm publish` |
1022
+ | Command | What it does |
1023
+ | -------------------- | ------------------------------------------------------ |
1024
+ | `make build` | `tsc` + `tsc-alias` → `dist/` (JS + type declarations) |
1025
+ | `make format` | Auto-fix: ESLint + Prettier + type-check |
1026
+ | `make verify-format` | CI gate — runs `format`, fails if any file changed |
1027
+ | `make storybook` | Start Expo dev server for Storybook |
1028
+ | `make publish` | Bump version + `npm publish` |
684
1029
 
685
1030
  After building, copy the dist to consumers in the local monorepo (no symlinks setup):
686
1031