@hzblj/kara-components 0.5.0 → 0.7.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 (225) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/README.md +31 -3
  3. package/lib/module/atoms/checkbox/checkbox.android.js +7 -3
  4. package/lib/module/atoms/checkbox/checkbox.android.js.map +1 -1
  5. package/lib/module/atoms/chip/chip.js +1 -1
  6. package/lib/module/atoms/chip/chip.js.map +1 -1
  7. package/lib/module/atoms/date-picker/date-picker.ios.js +32 -11
  8. package/lib/module/atoms/date-picker/date-picker.ios.js.map +1 -1
  9. package/lib/module/atoms/index.js +0 -1
  10. package/lib/module/atoms/index.js.map +1 -1
  11. package/lib/module/atoms/pressable/pressable.js +11 -5
  12. package/lib/module/atoms/pressable/pressable.js.map +1 -1
  13. package/lib/module/atoms/rn-flat-list/rn-flat-list.js +10 -9
  14. package/lib/module/atoms/rn-flat-list/rn-flat-list.js.map +1 -1
  15. package/lib/module/atoms/rn-section-list/rn-section-list.js +5 -8
  16. package/lib/module/atoms/rn-section-list/rn-section-list.js.map +1 -1
  17. package/lib/module/atoms/segmented-control/index.js +1 -1
  18. package/lib/module/atoms/segmented-control/index.js.map +1 -1
  19. package/lib/module/atoms/segmented-control/segmented-control.android.js +74 -0
  20. package/lib/module/atoms/segmented-control/segmented-control.android.js.map +1 -0
  21. package/lib/module/atoms/segmented-control/segmented-control.ios.js +44 -0
  22. package/lib/module/atoms/segmented-control/segmented-control.ios.js.map +1 -0
  23. package/lib/module/atoms/slider/slider.android.js +26 -2
  24. package/lib/module/atoms/slider/slider.android.js.map +1 -1
  25. package/lib/module/atoms/switch/switch.android.js +14 -4
  26. package/lib/module/atoms/switch/switch.android.js.map +1 -1
  27. package/lib/module/haptics/haptics.js +56 -0
  28. package/lib/module/haptics/haptics.js.map +1 -0
  29. package/lib/module/haptics/index.js +5 -0
  30. package/lib/module/haptics/index.js.map +1 -0
  31. package/lib/module/haptics/use-haptic-feedback.js +33 -0
  32. package/lib/module/haptics/use-haptic-feedback.js.map +1 -0
  33. package/lib/module/index.js +1 -0
  34. package/lib/module/index.js.map +1 -1
  35. package/lib/module/molecules/search-bar/search-bar.js +15 -2
  36. package/lib/module/molecules/search-bar/search-bar.js.map +1 -1
  37. package/lib/module/molecules/tooltip/tooltip.android.js +16 -5
  38. package/lib/module/molecules/tooltip/tooltip.android.js.map +1 -1
  39. package/lib/module/organisms/action-sheet/action-sheet.android.js +41 -20
  40. package/lib/module/organisms/action-sheet/action-sheet.android.js.map +1 -1
  41. package/lib/module/organisms/action-sheet/action-sheet.ios.js +24 -8
  42. package/lib/module/organisms/action-sheet/action-sheet.ios.js.map +1 -1
  43. package/lib/module/organisms/alert/alert.ios.js +15 -2
  44. package/lib/module/organisms/alert/alert.ios.js.map +1 -1
  45. package/lib/module/organisms/context-menu/context-menu.android.js +2 -2
  46. package/lib/module/organisms/context-menu/context-menu.android.js.map +1 -1
  47. package/lib/module/organisms/form/form.android.js +22 -9
  48. package/lib/module/organisms/form/form.android.js.map +1 -1
  49. package/lib/module/organisms/swipe-actions/swipe-actions.android.js +125 -11
  50. package/lib/module/organisms/swipe-actions/swipe-actions.android.js.map +1 -1
  51. package/lib/module/organisms/swipe-actions/swipe-actions.ios.js +46 -18
  52. package/lib/module/organisms/swipe-actions/swipe-actions.ios.js.map +1 -1
  53. package/lib/module/templates/screen/screen.android.js +31 -10
  54. package/lib/module/templates/screen/screen.android.js.map +1 -1
  55. package/lib/typescript/atoms/avatar/avatar.types.d.ts +5 -0
  56. package/lib/typescript/atoms/badge/badge.types.d.ts +3 -0
  57. package/lib/typescript/atoms/button/button.types.d.ts +12 -0
  58. package/lib/typescript/atoms/card/card.types.d.ts +6 -0
  59. package/lib/typescript/atoms/checkbox/checkbox.types.d.ts +5 -0
  60. package/lib/typescript/atoms/chip/chip.types.d.ts +5 -0
  61. package/lib/typescript/atoms/color-picker/color-picker.types.d.ts +4 -0
  62. package/lib/typescript/atoms/date-picker/date-picker.ios.d.ts +6 -1
  63. package/lib/typescript/atoms/date-picker/date-picker.types.d.ts +14 -0
  64. package/lib/typescript/atoms/divider/divider.types.d.ts +3 -0
  65. package/lib/typescript/atoms/fab/fab.types.d.ts +7 -0
  66. package/lib/typescript/atoms/glass-view/glass-view.types.d.ts +1 -0
  67. package/lib/typescript/atoms/h-stack/h-stack.types.d.ts +6 -0
  68. package/lib/typescript/atoms/icon/icon.types.d.ts +8 -0
  69. package/lib/typescript/atoms/icon-button/icon-button.types.d.ts +5 -0
  70. package/lib/typescript/atoms/index.d.ts +0 -1
  71. package/lib/typescript/atoms/island/island.types.d.ts +4 -0
  72. package/lib/typescript/atoms/list/list.types.d.ts +2 -0
  73. package/lib/typescript/atoms/picker/picker.types.d.ts +12 -0
  74. package/lib/typescript/atoms/pressable/pressable.types.d.ts +11 -1
  75. package/lib/typescript/atoms/progress/progress.types.d.ts +6 -0
  76. package/lib/typescript/atoms/rn-flat-list/rn-flat-list.d.ts +5 -8
  77. package/lib/typescript/atoms/rn-flat-list/rn-flat-list.types.d.ts +3 -1
  78. package/lib/typescript/atoms/rn-scroll-view/rn-scroll-view.types.d.ts +4 -0
  79. package/lib/typescript/atoms/rn-section-list/rn-section-list.d.ts +2 -8
  80. package/lib/typescript/atoms/rn-section-list/rn-section-list.types.d.ts +3 -1
  81. package/lib/typescript/atoms/rn-text/rn-text.types.d.ts +4 -0
  82. package/lib/typescript/atoms/rn-view/rn-view.types.d.ts +2 -0
  83. package/lib/typescript/atoms/scroll-view/scroll-view.types.d.ts +4 -0
  84. package/lib/typescript/atoms/segmented-control/segmented-control.d.ts +1 -2
  85. package/lib/typescript/atoms/segmented-control/segmented-control.ios.d.ts +7 -0
  86. package/lib/typescript/atoms/segmented-control/segmented-control.types.d.ts +13 -0
  87. package/lib/typescript/atoms/skeleton/skeleton.types.d.ts +5 -0
  88. package/lib/typescript/atoms/slider/slider.types.d.ts +7 -0
  89. package/lib/typescript/atoms/spacer/spacer.types.d.ts +3 -0
  90. package/lib/typescript/atoms/surface/surface.types.d.ts +7 -0
  91. package/lib/typescript/atoms/switch/switch.types.d.ts +8 -0
  92. package/lib/typescript/atoms/text/text.types.d.ts +12 -0
  93. package/lib/typescript/atoms/text-field/text-field.types.d.ts +12 -0
  94. package/lib/typescript/atoms/v-stack/v-stack.types.d.ts +9 -0
  95. package/lib/typescript/atoms/z-stack/z-stack.types.d.ts +8 -0
  96. package/lib/typescript/haptics/haptics.d.ts +61 -0
  97. package/lib/typescript/haptics/index.d.ts +2 -0
  98. package/lib/typescript/haptics/use-haptic-feedback.d.ts +15 -0
  99. package/lib/typescript/index.d.ts +1 -0
  100. package/lib/typescript/molecules/collapsible/collapsible.types.d.ts +8 -0
  101. package/lib/typescript/molecules/empty-state/empty-state.types.d.ts +5 -0
  102. package/lib/typescript/molecules/label/label.types.d.ts +6 -0
  103. package/lib/typescript/molecules/labeled-content/labeled-content.types.d.ts +6 -0
  104. package/lib/typescript/molecules/link/link.types.d.ts +6 -0
  105. package/lib/typescript/molecules/list-item/list-item.types.d.ts +9 -0
  106. package/lib/typescript/molecules/navigation-bar/navigation-bar.types.d.ts +8 -0
  107. package/lib/typescript/molecules/pager/pager.types.d.ts +2 -0
  108. package/lib/typescript/molecules/radio-group/radio-group.types.d.ts +10 -0
  109. package/lib/typescript/molecules/rn-list-item/rn-list-item.types.d.ts +1 -1
  110. package/lib/typescript/molecules/rn-tooltip/rn-tooltip.types.d.ts +11 -0
  111. package/lib/typescript/molecules/scroll-edge-container/scroll-edge-container.types.d.ts +3 -0
  112. package/lib/typescript/molecules/search-bar/search-bar.types.d.ts +8 -0
  113. package/lib/typescript/molecules/stepper/stepper.types.d.ts +13 -0
  114. package/lib/typescript/molecules/tooltip/tooltip.types.d.ts +12 -0
  115. package/lib/typescript/organisms/action-sheet/action-sheet.types.d.ts +8 -0
  116. package/lib/typescript/organisms/alert/alert.types.d.ts +11 -0
  117. package/lib/typescript/organisms/context-menu/context-menu.types.d.ts +4 -0
  118. package/lib/typescript/organisms/fab-menu/fab-menu.types.d.ts +2 -0
  119. package/lib/typescript/organisms/form/form.types.d.ts +6 -0
  120. package/lib/typescript/organisms/menu/menu.types.d.ts +17 -0
  121. package/lib/typescript/organisms/sheet/sheet.types.d.ts +19 -0
  122. package/lib/typescript/organisms/snackbar/snackbar.types.d.ts +8 -0
  123. package/lib/typescript/organisms/swipe-actions/swipe-actions.types.d.ts +36 -13
  124. package/lib/typescript/templates/screen/screen.types.d.ts +9 -0
  125. package/package.json +5 -9
  126. package/src/atoms/avatar/avatar.types.ts +5 -0
  127. package/src/atoms/badge/badge.types.ts +3 -0
  128. package/src/atoms/button/button.types.ts +12 -0
  129. package/src/atoms/card/card.types.ts +6 -0
  130. package/src/atoms/checkbox/checkbox.android.tsx +7 -3
  131. package/src/atoms/checkbox/checkbox.types.ts +5 -0
  132. package/src/atoms/chip/chip.tsx +1 -1
  133. package/src/atoms/chip/chip.types.ts +5 -0
  134. package/src/atoms/color-picker/color-picker.types.ts +4 -0
  135. package/src/atoms/date-picker/date-picker.ios.tsx +33 -13
  136. package/src/atoms/date-picker/date-picker.types.ts +14 -0
  137. package/src/atoms/divider/divider.types.ts +3 -0
  138. package/src/atoms/fab/fab.types.ts +7 -0
  139. package/src/atoms/glass-view/glass-view.types.ts +1 -0
  140. package/src/atoms/h-stack/h-stack.types.ts +6 -0
  141. package/src/atoms/icon/icon.types.ts +8 -0
  142. package/src/atoms/icon-button/icon-button.types.ts +5 -0
  143. package/src/atoms/index.ts +0 -1
  144. package/src/atoms/island/island.types.ts +4 -0
  145. package/src/atoms/list/list.types.ts +2 -0
  146. package/src/atoms/picker/picker.types.ts +12 -0
  147. package/src/atoms/pressable/pressable.tsx +12 -5
  148. package/src/atoms/pressable/pressable.types.ts +12 -1
  149. package/src/atoms/progress/progress.types.ts +6 -0
  150. package/src/atoms/rn-flat-list/rn-flat-list.tsx +8 -8
  151. package/src/atoms/rn-flat-list/rn-flat-list.types.ts +3 -1
  152. package/src/atoms/rn-scroll-view/rn-scroll-view.types.ts +4 -0
  153. package/src/atoms/rn-section-list/rn-section-list.tsx +5 -8
  154. package/src/atoms/rn-section-list/rn-section-list.types.ts +3 -1
  155. package/src/atoms/rn-text/rn-text.types.ts +4 -0
  156. package/src/atoms/rn-view/rn-view.types.ts +2 -0
  157. package/src/atoms/scroll-view/scroll-view.types.ts +4 -0
  158. package/src/atoms/segmented-control/segmented-control.android.tsx +79 -0
  159. package/src/atoms/segmented-control/segmented-control.ios.tsx +47 -0
  160. package/src/atoms/segmented-control/segmented-control.types.ts +13 -0
  161. package/src/atoms/skeleton/skeleton.types.ts +5 -0
  162. package/src/atoms/slider/slider.android.tsx +33 -2
  163. package/src/atoms/slider/slider.types.ts +7 -0
  164. package/src/atoms/spacer/spacer.types.ts +3 -0
  165. package/src/atoms/surface/surface.types.ts +7 -0
  166. package/src/atoms/switch/switch.android.tsx +18 -5
  167. package/src/atoms/switch/switch.types.ts +8 -0
  168. package/src/atoms/text/text.types.ts +12 -0
  169. package/src/atoms/text-field/text-field.types.ts +12 -0
  170. package/src/atoms/v-stack/v-stack.types.ts +9 -0
  171. package/src/atoms/z-stack/z-stack.types.ts +8 -0
  172. package/src/haptics/haptics.ts +68 -0
  173. package/src/haptics/index.ts +2 -0
  174. package/src/haptics/use-haptic-feedback.ts +36 -0
  175. package/src/index.ts +1 -0
  176. package/src/molecules/collapsible/collapsible.types.ts +8 -0
  177. package/src/molecules/empty-state/empty-state.types.ts +5 -0
  178. package/src/molecules/label/label.types.ts +6 -0
  179. package/src/molecules/labeled-content/labeled-content.types.ts +6 -0
  180. package/src/molecules/link/link.types.ts +6 -0
  181. package/src/molecules/list-item/list-item.types.ts +9 -0
  182. package/src/molecules/navigation-bar/navigation-bar.types.ts +8 -0
  183. package/src/molecules/pager/pager.types.ts +2 -0
  184. package/src/molecules/radio-group/radio-group.types.ts +10 -0
  185. package/src/molecules/rn-list-item/rn-list-item.types.ts +1 -1
  186. package/src/molecules/rn-tooltip/rn-tooltip.types.ts +11 -0
  187. package/src/molecules/scroll-edge-container/scroll-edge-container.types.ts +3 -0
  188. package/src/molecules/search-bar/search-bar.tsx +9 -2
  189. package/src/molecules/search-bar/search-bar.types.ts +8 -0
  190. package/src/molecules/stepper/stepper.types.ts +13 -0
  191. package/src/molecules/tooltip/tooltip.android.tsx +17 -9
  192. package/src/molecules/tooltip/tooltip.types.ts +12 -0
  193. package/src/organisms/action-sheet/action-sheet.android.tsx +37 -19
  194. package/src/organisms/action-sheet/action-sheet.ios.tsx +22 -9
  195. package/src/organisms/action-sheet/action-sheet.types.ts +8 -0
  196. package/src/organisms/alert/alert.ios.tsx +11 -1
  197. package/src/organisms/alert/alert.types.ts +11 -0
  198. package/src/organisms/context-menu/context-menu.android.tsx +2 -2
  199. package/src/organisms/context-menu/context-menu.types.ts +4 -0
  200. package/src/organisms/fab-menu/fab-menu.types.ts +2 -0
  201. package/src/organisms/form/form.android.tsx +15 -7
  202. package/src/organisms/form/form.types.ts +6 -0
  203. package/src/organisms/menu/menu.types.ts +17 -0
  204. package/src/organisms/sheet/sheet.types.ts +19 -0
  205. package/src/organisms/snackbar/snackbar.types.ts +8 -0
  206. package/src/organisms/swipe-actions/swipe-actions.android.tsx +129 -9
  207. package/src/organisms/swipe-actions/swipe-actions.ios.tsx +45 -11
  208. package/src/organisms/swipe-actions/swipe-actions.types.ts +37 -14
  209. package/src/templates/screen/screen.android.tsx +33 -12
  210. package/src/templates/screen/screen.types.ts +9 -0
  211. package/lib/module/atoms/flash-list/flash-list.js +0 -31
  212. package/lib/module/atoms/flash-list/flash-list.js.map +0 -1
  213. package/lib/module/atoms/flash-list/flash-list.types.js +0 -4
  214. package/lib/module/atoms/flash-list/flash-list.types.js.map +0 -1
  215. package/lib/module/atoms/flash-list/index.js +0 -5
  216. package/lib/module/atoms/flash-list/index.js.map +0 -1
  217. package/lib/module/atoms/segmented-control/segmented-control.js +0 -28
  218. package/lib/module/atoms/segmented-control/segmented-control.js.map +0 -1
  219. package/lib/typescript/atoms/flash-list/flash-list.d.ts +0 -8
  220. package/lib/typescript/atoms/flash-list/flash-list.types.d.ts +0 -18
  221. package/lib/typescript/atoms/flash-list/index.d.ts +0 -2
  222. package/src/atoms/flash-list/flash-list.tsx +0 -28
  223. package/src/atoms/flash-list/flash-list.types.ts +0 -20
  224. package/src/atoms/flash-list/index.ts +0 -2
  225. package/src/atoms/segmented-control/segmented-control.tsx +0 -34
@@ -1,13 +1,25 @@
1
1
  import type { ReactNode } from 'react';
2
+ /** One choice of a `Picker`. */
2
3
  export type PickerOption = {
4
+ /** What the user reads. */
3
5
  label: string;
6
+ /** What `onValueChange` reports. It also keys the option, so it must be unique. */
4
7
  value: string;
5
8
  };
9
+ /**
10
+ * A single choice from a list — a SwiftUI wheel picker on iOS, Material's exposed dropdown on Android. It brings its
11
+ * own host, so it renders outside `Screen` and `Island` as well.
12
+ */
6
13
  export type PickerProps = {
14
+ /** Stops the user changing the selection, and dims the picker. */
7
15
  disabled?: boolean;
16
+ /** Called with the chosen option's `value`. */
8
17
  onValueChange?: (value: string) => void;
18
+ /** The choices, in order. */
9
19
  options: PickerOption[];
20
+ /** Android: the dropdown field's test tag. iOS: `@expo/ui`'s wheel picker drops it. */
10
21
  testID?: string;
22
+ /** The selected option's `value`. Controlled: pass back what `onValueChange` reports. */
11
23
  value: string;
12
24
  };
13
25
  export type PickerComponent = (props: PickerProps) => ReactNode;
@@ -1,10 +1,20 @@
1
1
  import type { ResponsiveViewSx } from '@hzblj/kara-sx';
2
2
  import type { ReactNode } from 'react';
3
+ import type { Haptic } from '../../haptics';
4
+ /**
5
+ * React Native's `Pressable`, styled through `sx` like a `Box`: it springs down to 96% while pressed and takes
6
+ * touches 8 points past its edges. The React Native tier — it needs no host.
7
+ */
3
8
  export type PressableProps = ResponsiveViewSx & {
9
+ /** The pressable content. */
4
10
  children?: ReactNode;
11
+ /** Ignores presses — no `onPress`, no haptic, no spring. */
5
12
  disabled?: boolean;
6
- haptic?: boolean;
13
+ /** Played on press. `true` is a `light` impact; a name picks the haptic, e.g. `selection` for a choice. */
14
+ haptic?: boolean | Haptic;
15
+ /** Called when the press is released, after the `haptic` plays. */
7
16
  onPress?: () => void;
17
+ /** Test identifier, forwarded to the view. */
8
18
  testID?: string;
9
19
  };
10
20
  export type PressableComponent = (props: PressableProps) => ReactNode;
@@ -1,6 +1,12 @@
1
1
  import type { ReactNode } from 'react';
2
+ /**
3
+ * A progress bar or ring, tinted `fill.accent.primary` — SwiftUI `ProgressView` / Compose's
4
+ * `LinearProgressIndicator` and `CircularProgressIndicator`.
5
+ */
2
6
  export type ProgressProps = {
7
+ /** A circular indicator instead of a bar. Off by default. */
3
8
  circular?: boolean;
9
+ /** Between `0` and `1`. Leave it unset for an indeterminate indicator. */
4
10
  value?: number;
5
11
  };
6
12
  export type ProgressComponent = (props: ProgressProps) => ReactNode;
@@ -1,12 +1,9 @@
1
1
  import type { RnFlatListProps } from './rn-flat-list.types';
2
2
  /**
3
- * Flat list built on React Native's own `VirtualizedList` rather than FlashList.
4
- *
5
- * FlashList is the default for lists in this codebase and should stay that way for data rows — reach
6
- * for this only for the case it cannot serve: content that hosts native views. FlashList positions its
7
- * rows absolutely and recycles their cells, and an `@expo/ui` host survives neither — the hosted view
8
- * ends up drawn where the layout no longer is. `VirtualizedList` renders its cells in normal flow
9
- * inside a scroll view, using blank spacers for the range it has not rendered, so a hosted view stays
10
- * exactly where the layout put it. This is `SectionList`'s reason to exist too, without the sections.
3
+ * kara's list for React Native content: React Native's own `VirtualizedList`, styled through `sx`. It renders its
4
+ * cells in normal flow inside a scroll view, with blank spacers for the range it has not rendered, so a row that hosts
5
+ * native views keeps them where the layout put it. A recycling list (absolutely positioned, reused cells) cannot
6
+ * promise that — an `@expo/ui` host survives neither, and draws where the layout no longer is — which is why kara
7
+ * ships none.
11
8
  */
12
9
  export declare const RnFlatList: <TItem>({ content, data, renderItem, ...props }: RnFlatListProps<TItem>) => import("react").JSX.Element;
@@ -2,8 +2,10 @@ import type { ResponsiveViewSx } from '@hzblj/kara-sx';
2
2
  import type { FlatListProps as RNFlatListProps } from 'react-native';
3
3
  /**
4
4
  * Top-level `sx` styles the viewport; `content` styles the scrolling content container, so padding and
5
- * gap belong there — the same split as `RnScrollView`.
5
+ * gap belong there — the same split as `RnScrollView`. `removeClippedSubviews` is off unless you turn it on:
6
+ * Android's default would detach a row's host before it has measured itself, and the row would stay empty.
6
7
  */
7
8
  export type RnFlatListProps<TItem> = ResponsiveViewSx & Omit<RNFlatListProps<TItem>, 'contentContainerStyle' | 'style'> & {
9
+ /** Styles the scrolling content container — padding and gap belong here. */
8
10
  content?: ResponsiveViewSx;
9
11
  };
@@ -11,9 +11,13 @@ import type { ScrollViewAxis } from '../scroll-view';
11
11
  * so padding and gap belong there.
12
12
  */
13
13
  export type RnScrollViewProps = ResponsiveViewSx & Omit<RNScrollViewProps, 'contentContainerStyle' | 'horizontal' | 'style'> & {
14
+ /** The scroll direction. `vertical` by default. */
14
15
  axis?: ScrollViewAxis;
16
+ /** The scrolling content. */
15
17
  children?: ReactNode;
18
+ /** Styles the scrolling content container — padding and gap belong here. */
16
19
  content?: ResponsiveViewSx;
20
+ /** Shows the scroll indicators. On by default. */
17
21
  showsIndicators?: boolean;
18
22
  };
19
23
  export type RnScrollViewComponent = (props: RnScrollViewProps) => ReactNode;
@@ -1,14 +1,8 @@
1
1
  import { type DefaultSectionT } from 'react-native';
2
2
  import type { RnSectionListProps } from './rn-section-list.types';
3
3
  /**
4
- * Sectioned list built on React Native's own `VirtualizedList` rather than FlashList.
5
- *
6
- * FlashList is the default for lists in this codebase and should stay that way for data rows. This
7
- * exists for the case it cannot serve: content that hosts native views. FlashList positions its rows
8
- * absolutely and recycles their cells, and an `@expo/ui` host does not survive either — the hosted
9
- * view ends up drawn where the layout no longer is. `VirtualizedList` renders its cells in normal flow
10
- * inside a scroll view, using blank spacers for the range it has not rendered, so a hosted view stays
11
- * exactly where the layout put it.
4
+ * `RnFlatList` with sections: React Native's own `VirtualizedList`, cells in normal flow inside a scroll view, so a
5
+ * row that hosts native views keeps them where the layout put it.
12
6
  *
13
7
  * Sticky headers default off, unlike React Native, where they are on for vertical lists. A header that
14
8
  * detaches and floats over the content is a deliberate effect, not something a list should do unasked.
@@ -2,8 +2,10 @@ import type { ResponsiveViewSx } from '@hzblj/kara-sx';
2
2
  import type { DefaultSectionT, SectionListProps as RNSectionListProps } from 'react-native';
3
3
  /**
4
4
  * Top-level `sx` styles the viewport; `content` styles the scrolling content container, so padding and
5
- * gap belong there — the same split as `RnScrollView` and `RnFlatList`.
5
+ * gap belong there — the same split as `RnScrollView` and `RnFlatList`. `removeClippedSubviews` is off unless
6
+ * you turn it on, as in `RnFlatList`: Android's default would leave rows with hosts in them empty.
6
7
  */
7
8
  export type RnSectionListProps<TItem, TSection = DefaultSectionT> = ResponsiveViewSx & Omit<RNSectionListProps<TItem, TSection>, 'contentContainerStyle' | 'style'> & {
9
+ /** Styles the scrolling content container — padding and gap belong here. */
8
10
  content?: ResponsiveViewSx;
9
11
  };
@@ -1,9 +1,13 @@
1
1
  import type { ColorToken, TextVariant } from '@hzblj/kara-theme';
2
2
  import type { ReactNode } from 'react';
3
3
  import type { TextProps as RNTextProps } from 'react-native';
4
+ /** React Native's `Text` in a theme typography variant — the React Native tier, for text outside a native host. */
4
5
  export type RnTextProps = Omit<RNTextProps, 'style'> & {
6
+ /** Horizontal alignment, as React Native's `textAlign`. */
5
7
  align?: 'center' | 'left' | 'right';
8
+ /** The text's colour. `content.primary` by default. */
6
9
  color?: ColorToken;
10
+ /** The typography variant. `body` by default. */
7
11
  variant?: TextVariant;
8
12
  };
9
13
  export type RnTextComponent = (props: RnTextProps) => ReactNode;
@@ -1,4 +1,5 @@
1
1
  import type { ReactElement, ReactNode } from 'react';
2
+ /** Carries a React Native view into a SwiftUI or Compose tree — `@expo/ui`'s `RNHostView` on both platforms. */
2
3
  export type RnViewProps = {
3
4
  /**
4
5
  * A single React Native *view*. It may not contain React Native text: a bare string becomes a
@@ -14,6 +15,7 @@ export type RnViewProps = {
14
15
  * intrinsic size and would otherwise stretch to fill the SwiftUI parent.
15
16
  */
16
17
  matchContents?: boolean;
18
+ /** Not forwarded on either platform — give the child its own `testID`. */
17
19
  testID?: string;
18
20
  };
19
21
  export type RnViewComponent = (props: RnViewProps) => ReactNode;
@@ -7,7 +7,9 @@ export type ScrollViewAxis = 'horizontal' | 'vertical';
7
7
  * like React Native's `contentContainerStyle` padding and scrolls with the content.
8
8
  */
9
9
  export type ScrollViewProps = ResponsiveSx & {
10
+ /** The scroll direction. `vertical` by default. */
10
11
  axis?: ScrollViewAxis;
12
+ /** Laid out in a stack along `axis`. */
11
13
  children?: ReactNode;
12
14
  /**
13
15
  * Enables pull-to-refresh. Async on purpose: the spinner runs until the promise settles, which is
@@ -19,7 +21,9 @@ export type ScrollViewProps = ResponsiveSx & {
19
21
  onRefresh?: () => Promise<void>;
20
22
  /** iOS only — Compose exposes no indicator toggle, so Android always shows the native one. */
21
23
  showsIndicators?: boolean;
24
+ /** The space between children. */
22
25
  spacing?: SpaceSize;
26
+ /** Test identifier, forwarded to the native view. */
23
27
  testID?: string;
24
28
  };
25
29
  export type ScrollViewComponent = (props: ScrollViewProps) => ReactNode;
@@ -1,2 +1 @@
1
- import type { SegmentedControlComponent } from './segmented-control.types';
2
- export declare const SegmentedControl: SegmentedControlComponent;
1
+ export * from './segmented-control.ios';
@@ -0,0 +1,7 @@
1
+ import type { SegmentedControlComponent } from './segmented-control.types';
2
+ /**
3
+ * kara's own `UISegmentedControl`, with the pill in the accent and white text on it — the system control tints only the
4
+ * pill, and SwiftUI's segmented picker not even that. A plain `UIView` in React Native layout: it needs no host, takes
5
+ * the width it is given and UIKit's height. UIKit plays the control's own feedback.
6
+ */
7
+ export declare const SegmentedControl: SegmentedControlComponent;
@@ -1,9 +1,22 @@
1
1
  import type { ReactNode } from 'react';
2
+ /**
3
+ * A row of mutually exclusive segments, the selected one in the accent — kara's own `UISegmentedControl` on iOS,
4
+ * Material's single-choice segmented buttons on Android. It needs no `Screen` or `Island`: iOS is a plain view, Android
5
+ * brings its own host. It takes the width it is given; the height is the platform's.
6
+ */
2
7
  export type SegmentedControlProps = {
8
+ /** Stops the user changing the segment, and dims the control. */
3
9
  disabled?: boolean;
10
+ /**
11
+ * Called with the index and label of the segment the user picked — never for a tap on the one already selected.
12
+ * Android plays `selection`; iOS's control plays its own feedback.
13
+ */
4
14
  onChange?: (index: number, value: string) => void;
15
+ /** The selected segment. Controlled: pass back what `onChange` reports. */
5
16
  selectedIndex: number;
17
+ /** Test identifier, on the whole control — reach a segment by its label. */
6
18
  testID?: string;
19
+ /** The segments' labels, in order. */
7
20
  values: string[];
8
21
  };
9
22
  export type SegmentedControlComponent = (props: SegmentedControlProps) => ReactNode;
@@ -1,9 +1,14 @@
1
1
  import type { RadiiSize } from '@hzblj/kara-theme';
2
2
  import type { ReactNode } from 'react';
3
+ /** A loading placeholder that pulses in `fill.quaternary` — a React Native view, so it needs no host. */
3
4
  export type SkeletonProps = {
5
+ /** The corner radius. `small` by default. */
4
6
  borderRadius?: RadiiSize;
7
+ /** In points. */
5
8
  height: number;
9
+ /** Test identifier, forwarded to the view. */
6
10
  testID?: string;
11
+ /** In points. Leave it unset and it fills the available width. */
7
12
  width?: number;
8
13
  };
9
14
  export type SkeletonComponent = (props: SkeletonProps) => ReactNode;
@@ -1,10 +1,17 @@
1
1
  import type { ReactNode } from 'react';
2
+ /** SwiftUI `Slider` / Compose's Material `Slider`, tinted `fill.accent.primary`. */
2
3
  export type SliderProps = {
4
+ /** Stops the user moving the thumb, and dims the slider. */
3
5
  disabled?: boolean;
6
+ /** The upper end. `1` by default. */
4
7
  max?: number;
8
+ /** The lower end. `0` by default. */
5
9
  min?: number;
10
+ /** Called with the new value as the thumb moves. */
6
11
  onValueChange?: (value: number) => void;
12
+ /** The increment between stops; leave it unset for a continuous slider. On Android every stop plays a `tick`. */
7
13
  step?: number;
14
+ /** Between `min` and `max`. Controlled: pass back what `onValueChange` reports. */
8
15
  value: number;
9
16
  };
10
17
  export type SliderComponent = (props: SliderProps) => ReactNode;
@@ -1,7 +1,10 @@
1
1
  import type { SpaceSize } from '@hzblj/kara-theme';
2
2
  import type { ReactNode } from 'react';
3
+ /** Takes up the free space in a stack — SwiftUI `Spacer` / Compose `Spacer` with `weight(1)`. */
3
4
  export type SpacerProps = {
5
+ /** The least room it takes. iOS holds it along the stack's axis; Android as a minimum height only. */
4
6
  min?: SpaceSize;
7
+ /** iOS: forwarded to the native view. Android ignores it. */
5
8
  testID?: string;
6
9
  };
7
10
  export type SpacerComponent = (props: SpacerProps) => ReactNode;
@@ -1,8 +1,15 @@
1
1
  import type { ResponsiveSx } from '@hzblj/kara-sx';
2
2
  import type { ReactNode } from 'react';
3
+ /**
4
+ * A container padded `s16` and rounded `large` unless told otherwise — a SwiftUI `VStack` on iOS, Material's
5
+ * `Surface` around a `Column` on Android.
6
+ */
3
7
  export type SurfaceProps = ResponsiveSx & {
8
+ /** Stacked vertically, from the leading edge. */
4
9
  children?: ReactNode;
10
+ /** iOS wraps the content in a `GlassEffectContainer`; Android raises it to a tonal elevation of `3`. */
5
11
  glass?: boolean;
12
+ /** Test identifier, forwarded to the native view. */
6
13
  testID?: string;
7
14
  };
8
15
  export type SurfaceComponent = (props: SurfaceProps) => ReactNode;
@@ -1,8 +1,16 @@
1
1
  import type { ReactNode } from 'react';
2
+ /** SwiftUI `Toggle` / Compose `Switch`, tinted `fill.accent.primary`. */
2
3
  export type SwitchProps = {
4
+ /** Stops the user flipping it, and dims it. */
3
5
  disabled?: boolean;
6
+ /**
7
+ * Shown beside the switch. On Android it makes a full-width row — label at the start, switch at the end — that
8
+ * toggles wherever it is tapped.
9
+ */
4
10
  label?: string;
11
+ /** Called with the new value when the user flips it. On Android a flip plays `toggleOn` / `toggleOff`. */
5
12
  onValueChange?: (value: boolean) => void;
13
+ /** Whether it is on. Controlled: pass back what `onValueChange` reports. */
6
14
  value: boolean;
7
15
  };
8
16
  export type SwitchComponent = (props: SwitchProps) => ReactNode;
@@ -3,14 +3,26 @@ import type { ReactNode } from 'react';
3
3
  export type TextAlign = 'center' | 'left' | 'right';
4
4
  export type TextDecoration = 'none' | 'strikethrough' | 'underline';
5
5
  export type TextTransform = 'lowercase' | 'uppercase';
6
+ /** SwiftUI `Text` / Compose `Text` in a theme typography variant — a native atom; outside a host, use `RnText`. */
6
7
  export type TextProps = {
8
+ /**
9
+ * How its lines align. iOS reads `left` and `right` as leading and trailing, so they flip in a right-to-left
10
+ * layout; Android keeps them as they are.
11
+ */
7
12
  align?: TextAlign;
13
+ /** The text. */
8
14
  children?: ReactNode;
15
+ /** The text's colour. `content.primary` by default. */
9
16
  color?: ColorToken;
17
+ /** An underline or a strikethrough. */
10
18
  decoration?: TextDecoration;
19
+ /** The most lines it wraps to. iOS truncates the last with an ellipsis; Android clips it. */
11
20
  numberOfLines?: number;
21
+ /** Test identifier, forwarded to the native view. */
12
22
  testID?: string;
23
+ /** Upper- or lower-cases the text. Android applies it only when `children` is a plain string. */
13
24
  transform?: TextTransform;
25
+ /** The typography variant. `body` by default. */
14
26
  variant?: TextVariant;
15
27
  };
16
28
  export type TextComponent = (props: TextProps) => ReactNode;
@@ -1,12 +1,24 @@
1
1
  import type { ReactNode } from 'react';
2
+ /**
3
+ * An uncontrolled text field with an optional label above it — SwiftUI `TextField` (`SecureField` when `secure`) /
4
+ * Compose `OutlinedTextField`.
5
+ */
2
6
  export type TextFieldProps = {
7
+ /** The text it starts with. Read once, on mount — the field is uncontrolled. */
3
8
  defaultValue?: string;
9
+ /** Stops editing and dims the field. On iOS it outranks `error`. */
4
10
  disabled?: boolean;
11
+ /** Marks the field invalid: a destructive outline and label. */
5
12
  error?: boolean;
13
+ /** Shown above the field, in `labelMedium`. */
6
14
  label?: string;
15
+ /** Wraps the text and grows the field to fit it. iOS ignores it when `secure`. */
7
16
  multiline?: boolean;
17
+ /** Called with the whole text after every change. */
8
18
  onChangeText?: (text: string) => void;
19
+ /** Masks the text, for a password. */
9
20
  secure?: boolean;
21
+ /** iOS: forwarded to the native field. Android ignores it. */
10
22
  testID?: string;
11
23
  };
12
24
  export type TextFieldComponent = (props: TextFieldProps) => ReactNode;
@@ -2,11 +2,20 @@ import type { ResponsiveSx } from '@hzblj/kara-sx';
2
2
  import type { SpaceSize } from '@hzblj/kara-theme';
3
3
  import type { ReactNode } from 'react';
4
4
  export type VStackAlign = 'center' | 'end' | 'start';
5
+ /** Stacks its children top to bottom — SwiftUI `VStack` / Compose `Column`. */
5
6
  export type VStackProps = ResponsiveSx & {
7
+ /** The children's horizontal alignment. `start` by default. */
6
8
  align?: VStackAlign;
9
+ /** Laid out top to bottom, `spacing` apart. */
7
10
  children?: ReactNode;
11
+ /**
12
+ * Makes the whole stack pressable. iOS adds a tap gesture with no press feedback; Android a `clickable` whose ripple
13
+ * fills the stack's shape.
14
+ */
8
15
  onPress?: () => void;
16
+ /** The space between children. */
9
17
  spacing?: SpaceSize;
18
+ /** Test identifier, forwarded to the native view. */
10
19
  testID?: string;
11
20
  };
12
21
  export type VStackComponent = (props: VStackProps) => ReactNode;
@@ -1,10 +1,18 @@
1
1
  import type { ResponsiveSx } from '@hzblj/kara-sx';
2
2
  import type { ReactNode } from 'react';
3
3
  export type ZStackAlign = 'bottom' | 'center' | 'top';
4
+ /** Layers its children on one another — SwiftUI `ZStack` / Compose `Box`. */
4
5
  export type ZStackProps = ResponsiveSx & {
6
+ /** Where the children sit vertically; they are always centred horizontally. `center` by default. */
5
7
  align?: ZStackAlign;
8
+ /** Drawn in order, the last on top. */
6
9
  children?: ReactNode;
10
+ /**
11
+ * Makes the whole stack pressable. iOS adds a tap gesture with no press feedback; Android a `clickable` whose ripple
12
+ * fills the stack's shape.
13
+ */
7
14
  onPress?: () => void;
15
+ /** Test identifier, forwarded to the native view. */
8
16
  testID?: string;
9
17
  };
10
18
  export type ZStackComponent = (props: ZStackProps) => ReactNode;
@@ -0,0 +1,61 @@
1
+ import { type Haptic } from '@hzblj/kara-native';
2
+ export type { Haptic };
3
+ export type HapticOptions = {
4
+ /** iOS: scales an impact — `soft`, `light`, `medium`, `rigid`, `heavy` — from 0 to 1. Everything else ignores it. */
5
+ intensity?: number;
6
+ };
7
+ declare const play: (haptic: Haptic, options?: HapticOptions) => void;
8
+ declare const prepare: (haptic: Haptic) => void;
9
+ /**
10
+ * The platform's own haptic feedback, named for what happened: UIKit's feedback generators on iOS, the system's
11
+ * `HapticFeedbackConstants` on Android — never a raw vibration. Both follow the user's system haptics setting, and
12
+ * every call is synchronous, with nothing to await.
13
+ *
14
+ * ```ts
15
+ * haptics.success() // a name you know: one function per haptic
16
+ * haptics.play(haptic) // a name that arrives as data
17
+ * haptics.light({intensity: 0.6}) // impacts scale on iOS
18
+ * haptics.prepare('selection') // iOS: warm the Taptic Engine as a gesture begins
19
+ * haptics.setEnabled(userPreference) // silences every kara haptic, the components' own too
20
+ * ```
21
+ *
22
+ * - `selection` — a choice changed: a segment, a chip, a picker row.
23
+ * - `tick` — one step of a continuous gesture: a slider detent, a scrubbed value.
24
+ * - `toggleOn` / `toggleOff` — a switch flipped.
25
+ * - `success` / `warning` / `error` — how a task ended. Android has no warning of its own; it plays a rejection.
26
+ * - `longPress` / `dragStart` — a long press was recognised; an item lifted to be dragged.
27
+ * - `thresholdActivate` / `thresholdDeactivate` — a gesture crossed its commit point, or went back over it.
28
+ * - `keyPress` — a key of the app's own keypad.
29
+ * - `soft`, `light`, `medium`, `rigid`, `heavy` — a collision none of the names above describes.
30
+ *
31
+ * On Android the names that came with Android 14's constants fall back to the nearest older feedback, so every name
32
+ * plays on every version. Haptics are silent in a build without kara's native module.
33
+ */
34
+ export declare const haptics: {
35
+ /** Whether kara plays haptics — `true` until `setEnabled(false)`. */
36
+ isEnabled: () => boolean;
37
+ play: typeof play;
38
+ prepare: typeof prepare;
39
+ /**
40
+ * Switches every kara haptic on or off, the ones its components play included — for an app's own "Haptics" setting.
41
+ * Not persisted: call it at start-up with the stored preference. The system setting applies either way.
42
+ */
43
+ setEnabled: (value: boolean) => void;
44
+ dragStart: (options?: HapticOptions) => void;
45
+ error: (options?: HapticOptions) => void;
46
+ heavy: (options?: HapticOptions) => void;
47
+ keyPress: (options?: HapticOptions) => void;
48
+ light: (options?: HapticOptions) => void;
49
+ longPress: (options?: HapticOptions) => void;
50
+ medium: (options?: HapticOptions) => void;
51
+ rigid: (options?: HapticOptions) => void;
52
+ selection: (options?: HapticOptions) => void;
53
+ soft: (options?: HapticOptions) => void;
54
+ success: (options?: HapticOptions) => void;
55
+ thresholdActivate: (options?: HapticOptions) => void;
56
+ thresholdDeactivate: (options?: HapticOptions) => void;
57
+ tick: (options?: HapticOptions) => void;
58
+ toggleOff: (options?: HapticOptions) => void;
59
+ toggleOn: (options?: HapticOptions) => void;
60
+ warning: (options?: HapticOptions) => void;
61
+ };
@@ -0,0 +1,2 @@
1
+ export { type Haptic, type HapticOptions, haptics } from './haptics';
2
+ export { type HapticResolver, useHapticFeedback } from './use-haptic-feedback';
@@ -0,0 +1,15 @@
1
+ import { type Haptic } from './haptics';
2
+ /** Picks the haptic for one change of a trigger — or none, to stay silent for that change. */
3
+ export type HapticResolver<T> = (previous: T, next: T) => Haptic | false | null | undefined;
4
+ /**
5
+ * Plays a haptic whenever `trigger` changes — never on mount — like SwiftUI's `sensoryFeedback(_:trigger:)`. Give it
6
+ * a haptic, or a function of the previous and next value that picks one per change. Changes are compared with
7
+ * `Object.is`, so a trigger is a primitive or a stable reference.
8
+ *
9
+ * ```ts
10
+ * useHapticFeedback(tab, 'selection')
11
+ * useHapticFeedback(quantity, (before, after) => (after > before ? 'tick' : 'soft'))
12
+ * useHapticFeedback(payment.status, (_, status) => status === 'paid' ? 'success' : status === 'failed' && 'error')
13
+ * ```
14
+ */
15
+ export declare const useHapticFeedback: <T>(trigger: T, feedback: Haptic | HapticResolver<T>) => void;
@@ -1,4 +1,5 @@
1
1
  export * from './atoms';
2
+ export * from './haptics';
2
3
  export * from './molecules';
3
4
  export * from './organisms';
4
5
  export * from './templates';
@@ -1,8 +1,16 @@
1
1
  import type { ReactNode } from 'react';
2
+ /**
3
+ * A row that shows and hides its content: SwiftUI's `DisclosureGroup` on iOS; on Android a pressable row with a
4
+ * chevron over an animated reveal. A native atom — it renders inside `<Screen>` or `<Island>`.
5
+ */
2
6
  export type CollapsibleProps = {
7
+ /** Shown while `expanded`. */
3
8
  children: ReactNode;
9
+ /** Whether the content is shown. Update it from `onExpandedChange`. */
4
10
  expanded: boolean;
11
+ /** The row's text. */
5
12
  label: string;
13
+ /** The user pressed the row; it passes the state the row asks for. */
6
14
  onExpandedChange: (expanded: boolean) => void;
7
15
  };
8
16
  export type CollapsibleComponent = (props: CollapsibleProps) => ReactNode;
@@ -5,10 +5,15 @@ import type { IconName } from '../../atoms/icon';
5
5
  * `action` takes a `Button` so the state can offer a way out.
6
6
  */
7
7
  export type EmptyStateProps = {
8
+ /** Under the text — a `Button`, say. */
8
9
  action?: ReactNode;
10
+ /** A second line under the title, in the secondary colour. */
9
11
  description?: string;
12
+ /** One of the app's icons, large and muted above the title. */
10
13
  icon?: IconName;
14
+ /** Test identifier, forwarded to the native view. */
11
15
  testID?: string;
16
+ /** The headline. */
12
17
  title: string;
13
18
  };
14
19
  export type EmptyStateComponent = (props: EmptyStateProps) => ReactNode;
@@ -6,11 +6,17 @@ import type { IconName } from '../../atoms/icon';
6
6
  * header. For a full tappable row with a subtitle and chevron, use `ListItem`.
7
7
  */
8
8
  export type LabelProps = {
9
+ /** Colours the icon and the title alike. `content.primary` by default. */
9
10
  color?: ColorToken;
11
+ /** One of the app's icons, before the title. */
10
12
  icon: IconName;
13
+ /** The icon's size. `s20` by default. */
11
14
  iconSize?: SpaceSize;
15
+ /** Test identifier, forwarded to the native view. */
12
16
  testID?: string;
17
+ /** The text beside the icon. */
13
18
  title: string;
19
+ /** The title's text style. `body` by default. */
14
20
  variant?: TextVariant;
15
21
  };
16
22
  export type LabelComponent = (props: LabelProps) => ReactNode;
@@ -6,13 +6,19 @@ import type { IconName } from '../../atoms/icon';
6
6
  * Pass `children` instead of `value` when the trailing side is a control rather than text.
7
7
  */
8
8
  export type LabeledContentProps = {
9
+ /** The trailing side when it is a control, in place of `value`. */
9
10
  children?: ReactNode;
11
+ /** One of the app's icons, before the label, in the secondary colour. */
10
12
  icon?: IconName;
13
+ /** The leading text. */
11
14
  label: string;
15
+ /** Makes the row pressable and adds a chevron on the trailing edge. */
12
16
  onPress?: () => void;
13
17
  /** Horizontal padding inside the row — inside its press area too, so Android's ripple reaches the card's edges. */
14
18
  px?: SpaceSize;
19
+ /** Test identifier, forwarded to the native view. */
15
20
  testID?: string;
21
+ /** The trailing text, in the secondary colour. Ignored when `children` is given. */
16
22
  value?: string;
17
23
  };
18
24
  export type LabeledContentComponent = (props: LabeledContentProps) => ReactNode;
@@ -3,11 +3,17 @@ import type { ReactNode } from 'react';
3
3
  import type { IconName } from '../../atoms/icon';
4
4
  /** Opens an external URL in the platform browser or the app that claims the scheme. */
5
5
  export type LinkProps = {
6
+ /** Colours the label and the icon. `content.accent` by default. */
6
7
  color?: ColorToken;
8
+ /** One of the app's icons, before the label. */
7
9
  icon?: IconName;
10
+ /** The link's text. */
8
11
  label: string;
12
+ /** Test identifier, forwarded to the native view. */
9
13
  testID?: string;
14
+ /** Opened through React Native's `Linking` on press. A URL nothing can open fails silently. */
10
15
  url: string;
16
+ /** The label's text style. `body` by default. */
11
17
  variant?: TextVariant;
12
18
  };
13
19
  export type LinkComponent = (props: LinkProps) => ReactNode;
@@ -1,16 +1,25 @@
1
1
  import type { SpaceSize } from '@hzblj/kara-theme';
2
2
  import type { ReactNode } from 'react';
3
3
  import type { IconName } from '../../atoms/icon';
4
+ /**
5
+ * A row with an optional icon, a title and subtitle, and a chevron when it can be pressed. A native atom — it renders
6
+ * inside `<Screen>` or `<Island>`; `RnListItem` is the same row without a host.
7
+ */
4
8
  export type ListItemProps = {
9
+ /** One of the app's icons, before the title, in the secondary colour. */
5
10
  icon?: IconName;
11
+ /** Makes the row pressable and adds a chevron on the trailing edge. */
6
12
  onPress?: () => void;
7
13
  /**
8
14
  * Horizontal padding inside the row — inside its press area too, so Android's ripple reaches the card's edges. For
9
15
  * rows in a card of your own; a `List` insets its rows by itself.
10
16
  */
11
17
  px?: SpaceSize;
18
+ /** A second line under the title, smaller and in the secondary colour. */
12
19
  subtitle?: string;
20
+ /** Test identifier, forwarded to the row's view. */
13
21
  testID?: string;
22
+ /** The row's main text. */
14
23
  title: string;
15
24
  };
16
25
  export type ListItemComponent = (props: ListItemProps) => ReactNode;