@ankhorage/surface 5.0.1 → 7.0.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 (319) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +1 -2
  3. package/dist/{layout → core/responsive}/Show.d.ts +2 -1
  4. package/dist/core/responsive/Show.d.ts.map +1 -0
  5. package/dist/{layout → core/responsive}/Show.js +3 -1
  6. package/dist/core/responsive/Show.js.map +1 -0
  7. package/dist/core/responsive/index.d.ts +1 -0
  8. package/dist/core/responsive/index.d.ts.map +1 -1
  9. package/dist/core/responsive/index.js +1 -0
  10. package/dist/core/responsive/index.js.map +1 -1
  11. package/dist/features/app-bar/adapters/inbound/AppBar.d.ts +5 -0
  12. package/dist/features/app-bar/adapters/inbound/AppBar.d.ts.map +1 -0
  13. package/dist/features/app-bar/adapters/inbound/AppBar.js +40 -0
  14. package/dist/features/app-bar/adapters/inbound/AppBar.js.map +1 -0
  15. package/dist/features/app-bar/public.d.ts +3 -0
  16. package/dist/features/app-bar/public.d.ts.map +1 -0
  17. package/dist/features/app-bar/public.js +2 -0
  18. package/dist/features/app-bar/public.js.map +1 -0
  19. package/dist/features/badge/adapters/inbound/Badge.js +3 -3
  20. package/dist/features/badge/adapters/inbound/Badge.js.map +1 -1
  21. package/dist/features/button/adapters/inbound/Button.js +8 -8
  22. package/dist/features/button/adapters/inbound/Button.js.map +1 -1
  23. package/dist/features/button/adapters/inbound/IconButton.js +3 -3
  24. package/dist/features/button/adapters/inbound/IconButton.js.map +1 -1
  25. package/dist/features/form/checkbox/adapters/inbound/Checkbox.js +7 -7
  26. package/dist/features/form/checkbox/adapters/inbound/Checkbox.js.map +1 -1
  27. package/dist/{components/field → features/form/field/adapters/inbound}/Field.d.ts +2 -1
  28. package/dist/features/form/field/adapters/inbound/Field.d.ts.map +1 -0
  29. package/dist/features/form/field/adapters/inbound/Field.js +40 -0
  30. package/dist/features/form/field/adapters/inbound/Field.js.map +1 -0
  31. package/dist/features/form/field/public.d.ts +3 -0
  32. package/dist/features/form/field/public.d.ts.map +1 -0
  33. package/dist/features/form/field/public.js +2 -0
  34. package/dist/features/form/field/public.js.map +1 -0
  35. package/dist/features/form/radio/adapters/inbound/Radio.js +8 -8
  36. package/dist/features/form/radio/adapters/inbound/Radio.js.map +1 -1
  37. package/dist/{components/switch → features/form/switch/adapters/inbound}/Switch.d.ts +2 -1
  38. package/dist/features/form/switch/adapters/inbound/Switch.d.ts.map +1 -0
  39. package/dist/features/form/switch/adapters/inbound/Switch.js +52 -0
  40. package/dist/features/form/switch/adapters/inbound/Switch.js.map +1 -0
  41. package/dist/features/form/switch/public.d.ts +3 -0
  42. package/dist/features/form/switch/public.d.ts.map +1 -0
  43. package/dist/features/form/switch/public.js +2 -0
  44. package/dist/features/form/switch/public.js.map +1 -0
  45. package/dist/features/form/text-input/adapters/inbound/TextInput.d.ts.map +1 -1
  46. package/dist/features/form/text-input/adapters/inbound/TextInput.js +8 -4
  47. package/dist/features/form/text-input/adapters/inbound/TextInput.js.map +1 -1
  48. package/dist/features/layout/adapters/inbound/Divider.js +2 -2
  49. package/dist/features/layout/adapters/inbound/Divider.js.map +1 -1
  50. package/dist/features/layout/adapters/inbound/Grid.d.ts.map +1 -1
  51. package/dist/features/layout/adapters/inbound/Grid.js +7 -9
  52. package/dist/features/layout/adapters/inbound/Grid.js.map +1 -1
  53. package/dist/features/layout/adapters/inbound/ScrollView.d.ts +5 -0
  54. package/dist/features/layout/adapters/inbound/ScrollView.d.ts.map +1 -0
  55. package/dist/features/layout/adapters/inbound/ScrollView.js +69 -0
  56. package/dist/features/layout/adapters/inbound/ScrollView.js.map +1 -0
  57. package/dist/features/layout/adapters/inbound/View.d.ts +5 -0
  58. package/dist/features/layout/adapters/inbound/View.d.ts.map +1 -0
  59. package/dist/features/layout/adapters/inbound/View.js +17 -0
  60. package/dist/features/layout/adapters/inbound/View.js.map +1 -0
  61. package/dist/features/layout/public.d.ts +3 -4
  62. package/dist/features/layout/public.d.ts.map +1 -1
  63. package/dist/features/layout/public.js +2 -3
  64. package/dist/features/layout/public.js.map +1 -1
  65. package/dist/features/list/adapters/inbound/List.d.ts +5 -0
  66. package/dist/features/list/adapters/inbound/List.d.ts.map +1 -0
  67. package/dist/features/list/adapters/inbound/List.js +7 -0
  68. package/dist/features/list/adapters/inbound/List.js.map +1 -0
  69. package/dist/features/list/adapters/inbound/ListItem.d.ts +5 -0
  70. package/dist/features/list/adapters/inbound/ListItem.d.ts.map +1 -0
  71. package/dist/features/list/adapters/inbound/ListItem.js +59 -0
  72. package/dist/features/list/adapters/inbound/ListItem.js.map +1 -0
  73. package/dist/features/list/public.d.ts +4 -0
  74. package/dist/features/list/public.d.ts.map +1 -0
  75. package/dist/features/list/public.js +3 -0
  76. package/dist/features/list/public.js.map +1 -0
  77. package/dist/features/modal/adapters/inbound/Modal.d.ts.map +1 -1
  78. package/dist/features/modal/adapters/inbound/Modal.js +8 -8
  79. package/dist/features/modal/adapters/inbound/Modal.js.map +1 -1
  80. package/dist/features/popover-menu/adapters/inbound/PopoverMenu.d.ts.map +1 -1
  81. package/dist/features/popover-menu/adapters/inbound/PopoverMenu.js +11 -12
  82. package/dist/features/popover-menu/adapters/inbound/PopoverMenu.js.map +1 -1
  83. package/dist/features/surface/adapters/inbound/Surface.d.ts +1 -1
  84. package/dist/features/surface/adapters/inbound/Surface.d.ts.map +1 -1
  85. package/dist/features/surface/adapters/inbound/Surface.js +3 -3
  86. package/dist/features/surface/adapters/inbound/Surface.js.map +1 -1
  87. package/dist/features/tabs/adapters/inbound/Tab.js +3 -3
  88. package/dist/features/tabs/adapters/inbound/Tab.js.map +1 -1
  89. package/dist/features/tabs/adapters/inbound/TabList.d.ts.map +1 -1
  90. package/dist/features/tabs/adapters/inbound/TabList.js +3 -5
  91. package/dist/features/tabs/adapters/inbound/TabList.js.map +1 -1
  92. package/dist/features/tabs/adapters/inbound/Tabs.js +2 -2
  93. package/dist/features/tabs/adapters/inbound/Tabs.js.map +1 -1
  94. package/dist/features/toast/adapters/inbound/Toast.js +5 -5
  95. package/dist/features/toast/adapters/inbound/Toast.js.map +1 -1
  96. package/dist/features/toast/adapters/inbound/ToastProvider.js +3 -3
  97. package/dist/features/toast/adapters/inbound/ToastProvider.js.map +1 -1
  98. package/dist/index.d.ts +10 -15
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +5 -8
  101. package/dist/index.js.map +1 -1
  102. package/dist/primitives/button-base/ButtonBase.d.ts +1 -0
  103. package/dist/primitives/button-base/ButtonBase.d.ts.map +1 -1
  104. package/dist/primitives/button-base/ButtonBase.js +6 -5
  105. package/dist/primitives/button-base/ButtonBase.js.map +1 -1
  106. package/dist/primitives/button-base/types.d.ts +2 -2
  107. package/dist/primitives/button-base/types.d.ts.map +1 -1
  108. package/dist/primitives/button-base/types.js.map +1 -1
  109. package/dist/types/app-bar.d.ts +12 -0
  110. package/dist/types/app-bar.d.ts.map +1 -0
  111. package/dist/types/app-bar.js +2 -0
  112. package/dist/types/app-bar.js.map +1 -0
  113. package/dist/{components/field/types.d.ts → types/field.d.ts} +1 -1
  114. package/dist/types/field.d.ts.map +1 -0
  115. package/dist/types/field.js +2 -0
  116. package/dist/types/field.js.map +1 -0
  117. package/dist/types/layout.d.ts +15 -17
  118. package/dist/types/layout.d.ts.map +1 -1
  119. package/dist/types/layout.js.map +1 -1
  120. package/dist/types/list.d.ts +20 -0
  121. package/dist/types/list.d.ts.map +1 -0
  122. package/dist/types/list.js +2 -0
  123. package/dist/types/list.js.map +1 -0
  124. package/dist/types/surface.d.ts +2 -2
  125. package/dist/types/surface.d.ts.map +1 -1
  126. package/dist/types/surface.js.map +1 -1
  127. package/dist/{components/switch/types.d.ts → types/switch.d.ts} +4 -4
  128. package/dist/types/switch.d.ts.map +1 -0
  129. package/dist/types/switch.js +2 -0
  130. package/dist/types/switch.js.map +1 -0
  131. package/dist/utils/resolveViewStyles.d.ts +7 -0
  132. package/dist/utils/resolveViewStyles.d.ts.map +1 -0
  133. package/dist/utils/{resolveBoxStyles.js → resolveViewStyles.js} +11 -4
  134. package/dist/utils/resolveViewStyles.js.map +1 -0
  135. package/package.json +1 -1
  136. package/src/{layout → core/responsive}/Show.tsx +4 -1
  137. package/src/core/responsive/index.ts +1 -0
  138. package/src/features/app-bar/adapters/inbound/AppBar.tsx +69 -0
  139. package/src/features/app-bar/public.ts +2 -0
  140. package/src/features/badge/adapters/inbound/Badge.tsx +3 -3
  141. package/src/features/button/adapters/inbound/Button.tsx +8 -8
  142. package/src/features/button/adapters/inbound/IconButton.tsx +3 -3
  143. package/src/features/form/checkbox/adapters/inbound/Checkbox.tsx +7 -7
  144. package/src/features/form/field/adapters/inbound/Field.tsx +82 -0
  145. package/src/features/form/field/public.ts +2 -0
  146. package/src/features/form/radio/adapters/inbound/Radio.tsx +8 -8
  147. package/src/features/form/switch/adapters/inbound/Switch.tsx +123 -0
  148. package/src/features/form/switch/public.ts +2 -0
  149. package/src/features/form/text-input/adapters/inbound/TextInput.tsx +21 -5
  150. package/src/features/layout/adapters/inbound/Divider.tsx +2 -2
  151. package/src/features/layout/adapters/inbound/Grid.tsx +12 -14
  152. package/src/features/layout/adapters/inbound/ScrollView.tsx +102 -0
  153. package/src/features/layout/adapters/inbound/{Box.tsx → View.tsx} +9 -9
  154. package/src/features/layout/public.ts +3 -10
  155. package/src/features/list/adapters/inbound/List.tsx +9 -0
  156. package/src/features/list/adapters/inbound/ListItem.tsx +128 -0
  157. package/src/features/list/public.test.ts +13 -0
  158. package/src/features/list/public.ts +3 -0
  159. package/src/features/modal/adapters/inbound/Modal.tsx +11 -8
  160. package/src/features/popover-menu/adapters/inbound/PopoverMenu.tsx +11 -14
  161. package/src/features/surface/adapters/inbound/Surface.tsx +3 -3
  162. package/src/features/tabs/adapters/inbound/Tab.tsx +3 -3
  163. package/src/features/tabs/adapters/inbound/TabList.tsx +3 -6
  164. package/src/features/tabs/adapters/inbound/Tabs.tsx +2 -2
  165. package/src/features/toast/adapters/inbound/Toast.tsx +5 -5
  166. package/src/features/toast/adapters/inbound/ToastProvider.tsx +3 -3
  167. package/src/index.test.ts +26 -48
  168. package/src/index.ts +10 -21
  169. package/src/primitives/button-base/ButtonBase.tsx +6 -8
  170. package/src/primitives/button-base/types.ts +2 -2
  171. package/src/types/app-bar.ts +13 -0
  172. package/src/types/layout.ts +25 -20
  173. package/src/types/list.ts +22 -0
  174. package/src/types/surface.ts +2 -2
  175. package/src/{components/switch/types.ts → types/switch.ts} +3 -3
  176. package/src/utils/resolveViewStyles.test.ts +71 -0
  177. package/src/utils/{resolveBoxStyles.ts → resolveViewStyles.ts} +16 -9
  178. package/src/webAcceptance.test.tsx +8 -9
  179. package/dist/components/field/Field.d.ts.map +0 -1
  180. package/dist/components/field/Field.js +0 -26
  181. package/dist/components/field/Field.js.map +0 -1
  182. package/dist/components/field/index.d.ts +0 -3
  183. package/dist/components/field/index.d.ts.map +0 -1
  184. package/dist/components/field/index.js +0 -2
  185. package/dist/components/field/index.js.map +0 -1
  186. package/dist/components/field/types.d.ts.map +0 -1
  187. package/dist/components/field/types.js +0 -2
  188. package/dist/components/field/types.js.map +0 -1
  189. package/dist/components/helper-text/HelperText.d.ts +0 -4
  190. package/dist/components/helper-text/HelperText.d.ts.map +0 -1
  191. package/dist/components/helper-text/HelperText.js +0 -8
  192. package/dist/components/helper-text/HelperText.js.map +0 -1
  193. package/dist/components/helper-text/index.d.ts +0 -3
  194. package/dist/components/helper-text/index.d.ts.map +0 -1
  195. package/dist/components/helper-text/index.js +0 -2
  196. package/dist/components/helper-text/index.js.map +0 -1
  197. package/dist/components/helper-text/types.d.ts +0 -9
  198. package/dist/components/helper-text/types.d.ts.map +0 -1
  199. package/dist/components/helper-text/types.js +0 -2
  200. package/dist/components/helper-text/types.js.map +0 -1
  201. package/dist/components/label/Label.d.ts +0 -4
  202. package/dist/components/label/Label.d.ts.map +0 -1
  203. package/dist/components/label/Label.js +0 -11
  204. package/dist/components/label/Label.js.map +0 -1
  205. package/dist/components/label/index.d.ts +0 -3
  206. package/dist/components/label/index.d.ts.map +0 -1
  207. package/dist/components/label/index.js +0 -2
  208. package/dist/components/label/index.js.map +0 -1
  209. package/dist/components/label/types.d.ts +0 -10
  210. package/dist/components/label/types.d.ts.map +0 -1
  211. package/dist/components/label/types.js +0 -2
  212. package/dist/components/label/types.js.map +0 -1
  213. package/dist/components/list-item/ListItem.d.ts +0 -4
  214. package/dist/components/list-item/ListItem.d.ts.map +0 -1
  215. package/dist/components/list-item/ListItem.js +0 -43
  216. package/dist/components/list-item/ListItem.js.map +0 -1
  217. package/dist/components/list-item/index.d.ts +0 -3
  218. package/dist/components/list-item/index.d.ts.map +0 -1
  219. package/dist/components/list-item/index.js +0 -2
  220. package/dist/components/list-item/index.js.map +0 -1
  221. package/dist/components/list-item/types.d.ts +0 -11
  222. package/dist/components/list-item/types.d.ts.map +0 -1
  223. package/dist/components/list-item/types.js +0 -2
  224. package/dist/components/list-item/types.js.map +0 -1
  225. package/dist/components/switch/Switch.d.ts.map +0 -1
  226. package/dist/components/switch/Switch.js +0 -71
  227. package/dist/components/switch/Switch.js.map +0 -1
  228. package/dist/components/switch/index.d.ts +0 -3
  229. package/dist/components/switch/index.d.ts.map +0 -1
  230. package/dist/components/switch/index.js +0 -2
  231. package/dist/components/switch/index.js.map +0 -1
  232. package/dist/components/switch/types.d.ts.map +0 -1
  233. package/dist/components/switch/types.js +0 -2
  234. package/dist/components/switch/types.js.map +0 -1
  235. package/dist/components/textarea/Textarea.d.ts +0 -4
  236. package/dist/components/textarea/Textarea.d.ts.map +0 -1
  237. package/dist/components/textarea/Textarea.js +0 -6
  238. package/dist/components/textarea/Textarea.js.map +0 -1
  239. package/dist/components/textarea/index.d.ts +0 -3
  240. package/dist/components/textarea/index.d.ts.map +0 -1
  241. package/dist/components/textarea/index.js +0 -2
  242. package/dist/components/textarea/index.js.map +0 -1
  243. package/dist/components/textarea/types.d.ts +0 -5
  244. package/dist/components/textarea/types.d.ts.map +0 -1
  245. package/dist/components/textarea/types.js +0 -2
  246. package/dist/components/textarea/types.js.map +0 -1
  247. package/dist/features/layout/adapters/inbound/Box.d.ts +0 -5
  248. package/dist/features/layout/adapters/inbound/Box.d.ts.map +0 -1
  249. package/dist/features/layout/adapters/inbound/Box.js +0 -17
  250. package/dist/features/layout/adapters/inbound/Box.js.map +0 -1
  251. package/dist/features/layout/adapters/inbound/Container.d.ts +0 -5
  252. package/dist/features/layout/adapters/inbound/Container.d.ts.map +0 -1
  253. package/dist/features/layout/adapters/inbound/Container.js +0 -28
  254. package/dist/features/layout/adapters/inbound/Container.js.map +0 -1
  255. package/dist/features/layout/adapters/inbound/Stack.d.ts +0 -5
  256. package/dist/features/layout/adapters/inbound/Stack.d.ts.map +0 -1
  257. package/dist/features/layout/adapters/inbound/Stack.js +0 -27
  258. package/dist/features/layout/adapters/inbound/Stack.js.map +0 -1
  259. package/dist/layout/AppBar.d.ts +0 -13
  260. package/dist/layout/AppBar.d.ts.map +0 -1
  261. package/dist/layout/AppBar.js +0 -30
  262. package/dist/layout/AppBar.js.map +0 -1
  263. package/dist/layout/Center.d.ts +0 -7
  264. package/dist/layout/Center.d.ts.map +0 -1
  265. package/dist/layout/Center.js +0 -12
  266. package/dist/layout/Center.js.map +0 -1
  267. package/dist/layout/Inline.d.ts +0 -5
  268. package/dist/layout/Inline.d.ts.map +0 -1
  269. package/dist/layout/Inline.js +0 -6
  270. package/dist/layout/Inline.js.map +0 -1
  271. package/dist/layout/ScrollArea.d.ts +0 -9
  272. package/dist/layout/ScrollArea.d.ts.map +0 -1
  273. package/dist/layout/ScrollArea.js +0 -52
  274. package/dist/layout/ScrollArea.js.map +0 -1
  275. package/dist/layout/Show.d.ts.map +0 -1
  276. package/dist/layout/Show.js.map +0 -1
  277. package/dist/layout/Spacer.d.ts +0 -9
  278. package/dist/layout/Spacer.d.ts.map +0 -1
  279. package/dist/layout/Spacer.js +0 -12
  280. package/dist/layout/Spacer.js.map +0 -1
  281. package/dist/layout/Template.d.ts +0 -18
  282. package/dist/layout/Template.d.ts.map +0 -1
  283. package/dist/layout/Template.js +0 -36
  284. package/dist/layout/Template.js.map +0 -1
  285. package/dist/layout/index.d.ts +0 -15
  286. package/dist/layout/index.d.ts.map +0 -1
  287. package/dist/layout/index.js +0 -8
  288. package/dist/layout/index.js.map +0 -1
  289. package/dist/utils/resolveBoxStyles.d.ts +0 -7
  290. package/dist/utils/resolveBoxStyles.d.ts.map +0 -1
  291. package/dist/utils/resolveBoxStyles.js.map +0 -1
  292. package/src/components/field/Field.tsx +0 -51
  293. package/src/components/field/index.ts +0 -2
  294. package/src/components/helper-text/HelperText.tsx +0 -12
  295. package/src/components/helper-text/index.ts +0 -2
  296. package/src/components/helper-text/types.ts +0 -10
  297. package/src/components/label/Label.tsx +0 -23
  298. package/src/components/label/index.ts +0 -2
  299. package/src/components/label/types.ts +0 -11
  300. package/src/components/list-item/ListItem.tsx +0 -72
  301. package/src/components/list-item/index.ts +0 -2
  302. package/src/components/list-item/types.ts +0 -11
  303. package/src/components/switch/Switch.tsx +0 -118
  304. package/src/components/switch/index.ts +0 -2
  305. package/src/components/textarea/Textarea.tsx +0 -15
  306. package/src/components/textarea/index.ts +0 -2
  307. package/src/components/textarea/types.ts +0 -5
  308. package/src/features/layout/adapters/inbound/Container.tsx +0 -43
  309. package/src/features/layout/adapters/inbound/Stack.test.ts +0 -13
  310. package/src/features/layout/adapters/inbound/Stack.tsx +0 -44
  311. package/src/layout/AppBar.tsx +0 -60
  312. package/src/layout/Center.tsx +0 -22
  313. package/src/layout/Inline.tsx +0 -9
  314. package/src/layout/ScrollArea.tsx +0 -116
  315. package/src/layout/Spacer.tsx +0 -22
  316. package/src/layout/Template.tsx +0 -86
  317. package/src/layout/index.ts +0 -14
  318. package/src/utils/resolveBoxStyles.test.ts +0 -54
  319. /package/src/{components/field/types.ts → types/field.ts} +0 -0
@@ -0,0 +1,102 @@
1
+ import React from 'react';
2
+ import { ScrollView as ReactNativeScrollView } from 'react-native';
3
+
4
+ import { useResponsiveRuntime } from '../../../../core/responsive';
5
+ import { useTheme } from '../../../../theme/ThemeContext';
6
+ import type { ScrollViewProps } from '../../../../types/layout';
7
+ import { resolveViewStyles } from '../../../../utils/resolveViewStyles';
8
+
9
+ /*** Renders the token-aware responsive Surface adapter for React Native ScrollView. */
10
+ export function ScrollView(props: ScrollViewProps) {
11
+ const { theme } = useTheme();
12
+ const { breakpoint } = useResponsiveRuntime();
13
+ const spacing = splitSpacingProps(props);
14
+ const visual = splitVisualProps(spacing.rest);
15
+ const dimensions = splitDimensionProps(visual.rest);
16
+ const layout = splitLayoutProps(dimensions.rest);
17
+ const { children, contentContainerStyle, style, ...scrollProps } = layout.rest;
18
+ const resolved = resolveViewStyles(theme, breakpoint, {
19
+ ...spacing.styleProps,
20
+ ...visual.styleProps,
21
+ ...dimensions.styleProps,
22
+ ...layout.styleProps,
23
+ });
24
+
25
+ return (
26
+ <ReactNativeScrollView
27
+ {...scrollProps}
28
+ contentContainerStyle={contentContainerStyle}
29
+ style={[resolved, style]}
30
+ >
31
+ {children}
32
+ </ReactNativeScrollView>
33
+ );
34
+ }
35
+
36
+ /*** Splits spacing-aware Surface props from native ScrollView props. */
37
+ function splitSpacingProps(props: ScrollViewProps) {
38
+ const { p, px, py, pt, pb, pl, pr, m, mx, my, mt, mb, ml, mr, gap, rowGap, columnGap, ...rest } =
39
+ props;
40
+ return {
41
+ rest,
42
+ styleProps: { p, px, py, pt, pb, pl, pr, m, mx, my, mt, mb, ml, mr, gap, rowGap, columnGap },
43
+ };
44
+ }
45
+
46
+ /*** Splits token-aware visual Surface props from native ScrollView props. */
47
+ function splitVisualProps(props: ReturnType<typeof splitSpacingProps>['rest']) {
48
+ const { bg, radius, borderWidth, borderColor, ...rest } = props;
49
+ return { rest, styleProps: { bg, radius, borderWidth, borderColor } };
50
+ }
51
+
52
+ /*** Splits responsive dimension Surface props from native ScrollView props. */
53
+ function splitDimensionProps(props: ReturnType<typeof splitVisualProps>['rest']) {
54
+ const { width, height, minWidth, maxWidth, minHeight, maxHeight, ...rest } = props;
55
+ return { rest, styleProps: { width, height, minWidth, maxWidth, minHeight, maxHeight } };
56
+ }
57
+
58
+ /*** Splits responsive flex and positioning Surface props from native ScrollView props. */
59
+ function splitLayoutProps(props: ReturnType<typeof splitDimensionProps>['rest']) {
60
+ const {
61
+ flex,
62
+ flexGrow,
63
+ flexShrink,
64
+ flexBasis,
65
+ direction,
66
+ align,
67
+ justify,
68
+ wrap,
69
+ alignSelf,
70
+ position,
71
+ top,
72
+ bottom,
73
+ left,
74
+ right,
75
+ overflow,
76
+ zIndex,
77
+ opacity,
78
+ ...rest
79
+ } = props;
80
+ return {
81
+ rest,
82
+ styleProps: {
83
+ flex,
84
+ flexGrow,
85
+ flexShrink,
86
+ flexBasis,
87
+ direction,
88
+ align,
89
+ justify,
90
+ wrap,
91
+ alignSelf,
92
+ position,
93
+ top,
94
+ bottom,
95
+ left,
96
+ right,
97
+ overflow,
98
+ zIndex,
99
+ opacity,
100
+ },
101
+ };
102
+ }
@@ -1,14 +1,14 @@
1
1
  import React from 'react';
2
- import { View } from 'react-native';
2
+ import { View as ReactNativeView } from 'react-native';
3
3
 
4
4
  import { useResponsiveRuntime } from '../../../../core/responsive';
5
5
  import { resolvePointerEvents } from '../../../../internal/resolvePointerEvents';
6
6
  import { useTheme } from '../../../../theme/ThemeContext';
7
- import type { BoxProps } from '../../../../types/layout';
8
- import { resolveBoxStyles } from '../../../../utils/resolveBoxStyles';
7
+ import type { ViewProps } from '../../../../types/layout';
8
+ import { resolveViewStyles } from '../../../../utils/resolveViewStyles';
9
9
 
10
- /*** Renders the responsive foundational layout box. */
11
- export function Box({
10
+ /*** Renders the token-aware responsive Surface adapter for React Native View. */
11
+ export function View({
12
12
  accessible,
13
13
  accessibilityLabel,
14
14
  accessibilityRole,
@@ -18,14 +18,14 @@ export function Box({
18
18
  style,
19
19
  testID,
20
20
  ...props
21
- }: BoxProps) {
21
+ }: ViewProps) {
22
22
  const { theme } = useTheme();
23
23
  const { breakpoint } = useResponsiveRuntime();
24
- const resolved = resolveBoxStyles(theme, breakpoint, props);
24
+ const resolved = resolveViewStyles(theme, breakpoint, props);
25
25
  const resolvedPointerEvents = pointerEvents ? resolvePointerEvents(pointerEvents) : null;
26
26
 
27
27
  return (
28
- <View
28
+ <ReactNativeView
29
29
  {...resolvedPointerEvents?.props}
30
30
  accessible={accessible}
31
31
  accessibilityLabel={accessibilityLabel}
@@ -35,6 +35,6 @@ export function Box({
35
35
  style={[resolved, resolvedPointerEvents?.style, style]}
36
36
  >
37
37
  {children}
38
- </View>
38
+ </ReactNativeView>
39
39
  );
40
40
  }
@@ -1,12 +1,5 @@
1
- export type {
2
- BoxProps,
3
- ContainerProps,
4
- DividerProps,
5
- GridProps,
6
- StackProps,
7
- } from '../../types/layout';
8
- export { Box } from './adapters/inbound/Box';
9
- export { Container } from './adapters/inbound/Container';
1
+ export type { DividerProps, GridProps, ScrollViewProps, ViewProps } from '../../types/layout';
10
2
  export { Divider } from './adapters/inbound/Divider';
11
3
  export { Grid } from './adapters/inbound/Grid';
12
- export { Stack } from './adapters/inbound/Stack';
4
+ export { ScrollView } from './adapters/inbound/ScrollView';
5
+ export { View } from './adapters/inbound/View';
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+
3
+ import type { ListProps } from '../../../../types/list';
4
+ import { View } from '../../../layout/public';
5
+
6
+ /*** Groups list items under one neutral Surface list boundary. */
7
+ export function List({ children, testID }: ListProps) {
8
+ return <View testID={testID}>{children}</View>;
9
+ }
@@ -0,0 +1,128 @@
1
+ import React from 'react';
2
+
3
+ import { ButtonBase } from '../../../../primitives/button-base';
4
+ import { useTheme } from '../../../../theme/ThemeContext';
5
+ import type { SurfaceTheme } from '../../../../theme/types';
6
+ import type { ListItemProps } from '../../../../types/list';
7
+ import { View } from '../../../layout/public';
8
+ import { Text } from '../../../typography/public';
9
+
10
+ /*** Renders a static or interactive list item with shared row geometry and interaction states. */
11
+ export function ListItem(props: ListItemProps) {
12
+ const { theme } = useTheme();
13
+ if (!props.onPress) return renderStaticListItem(props, theme);
14
+ return renderInteractiveListItem({ ...props, onPress: props.onPress }, theme);
15
+ }
16
+
17
+ /*** Renders a non-pressable list item. */
18
+ function renderStaticListItem(props: ListItemProps, theme: SurfaceTheme) {
19
+ return (
20
+ <ListItemContent
21
+ {...props}
22
+ backgroundColor={props.selected ? theme.semantics.selection.background : 'transparent'}
23
+ />
24
+ );
25
+ }
26
+
27
+ /*** Renders a pressable list item with shared interaction-state presentation. */
28
+ function renderInteractiveListItem(
29
+ props: ListItemProps & { onPress: NonNullable<ListItemProps['onPress']> },
30
+ theme: SurfaceTheme,
31
+ ) {
32
+ return (
33
+ <ButtonBase
34
+ accessibilityLabel={props.accessibilityLabel}
35
+ accessibilityRole="button"
36
+ accessibilityState={{ disabled: props.disabled ?? false, selected: props.selected ?? false }}
37
+ disabled={props.disabled ?? false}
38
+ interactionPolicy={props.interactionPolicy}
39
+ onPress={props.onPress}
40
+ testID={props.testID}
41
+ >
42
+ {(state) => (
43
+ <ListItemContent
44
+ {...props}
45
+ backgroundColor={resolveListItemBackground(theme, {
46
+ hovered: state.hovered,
47
+ pressed: state.pressed,
48
+ selected: props.selected ?? false,
49
+ })}
50
+ disabled={state.disabled}
51
+ testID={undefined}
52
+ />
53
+ )}
54
+ </ButtonBase>
55
+ );
56
+ }
57
+
58
+ interface ListItemBackgroundState {
59
+ hovered: boolean;
60
+ pressed: boolean;
61
+ selected: boolean;
62
+ }
63
+
64
+ type ListItemContentProps = Omit<
65
+ ListItemProps,
66
+ 'accessibilityLabel' | 'interactionPolicy' | 'onPress' | 'selected'
67
+ > & {
68
+ backgroundColor: string;
69
+ };
70
+
71
+ /*** Resolves the neutral list-item background for one interaction state. */
72
+ function resolveListItemBackground(theme: SurfaceTheme, state: ListItemBackgroundState) {
73
+ if (state.pressed) return theme.semantics.neutral.surfaceActive;
74
+ if (state.hovered) return theme.semantics.neutral.surfaceHover;
75
+ if (state.selected) return theme.semantics.selection.background;
76
+ return 'transparent';
77
+ }
78
+
79
+ /*** Renders the shared visual row content for static and interactive list items. */
80
+ function ListItemContent({
81
+ backgroundColor,
82
+ children,
83
+ compact = false,
84
+ description,
85
+ disabled = false,
86
+ leading,
87
+ testID,
88
+ title,
89
+ trailing,
90
+ }: ListItemContentProps) {
91
+ const content = children ?? renderDefaultContent(title, description);
92
+
93
+ return (
94
+ <View
95
+ align="center"
96
+ bg={backgroundColor}
97
+ direction="row"
98
+ gap="m"
99
+ opacity={disabled ? 0.72 : 1}
100
+ px="m"
101
+ py={compact ? 's' : 'm'}
102
+ testID={testID}
103
+ >
104
+ {leading !== undefined ? <View>{leading}</View> : null}
105
+ <View flex={1}>{content}</View>
106
+ {trailing !== undefined ? <View>{trailing}</View> : null}
107
+ </View>
108
+ );
109
+ }
110
+
111
+ /*** Renders the default title and description content when custom children are absent. */
112
+ function renderDefaultContent(title: React.ReactNode, description: React.ReactNode) {
113
+ if (title === undefined && description === undefined) return null;
114
+ return (
115
+ <View flex={1} gap="xs">
116
+ {title !== undefined ? (
117
+ <Text numberOfLines={1} variant="body" weight="medium">
118
+ {title}
119
+ </Text>
120
+ ) : null}
121
+ {description !== undefined ? (
122
+ <Text emphasis="muted" numberOfLines={2} variant="bodySmall">
123
+ {description}
124
+ </Text>
125
+ ) : null}
126
+ </View>
127
+ );
128
+ }
@@ -0,0 +1,13 @@
1
+ import { expect, test } from 'bun:test';
2
+
3
+ test('list capability owns List and ListItem under one feature boundary', async () => {
4
+ const listSource = await Bun.file('src/features/list/adapters/inbound/List.tsx').text();
5
+ const listItemSource = await Bun.file('src/features/list/adapters/inbound/ListItem.tsx').text();
6
+
7
+ expect(listSource).toContain('export function List');
8
+ expect(listItemSource).toContain('export function ListItem');
9
+ expect(listItemSource).toContain('interactionPolicy={props.interactionPolicy}');
10
+ expect(listItemSource).toContain('selected');
11
+ expect(listItemSource).toContain('compact');
12
+ expect(listItemSource).not.toContain('components/list-item');
13
+ });
@@ -0,0 +1,3 @@
1
+ export type { ListItemProps, ListProps } from '../../types/list';
2
+ export { List } from './adapters/inbound/List';
3
+ export { ListItem } from './adapters/inbound/ListItem';
@@ -1,13 +1,13 @@
1
1
  import React from 'react';
2
- import { Pressable, StyleSheet, View, type ViewStyle } from 'react-native';
2
+ import { Pressable, StyleSheet, View as ReactNativeView, type ViewStyle } from 'react-native';
3
3
 
4
4
  import { FocusScope } from '../../../../internal/focus/FocusScope';
5
5
  import { Portal } from '../../../../internal/overlay/Portal';
6
6
  import { resolvePointerEvents } from '../../../../internal/resolvePointerEvents';
7
7
  import { resolveOverlayAnimation } from '../../../../internal/resolvers';
8
- import { Center } from '../../../../layout';
9
8
  import { useTheme } from '../../../../theme/ThemeContext';
10
9
  import type { ModalProps } from '../../../../types/modal';
10
+ import { View } from '../../../layout/public';
11
11
  import { Surface } from '../../../surface/public';
12
12
 
13
13
  const boxNonePointerEvents = resolvePointerEvents('box-none');
@@ -30,7 +30,10 @@ export function Modal({
30
30
 
31
31
  return (
32
32
  <Portal layer="modal" visible={visible}>
33
- <View {...boxNonePointerEvents.props} style={[boxNonePointerEvents.style, styles.fill]}>
33
+ <ReactNativeView
34
+ {...boxNonePointerEvents.props}
35
+ style={[boxNonePointerEvents.style, styles.fill]}
36
+ >
34
37
  <Pressable
35
38
  onPress={backdropPress}
36
39
  style={[
@@ -44,15 +47,15 @@ export function Modal({
44
47
  onEscape={passive ? undefined : onDismiss}
45
48
  testID={testID ? `${testID}-focus` : undefined}
46
49
  >
47
- <Center p="l" style={styles.center}>
48
- <View accessible accessibilityViewIsModal style={styles.content}>
50
+ <View align="center" justify="center" p="l" style={styles.center}>
51
+ <ReactNativeView accessible accessibilityViewIsModal style={styles.content}>
49
52
  <Surface p="l" style={styles.surface} testID={testID} variant="raised">
50
53
  {children}
51
54
  </Surface>
52
- </View>
53
- </Center>
55
+ </ReactNativeView>
56
+ </View>
54
57
  </FocusScope>
55
- </View>
58
+ </ReactNativeView>
56
59
  </Portal>
57
60
  );
58
61
  }
@@ -3,10 +3,9 @@ import { Pressable } from 'react-native';
3
3
 
4
4
  import { FocusScope } from '../../../../internal/focus/FocusScope';
5
5
  import { useFocusManager } from '../../../../internal/focus/useFocusManager';
6
- import { Inline } from '../../../../layout';
7
6
  import { useTheme } from '../../../../theme/ThemeContext';
8
7
  import type { PopoverMenuAction, PopoverMenuProps } from '../../../../types/popoverMenu';
9
- import { Box, Stack } from '../../../layout/public';
8
+ import { View } from '../../../layout/public';
10
9
  import { Popover } from '../../../popover/public';
11
10
  import { Surface } from '../../../surface/public';
12
11
  import { Text } from '../../../typography/public';
@@ -103,10 +102,8 @@ function usePopoverMenuKeyboard({
103
102
  () =>
104
103
  bindKeydown((event) => {
105
104
  if (passive) return;
106
-
107
105
  const { key } = event;
108
106
  if (key === undefined) return;
109
-
110
107
  if (['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(key)) {
111
108
  event.preventDefault();
112
109
  setActiveIndex((current) => resolveNextMenuIndex(actions, current, key));
@@ -152,7 +149,7 @@ function PopoverMenuItem({
152
149
  onPress={passive ? undefined : () => activateAction(action)}
153
150
  testID={testID ? `${testID}-item-${action.id}` : undefined}
154
151
  >
155
- <Box
152
+ <View
156
153
  bg={selected ? theme.semantics.action.neutral.softBg : 'transparent'}
157
154
  opacity={action.disabled ? 0.56 : 1}
158
155
  px="m"
@@ -160,7 +157,7 @@ function PopoverMenuItem({
160
157
  radius="s"
161
158
  >
162
159
  <PopoverMenuItemContent action={action} active={active} />
163
- </Box>
160
+ </View>
164
161
  </Pressable>
165
162
  );
166
163
  }
@@ -177,10 +174,10 @@ function PopoverMenuItemContent({
177
174
  action.intent === 'danger' ? 'danger' : active || action.selected ? 'neutral' : undefined;
178
175
 
179
176
  return (
180
- <Inline align="center" gap="s" justify="space-between" wrap="nowrap">
181
- {action.leading ? <Box>{action.leading}</Box> : null}
182
- <Box flex={1}>
183
- <Stack gap="xxs">
177
+ <View align="center" direction="row" gap="s" justify="space-between" wrap="nowrap">
178
+ {action.leading ? <View>{action.leading}</View> : null}
179
+ <View flex={1}>
180
+ <View gap="xxs">
184
181
  <Text
185
182
  color={titleColor}
186
183
  variant="bodySmall"
@@ -193,9 +190,9 @@ function PopoverMenuItemContent({
193
190
  {action.description}
194
191
  </Text>
195
192
  ) : null}
196
- </Stack>
197
- </Box>
198
- {action.trailing ? <Box>{action.trailing}</Box> : null}
199
- </Inline>
193
+ </View>
194
+ </View>
195
+ {action.trailing ? <View>{action.trailing}</View> : null}
196
+ </View>
200
197
  );
201
198
  }
@@ -3,9 +3,9 @@ import type { ViewStyle } from 'react-native';
3
3
 
4
4
  import { useTheme } from '../../../../theme/ThemeContext';
5
5
  import type { SurfaceProps, SurfaceVariant } from '../../../../types/surface';
6
- import { Box } from '../../../layout/public';
6
+ import { View } from '../../../layout/public';
7
7
 
8
- /*** Renders a themed container surface with semantic elevation and border variants. */
8
+ /*** Renders a themed content surface with semantic elevation and border variants. */
9
9
  export function Surface({ variant = 'default', radius = 'm', style, ...props }: SurfaceProps) {
10
10
  const { theme } = useTheme();
11
11
  const backgroundColor =
@@ -17,7 +17,7 @@ export function Surface({ variant = 'default', radius = 'm', style, ...props }:
17
17
  const borderColor = theme.semantics.border.default;
18
18
 
19
19
  return (
20
- <Box
20
+ <View
21
21
  {...props}
22
22
  radius={radius}
23
23
  style={[resolveSurfaceVariantStyles(variant, borderColor, backgroundColor), style]}
@@ -3,7 +3,7 @@ import { Pressable, type ViewStyle } from 'react-native';
3
3
 
4
4
  import { useTheme } from '../../../../theme/ThemeContext';
5
5
  import type { TabProps } from '../../../../types/tabs';
6
- import { Box } from '../../../layout/public';
6
+ import { View } from '../../../layout/public';
7
7
  import { Text } from '../../../typography/public';
8
8
  import { useTabRegistration } from '../../composition/useTabRegistration';
9
9
  import { useTabsContext } from '../../composition/useTabsContext';
@@ -37,7 +37,7 @@ export function Tab({
37
37
  ref={pressableRef}
38
38
  testID={testID}
39
39
  >
40
- <Box
40
+ <View
41
41
  px="m"
42
42
  py="s"
43
43
  style={resolveTabStyle({
@@ -50,7 +50,7 @@ export function Tab({
50
50
  <Text color={selected ? 'primary' : undefined} variant="label" weight="medium">
51
51
  {children}
52
52
  </Text>
53
- </Box>
53
+ </View>
54
54
  </Pressable>
55
55
  );
56
56
  }
@@ -1,9 +1,8 @@
1
1
  import React from 'react';
2
- import { StyleSheet } from 'react-native';
3
2
 
4
3
  import { useFocusManager } from '../../../../internal/focus/useFocusManager';
5
4
  import type { TabListProps, TabNavigationKey } from '../../../../types/tabs';
6
- import { Box } from '../../../layout/public';
5
+ import { View } from '../../../layout/public';
7
6
  import { useTabsContext } from '../../composition/useTabsContext';
8
7
  import { resolveNextTabValue } from '../../utils/resolveNextTabValue';
9
8
 
@@ -36,9 +35,9 @@ export function TabList({ children, testID }: TabListProps) {
36
35
  }, [bindKeydown, focusedValue, setActiveValue, tabs]);
37
36
 
38
37
  return (
39
- <Box accessibilityRole="tablist" style={styles.list} testID={testID}>
38
+ <View accessibilityRole="tablist" direction="row" testID={testID}>
40
39
  {children}
41
- </Box>
40
+ </View>
42
41
  );
43
42
  }
44
43
 
@@ -46,5 +45,3 @@ export function TabList({ children, testID }: TabListProps) {
46
45
  function isTabNavigationKey(key: string | undefined): key is TabNavigationKey {
47
46
  return key !== undefined && navigationKeys.includes(key);
48
47
  }
49
-
50
- const styles = StyleSheet.create({ list: { flexDirection: 'row' } });
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
 
3
3
  import type { TabsProps } from '../../../../types/tabs';
4
- import { Box } from '../../../layout/public';
4
+ import { View } from '../../../layout/public';
5
5
  import { TabsContext } from '../../composition/TabsContext';
6
6
  import { useTabsController } from '../../composition/useTabsController';
7
7
 
@@ -11,7 +11,7 @@ export function Tabs({ children, ...props }: TabsProps) {
11
11
 
12
12
  return (
13
13
  <TabsContext value={contextValue}>
14
- <Box testID={props.testID}>{children}</Box>
14
+ <View testID={props.testID}>{children}</View>
15
15
  </TabsContext>
16
16
  );
17
17
  }
@@ -5,7 +5,7 @@ import type { SurfaceColor } from '../../../../surfaceColor';
5
5
  import { useTheme } from '../../../../theme/ThemeContext';
6
6
  import type { SurfaceTheme } from '../../../../theme/types';
7
7
  import type { ToastProps } from '../../../../types/toast';
8
- import { Box, Stack } from '../../../layout/public';
8
+ import { View } from '../../../layout/public';
9
9
  import { Surface } from '../../../surface/public';
10
10
  import { Text } from '../../../typography/public';
11
11
 
@@ -29,15 +29,15 @@ export function Toast({
29
29
 
30
30
  return (
31
31
  <Surface p="m" style={[styles.root, statusStyle]} testID={testID} variant="raised">
32
- <Stack align="center" direction="row" justify="space-between">
33
- <Box flex={1}>
32
+ <View align="center" direction="row" justify="space-between">
33
+ <View flex={1}>
34
34
  {title ? (
35
35
  <Text variant="label" weight="medium">
36
36
  {title}
37
37
  </Text>
38
38
  ) : null}
39
39
  {description ? <Text emphasis="muted">{description}</Text> : null}
40
- </Box>
40
+ </View>
41
41
  {onDismiss ? (
42
42
  <Pressable
43
43
  accessibilityLabel="Dismiss notification"
@@ -48,7 +48,7 @@ export function Toast({
48
48
  <Text color={statusTextColor}>×</Text>
49
49
  </Pressable>
50
50
  ) : null}
51
- </Stack>
51
+ </View>
52
52
  </Surface>
53
53
  );
54
54
  }
@@ -4,7 +4,7 @@ import { StyleSheet, type ViewStyle } from 'react-native';
4
4
  import { Portal } from '../../../../internal/overlay/Portal';
5
5
  import { resolveOverlayAnimation } from '../../../../internal/resolvers';
6
6
  import type { ToastProviderProps } from '../../../../types/toast';
7
- import { Stack } from '../../../layout/public';
7
+ import { View } from '../../../layout/public';
8
8
  import { ToastContext } from '../../composition/ToastContext';
9
9
  import { useToastRuntime } from '../../composition/useToastRuntime';
10
10
  import { Toast } from './Toast';
@@ -22,7 +22,7 @@ export function ToastProvider({ children, defaultDuration = 4000 }: ToastProvide
22
22
  <ToastContext value={controller}>
23
23
  {children}
24
24
  <Portal layer="toast" visible={toasts.length > 0}>
25
- <Stack gap="s" pointerEvents="box-none" style={[styles.container, animationStyle]}>
25
+ <View gap="s" pointerEvents="box-none" style={[styles.container, animationStyle]}>
26
26
  {toasts.map((toast) => (
27
27
  <Toast
28
28
  description={toast.description}
@@ -33,7 +33,7 @@ export function ToastProvider({ children, defaultDuration = 4000 }: ToastProvide
33
33
  title={toast.title}
34
34
  />
35
35
  ))}
36
- </Stack>
36
+ </View>
37
37
  </Portal>
38
38
  </ToastContext>
39
39
  );