@hzblj/kara-components 0.16.0 → 0.18.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 (211) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/lib/module/atoms/badge/badge.android.js +5 -0
  3. package/lib/module/atoms/badge/badge.android.js.map +1 -1
  4. package/lib/module/atoms/badge/badge.ios.js +2 -0
  5. package/lib/module/atoms/badge/badge.ios.js.map +1 -1
  6. package/lib/module/atoms/button/button-tokens.js +8 -0
  7. package/lib/module/atoms/button/button-tokens.js.map +1 -1
  8. package/lib/module/atoms/button/button.android.js +43 -15
  9. package/lib/module/atoms/button/button.android.js.map +1 -1
  10. package/lib/module/atoms/button/button.ios.js +66 -10
  11. package/lib/module/atoms/button/button.ios.js.map +1 -1
  12. package/lib/module/atoms/checkbox/checkbox.android.js +5 -1
  13. package/lib/module/atoms/checkbox/checkbox.android.js.map +1 -1
  14. package/lib/module/atoms/checkbox/checkbox.ios.js +3 -1
  15. package/lib/module/atoms/checkbox/checkbox.ios.js.map +1 -1
  16. package/lib/module/atoms/color-picker/color-picker.android.js +4 -0
  17. package/lib/module/atoms/color-picker/color-picker.android.js.map +1 -1
  18. package/lib/module/atoms/color-picker/color-picker.ios.js +24 -2
  19. package/lib/module/atoms/color-picker/color-picker.ios.js.map +1 -1
  20. package/lib/module/atoms/date-picker/date-picker.android.js +85 -10
  21. package/lib/module/atoms/date-picker/date-picker.android.js.map +1 -1
  22. package/lib/module/atoms/date-picker/date-picker.ios.js +9 -7
  23. package/lib/module/atoms/date-picker/date-picker.ios.js.map +1 -1
  24. package/lib/module/atoms/divider/divider.android.js +17 -4
  25. package/lib/module/atoms/divider/divider.android.js.map +1 -1
  26. package/lib/module/atoms/divider/divider.ios.js +4 -0
  27. package/lib/module/atoms/divider/divider.ios.js.map +1 -1
  28. package/lib/module/atoms/fab/fab.android.js +64 -8
  29. package/lib/module/atoms/fab/fab.android.js.map +1 -1
  30. package/lib/module/atoms/fab/fab.ios.js +68 -12
  31. package/lib/module/atoms/fab/fab.ios.js.map +1 -1
  32. package/lib/module/atoms/icon-button/icon-button.android.js +48 -5
  33. package/lib/module/atoms/icon-button/icon-button.android.js.map +1 -1
  34. package/lib/module/atoms/icon-button/icon-button.ios.js +60 -10
  35. package/lib/module/atoms/icon-button/icon-button.ios.js.map +1 -1
  36. package/lib/module/atoms/list/list.android.js +32 -4
  37. package/lib/module/atoms/list/list.android.js.map +1 -1
  38. package/lib/module/atoms/list/list.ios.js +15 -5
  39. package/lib/module/atoms/list/list.ios.js.map +1 -1
  40. package/lib/module/atoms/picker/picker.ios.js +27 -15
  41. package/lib/module/atoms/picker/picker.ios.js.map +1 -1
  42. package/lib/module/atoms/progress/progress.android.js +21 -7
  43. package/lib/module/atoms/progress/progress.android.js.map +1 -1
  44. package/lib/module/atoms/progress/progress.ios.js +5 -1
  45. package/lib/module/atoms/progress/progress.ios.js.map +1 -1
  46. package/lib/module/atoms/slider/slider.android.js +16 -2
  47. package/lib/module/atoms/slider/slider.android.js.map +1 -1
  48. package/lib/module/atoms/slider/slider.ios.js +22 -2
  49. package/lib/module/atoms/slider/slider.ios.js.map +1 -1
  50. package/lib/module/atoms/switch/switch.android.js +5 -1
  51. package/lib/module/atoms/switch/switch.android.js.map +1 -1
  52. package/lib/module/atoms/switch/switch.ios.js +3 -1
  53. package/lib/module/atoms/switch/switch.ios.js.map +1 -1
  54. package/lib/module/atoms/text/spans.js +2 -1
  55. package/lib/module/atoms/text/spans.js.map +1 -1
  56. package/lib/module/atoms/text/text.android.js +18 -6
  57. package/lib/module/atoms/text/text.android.js.map +1 -1
  58. package/lib/module/atoms/text/text.ios.js +6 -2
  59. package/lib/module/atoms/text/text.ios.js.map +1 -1
  60. package/lib/module/atoms/text-field/text-field-input.js +14 -0
  61. package/lib/module/atoms/text-field/text-field-input.js.map +1 -0
  62. package/lib/module/atoms/text-field/text-field.android.js +113 -6
  63. package/lib/module/atoms/text-field/text-field.android.js.map +1 -1
  64. package/lib/module/atoms/text-field/text-field.ios.js +75 -3
  65. package/lib/module/atoms/text-field/text-field.ios.js.map +1 -1
  66. package/lib/module/molecules/collapsible/collapsible.android.js +4 -3
  67. package/lib/module/molecules/collapsible/collapsible.android.js.map +1 -1
  68. package/lib/module/molecules/collapsible/collapsible.ios.js +3 -1
  69. package/lib/module/molecules/collapsible/collapsible.ios.js.map +1 -1
  70. package/lib/module/molecules/radio-group/radio-group.android.js +10 -2
  71. package/lib/module/molecules/radio-group/radio-group.android.js.map +1 -1
  72. package/lib/module/molecules/radio-group/radio-group.ios.js +6 -2
  73. package/lib/module/molecules/radio-group/radio-group.ios.js.map +1 -1
  74. package/lib/module/molecules/search-bar/search-bar.js +9 -0
  75. package/lib/module/molecules/search-bar/search-bar.js.map +1 -1
  76. package/lib/module/molecules/stepper/stepper.android.js +25 -13
  77. package/lib/module/molecules/stepper/stepper.android.js.map +1 -1
  78. package/lib/module/molecules/stepper/stepper.ios.js +12 -6
  79. package/lib/module/molecules/stepper/stepper.ios.js.map +1 -1
  80. package/lib/module/organisms/action-sheet/action-sheet.android.js +16 -8
  81. package/lib/module/organisms/action-sheet/action-sheet.android.js.map +1 -1
  82. package/lib/module/organisms/action-sheet/action-sheet.ios.js +16 -3
  83. package/lib/module/organisms/action-sheet/action-sheet.ios.js.map +1 -1
  84. package/lib/module/organisms/alert/alert.android.js +4 -3
  85. package/lib/module/organisms/alert/alert.android.js.map +1 -1
  86. package/lib/module/organisms/alert/alert.ios.js +3 -2
  87. package/lib/module/organisms/alert/alert.ios.js.map +1 -1
  88. package/lib/module/organisms/context-menu/context-menu.android.js +3 -1
  89. package/lib/module/organisms/context-menu/context-menu.android.js.map +1 -1
  90. package/lib/module/organisms/context-menu/context-menu.ios.js +1 -0
  91. package/lib/module/organisms/context-menu/context-menu.ios.js.map +1 -1
  92. package/lib/module/organisms/fab-menu/fab-menu.android.js +3 -0
  93. package/lib/module/organisms/fab-menu/fab-menu.android.js.map +1 -1
  94. package/lib/module/organisms/fab-menu/fab-menu.ios.js +3 -0
  95. package/lib/module/organisms/fab-menu/fab-menu.ios.js.map +1 -1
  96. package/lib/module/organisms/menu/menu-parts.js +20 -0
  97. package/lib/module/organisms/menu/menu-parts.js.map +1 -0
  98. package/lib/module/organisms/menu/menu.android.js +51 -19
  99. package/lib/module/organisms/menu/menu.android.js.map +1 -1
  100. package/lib/module/organisms/menu/menu.ios.js +71 -8
  101. package/lib/module/organisms/menu/menu.ios.js.map +1 -1
  102. package/lib/module/organisms/sheet/sheet.js +2 -1
  103. package/lib/module/organisms/sheet/sheet.js.map +1 -1
  104. package/lib/typescript/atoms/badge/badge.types.d.ts +2 -0
  105. package/lib/typescript/atoms/button/button-tokens.d.ts +6 -2
  106. package/lib/typescript/atoms/button/button.types.d.ts +19 -5
  107. package/lib/typescript/atoms/checkbox/checkbox.types.d.ts +2 -0
  108. package/lib/typescript/atoms/color-picker/color-picker.types.d.ts +2 -0
  109. package/lib/typescript/atoms/date-picker/date-picker.ios.d.ts +5 -5
  110. package/lib/typescript/atoms/date-picker/date-picker.types.d.ts +30 -7
  111. package/lib/typescript/atoms/divider/divider.ios.d.ts +4 -0
  112. package/lib/typescript/atoms/divider/divider.types.d.ts +13 -2
  113. package/lib/typescript/atoms/fab/fab.types.d.ts +21 -4
  114. package/lib/typescript/atoms/icon-button/icon-button.types.d.ts +23 -4
  115. package/lib/typescript/atoms/list/list.types.d.ts +15 -1
  116. package/lib/typescript/atoms/picker/picker.ios.d.ts +5 -3
  117. package/lib/typescript/atoms/picker/picker.types.d.ts +11 -3
  118. package/lib/typescript/atoms/progress/progress.types.d.ts +13 -2
  119. package/lib/typescript/atoms/slider/slider.ios.d.ts +4 -0
  120. package/lib/typescript/atoms/slider/slider.types.d.ts +7 -0
  121. package/lib/typescript/atoms/switch/switch.types.d.ts +2 -0
  122. package/lib/typescript/atoms/text/spans.d.ts +2 -0
  123. package/lib/typescript/atoms/text/text.types.d.ts +9 -1
  124. package/lib/typescript/atoms/text-field/text-field-input.d.ts +7 -0
  125. package/lib/typescript/atoms/text-field/text-field.types.d.ts +77 -4
  126. package/lib/typescript/molecules/collapsible/collapsible.types.d.ts +2 -0
  127. package/lib/typescript/molecules/radio-group/radio-group.types.d.ts +4 -0
  128. package/lib/typescript/molecules/search-bar/search-bar.types.d.ts +11 -1
  129. package/lib/typescript/molecules/stepper/stepper.ios.d.ts +2 -1
  130. package/lib/typescript/molecules/stepper/stepper.types.d.ts +17 -0
  131. package/lib/typescript/organisms/action-sheet/action-sheet.ios.d.ts +4 -0
  132. package/lib/typescript/organisms/action-sheet/action-sheet.types.d.ts +8 -3
  133. package/lib/typescript/organisms/alert/alert.types.d.ts +8 -3
  134. package/lib/typescript/organisms/menu/menu-parts.d.ts +14 -0
  135. package/lib/typescript/organisms/menu/menu.types.d.ts +35 -7
  136. package/lib/typescript/organisms/sheet/sheet.types.d.ts +7 -1
  137. package/package.json +4 -4
  138. package/src/atoms/badge/badge.android.tsx +9 -2
  139. package/src/atoms/badge/badge.ios.tsx +2 -2
  140. package/src/atoms/badge/badge.types.ts +2 -0
  141. package/src/atoms/button/button-tokens.ts +6 -3
  142. package/src/atoms/button/button.android.tsx +35 -11
  143. package/src/atoms/button/button.ios.tsx +72 -8
  144. package/src/atoms/button/button.types.ts +20 -5
  145. package/src/atoms/checkbox/checkbox.android.tsx +5 -2
  146. package/src/atoms/checkbox/checkbox.ios.tsx +2 -2
  147. package/src/atoms/checkbox/checkbox.types.ts +2 -0
  148. package/src/atoms/color-picker/color-picker.android.tsx +10 -2
  149. package/src/atoms/color-picker/color-picker.ios.tsx +24 -1
  150. package/src/atoms/color-picker/color-picker.types.ts +2 -0
  151. package/src/atoms/date-picker/date-picker.android.tsx +86 -16
  152. package/src/atoms/date-picker/date-picker.ios.tsx +20 -8
  153. package/src/atoms/date-picker/date-picker.types.ts +31 -7
  154. package/src/atoms/divider/divider.android.tsx +14 -3
  155. package/src/atoms/divider/divider.ios.tsx +4 -0
  156. package/src/atoms/divider/divider.types.ts +14 -2
  157. package/src/atoms/fab/fab.android.tsx +61 -11
  158. package/src/atoms/fab/fab.ios.tsx +48 -13
  159. package/src/atoms/fab/fab.types.ts +22 -4
  160. package/src/atoms/icon-button/icon-button.android.tsx +60 -10
  161. package/src/atoms/icon-button/icon-button.ios.tsx +77 -8
  162. package/src/atoms/icon-button/icon-button.types.ts +24 -4
  163. package/src/atoms/list/list.android.tsx +26 -4
  164. package/src/atoms/list/list.ios.tsx +20 -5
  165. package/src/atoms/list/list.types.ts +16 -1
  166. package/src/atoms/picker/picker.ios.tsx +46 -16
  167. package/src/atoms/picker/picker.types.ts +12 -3
  168. package/src/atoms/progress/progress.android.tsx +32 -6
  169. package/src/atoms/progress/progress.ios.tsx +11 -5
  170. package/src/atoms/progress/progress.types.ts +13 -2
  171. package/src/atoms/slider/slider.android.tsx +18 -2
  172. package/src/atoms/slider/slider.ios.tsx +38 -2
  173. package/src/atoms/slider/slider.types.ts +7 -0
  174. package/src/atoms/switch/switch.android.tsx +5 -2
  175. package/src/atoms/switch/switch.ios.tsx +2 -2
  176. package/src/atoms/switch/switch.types.ts +2 -0
  177. package/src/atoms/text/spans.ts +2 -1
  178. package/src/atoms/text/text.android.tsx +20 -7
  179. package/src/atoms/text/text.ios.tsx +7 -0
  180. package/src/atoms/text/text.types.ts +10 -1
  181. package/src/atoms/text-field/text-field-input.ts +17 -0
  182. package/src/atoms/text-field/text-field.android.tsx +132 -9
  183. package/src/atoms/text-field/text-field.ios.tsx +110 -6
  184. package/src/atoms/text-field/text-field.types.ts +98 -4
  185. package/src/molecules/collapsible/collapsible.android.tsx +10 -2
  186. package/src/molecules/collapsible/collapsible.ios.tsx +8 -2
  187. package/src/molecules/collapsible/collapsible.types.ts +2 -0
  188. package/src/molecules/radio-group/radio-group.android.tsx +18 -4
  189. package/src/molecules/radio-group/radio-group.ios.tsx +19 -5
  190. package/src/molecules/radio-group/radio-group.types.ts +4 -0
  191. package/src/molecules/search-bar/search-bar.tsx +9 -0
  192. package/src/molecules/search-bar/search-bar.types.ts +12 -1
  193. package/src/molecules/stepper/stepper.android.tsx +24 -4
  194. package/src/molecules/stepper/stepper.ios.tsx +23 -8
  195. package/src/molecules/stepper/stepper.types.ts +17 -0
  196. package/src/organisms/action-sheet/action-sheet.android.tsx +23 -11
  197. package/src/organisms/action-sheet/action-sheet.ios.tsx +20 -3
  198. package/src/organisms/action-sheet/action-sheet.types.ts +8 -3
  199. package/src/organisms/alert/alert.android.tsx +11 -8
  200. package/src/organisms/alert/alert.ios.tsx +2 -1
  201. package/src/organisms/alert/alert.types.ts +8 -3
  202. package/src/organisms/context-menu/context-menu.android.tsx +3 -2
  203. package/src/organisms/context-menu/context-menu.ios.tsx +1 -0
  204. package/src/organisms/fab-menu/fab-menu.android.tsx +3 -0
  205. package/src/organisms/fab-menu/fab-menu.ios.tsx +9 -1
  206. package/src/organisms/menu/menu-parts.ts +21 -0
  207. package/src/organisms/menu/menu.android.tsx +39 -10
  208. package/src/organisms/menu/menu.ios.tsx +55 -5
  209. package/src/organisms/menu/menu.types.ts +30 -7
  210. package/src/organisms/sheet/sheet.tsx +2 -1
  211. package/src/organisms/sheet/sheet.types.ts +7 -1
@@ -4,6 +4,8 @@ export type BadgeTone = 'accent' | 'destructive' | 'neutral' | 'success';
4
4
  export type BadgeProps = {
5
5
  /** The text inside. */
6
6
  label: string;
7
+ /** Test identifier, forwarded to the native view. */
8
+ testID?: string;
7
9
  /** The fill and text colours. `neutral` by default. */
8
10
  tone?: BadgeTone;
9
11
  };
@@ -12,14 +12,18 @@ export declare const buttonTokens: (variant: ButtonVariant, disabled: boolean, t
12
12
  readonly content: 'content.primary';
13
13
  readonly fill: 'btn.bg.glass.base';
14
14
  readonly shadow: 'btn.glass';
15
+ } | {
16
+ readonly content: 'content.accent';
17
+ readonly fill: undefined;
18
+ readonly shadow: undefined;
15
19
  } | {
16
20
  readonly content: 'content.primary';
17
21
  readonly fill: 'btn.bg.secondary.base';
18
22
  readonly shadow: 'btn.secondary';
19
23
  } | {
20
24
  readonly content: 'btn.content.disabled';
21
- readonly fill: "btn.bg.glass.disabled" | "btn.bg.secondary.disabled" | "fill.accent.disabled" | "fill.destructive.disabled";
22
- readonly shadow: "btn.accent" | "btn.destructive" | "btn.glass" | "btn.secondary";
25
+ readonly fill: "btn.bg.glass.disabled" | "btn.bg.secondary.disabled" | "fill.accent.disabled" | "fill.destructive.disabled" | undefined;
26
+ readonly shadow: "btn.accent" | "btn.destructive" | "btn.glass" | "btn.secondary" | undefined;
23
27
  };
24
28
  /**
25
29
  * The label for a button filled with an arbitrary `tint`: the on-accent white over a strong colour, the primary
@@ -1,6 +1,7 @@
1
1
  import type { ColorToken } from '@hzblj/kara-theme';
2
2
  import type { ReactNode } from 'react';
3
- export type ButtonVariant = 'accent' | 'destructive' | 'glass' | 'secondary';
3
+ import type { IconName } from '../icon';
4
+ export type ButtonVariant = 'accent' | 'destructive' | 'glass' | 'plain' | 'secondary';
4
5
  /**
5
6
  * SwiftUI `ButtonStyle`. iOS only: Compose has no equivalent, so Android ignores it and keeps
6
7
  * rendering the variant's tokens.
@@ -11,19 +12,28 @@ export type ButtonStyleName = 'automatic' | 'bordered' | 'borderedProminent' | '
11
12
  * whatever the surrounding SwiftUI environment provides.
12
13
  */
13
14
  export type ButtonControlSize = 'extraLarge' | 'large' | 'mini' | 'regular' | 'small';
14
- /** A text button: SwiftUI `Button` on iOS, Material's filled button (outlined for `glass`) on Android. */
15
+ /**
16
+ * A text button: SwiftUI `Button` on iOS, Material's filled button on Android (outlined for `glass`, a `TextButton`
17
+ * for `plain`).
18
+ */
15
19
  export type ButtonProps = {
16
20
  /** What pressing it does, when the label alone does not say. See `AccessibilityProps`. */
17
21
  accessibilityHint?: string;
18
22
  /**
19
23
  * Replaces the style the variant picks: `borderedProminent` for `accent` and `destructive`, `bordered` for
20
- * `secondary`, `glass` for `glass`. iOS only. Android ignores it.
24
+ * `secondary`, `glass` for `glass`, `borderless` for `plain`. iOS only. Android ignores it.
21
25
  */
22
26
  buttonStyle?: ButtonStyleName;
23
27
  /** SwiftUI's control size. `large` by default. iOS only. Android ignores it. */
24
28
  controlSize?: ButtonControlSize;
25
29
  /** Draws the button in its disabled colours and stops it responding to presses. */
26
30
  disabled?: boolean;
31
+ /**
32
+ * One of the app's icons, before the label and in the label's colour. iOS sets the two as a SwiftUI `Label`; Android
33
+ * puts the icon in the button's content row, as Material's buttons with an icon do. Screen readers read the label
34
+ * only.
35
+ */
36
+ icon?: IconName;
27
37
  /** The button's text. */
28
38
  label: string;
29
39
  /** Called when the button is pressed. */
@@ -33,10 +43,14 @@ export type ButtonProps = {
33
43
  /**
34
44
  * Overrides the variant's own tint. A prominent style takes it as the fill and picks a contrasting
35
45
  * label. `glass` has to reach the material through `glassEffect` instead, so tinting one costs it
36
- * the stock `.glass` style (see the iOS implementation).
46
+ * the stock `.glass` style (see the iOS implementation). `plain` has no fill, so there it colours the label.
37
47
  */
38
48
  tint?: ColorToken;
39
- /** The look. `accent` by default. Material has no glass, so on Android `glass` is an outlined button. */
49
+ /**
50
+ * The look. `accent` by default. Material has no glass, so on Android `glass` is an outlined button. `plain` is a
51
+ * text button in the accent, with no fill or border, for a lesser action beside a prominent one ("Skip", "Forgot
52
+ * password?"): SwiftUI's `borderless` style, Material's `TextButton`.
53
+ */
40
54
  variant?: ButtonVariant;
41
55
  /** Stretches the button to the full width it is offered. On by default. */
42
56
  wide?: boolean;
@@ -7,6 +7,8 @@ export type CheckboxProps = {
7
7
  label?: string;
8
8
  /** Called with the new value when the user toggles it. */
9
9
  onValueChange?: (value: boolean) => void;
10
+ /** Test identifier, forwarded to the native control (on Android the box itself, not the labelled row). */
11
+ testID?: string;
10
12
  /** Whether it is checked. Controlled: update it from `onValueChange`. */
11
13
  value: boolean;
12
14
  };
@@ -5,6 +5,8 @@ import type { ReactNode } from 'react';
5
5
  * spectrum and RGB sliders.
6
6
  */
7
7
  export type ColorPickerProps = {
8
+ /** Stops the user picking a colour, and dims the label and the well. */
9
+ disabled?: boolean;
8
10
  /** Text beside the colour well, and the Android sheet's title. */
9
11
  label?: string;
10
12
  /** Called with the colour the user picks. */
@@ -1,9 +1,9 @@
1
1
  import type { DatePickerComponent } from './date-picker.types';
2
2
  /**
3
- * The system's compact date picker: the value in a pill, and a tap on it opens the calendar popover UIKit owns. Its own
4
- * host, sized to the pill on both axes — a host that took the width it was given would lay the pill out against the
5
- * far edge of it, or past its container's — so it drops into a row the way a `Text` does. The label is the caller's,
6
- * beside it; the calendar is in the accent. Inside a `Screen` or `Island` it renders into that host instead (see
7
- * `useInsideHost`).
3
+ * The system's date picker, in the accent. `compact` by default: the value in a pill, and a tap on it opens the
4
+ * calendar popover UIKit owns. `graphical` is that calendar in place, `wheel` the value on wheels. Its own host, sized
5
+ * to the picker on both axes (a host that took the width it was given would lay the pill out against the far edge of
6
+ * it, or past its container's), so it drops into a row the way a `Text` does. The label is the caller's, beside it.
7
+ * Inside a `Screen` or `Island` it renders into that host instead (see `useInsideHost`).
8
8
  */
9
9
  export declare const DatePicker: DatePickerComponent;
@@ -1,23 +1,46 @@
1
1
  import type { ReactNode } from 'react';
2
2
  export type DatePickerMode = 'date' | 'datetime' | 'time';
3
+ /** How SwiftUI shows the picker: a pill that opens the calendar, the calendar in place, or wheels. */
4
+ export type DatePickerStyleName = 'compact' | 'graphical' | 'wheel';
3
5
  /**
4
- * A date or time picker: SwiftUI's compact `DatePicker` on iOS, a field that opens Material's picker dialog on a tap
5
- * on Android. The React Native tier: it brings its own host and sizes itself to the value, so it sits in a row beside
6
- * its label like a `Text`. Inside a `Screen` or `Island` it joins that host instead, beside a native `Text` label.
6
+ * A date or time picker: SwiftUI's `DatePicker` on iOS (a pill by default, a calendar or wheels with
7
+ * `datePickerStyle`), a field that opens Material's picker dialog on a tap on Android, or Material's calendar in place
8
+ * with `datePickerStyle="graphical"`. The React Native tier: it brings its own host and sizes itself to the value, so it
9
+ * sits in a row beside its label like a `Text`. Inside a `Screen` or `Island` it joins that host instead, beside a
10
+ * native `Text` label.
7
11
  */
8
12
  export type DatePickerProps = {
13
+ /**
14
+ * SwiftUI's date picker style. `compact` by default: the value in a pill, which opens the calendar in a popover.
15
+ * `graphical` is the calendar in place, a month at a time, with the time under it in `datetime` mode: what a screen
16
+ * built around picking a day wants. `wheel` puts the value on wheels. Android shows Material's calendar in place for
17
+ * `graphical` in `date` and `datetime` modes (without its title and headline); otherwise it keeps its field and
18
+ * dialog, since Material has no wheel.
19
+ */
20
+ datePickerStyle?: DatePickerStyleName;
21
+ /**
22
+ * Stops the user changing the date, and dims the picker. Material's calendar has no disabled state of its own, so a
23
+ * `graphical` picker on Android is dimmed and offers only the selected day.
24
+ */
25
+ disabled?: boolean;
9
26
  /** The latest date that can be picked. Android ignores it in `time` mode. */
10
27
  max?: Date;
11
28
  /** The earliest date that can be picked. Android ignores it in `time` mode. */
12
29
  min?: Date;
13
30
  /**
14
- * What it picks. `date` by default. Android has no combined dialog, so there `datetime` picks the date and keeps
15
- * `value`'s time of day.
31
+ * What it picks. `date` by default. Android has no combined dialog or calendar, so there `datetime` picks the date
32
+ * and keeps `value`'s time of day.
16
33
  */
17
34
  mode?: DatePickerMode;
18
- /** Called with the new date: on iOS as it changes, on Android when the dialog is confirmed. */
35
+ /**
36
+ * Called with the new date: on iOS as it changes, on Android when the dialog is confirmed or a day in the calendar
37
+ * is tapped.
38
+ */
19
39
  onValueChange?: (date: Date) => void;
20
- /** Test identifier, on the native picker on iOS and on the tappable field on Android. */
40
+ /**
41
+ * Test identifier, on the native picker on iOS and on Android's calendar, and on the tappable field elsewhere on
42
+ * Android.
43
+ */
21
44
  testID?: string;
22
45
  /** The selected date. Controlled: update it from `onValueChange`. */
23
46
  value: Date;
@@ -1,2 +1,6 @@
1
1
  import type { DividerComponent } from './divider.types';
2
+ /**
3
+ * SwiftUI's divider, which turns with its stack: vertical in an `HStack`, horizontal anywhere else. So `axis`, which
4
+ * Android needs to pick its divider, has nothing to do here.
5
+ */
2
6
  export declare const Divider: DividerComponent;
@@ -1,10 +1,21 @@
1
1
  import type { ColorToken } from '@hzblj/kara-theme';
2
2
  import type { ReactNode } from 'react';
3
- /** A horizontal hairline: SwiftUI `Divider` / Compose `HorizontalDivider`. */
3
+ /** Which way the line runs. */
4
+ export type DividerAxis = 'horizontal' | 'vertical';
5
+ /**
6
+ * A hairline between views: SwiftUI `Divider` / Compose `HorizontalDivider`, or `VerticalDivider` with
7
+ * `axis="vertical"`.
8
+ */
4
9
  export type DividerProps = {
10
+ /**
11
+ * Which way the line runs. `horizontal` by default: across a `VStack`. `vertical` stands it up between the children
12
+ * of an `HStack`, as tall as the stack, so give the stack a height (`h`). iOS ignores it: SwiftUI's divider turns by
13
+ * itself, vertical in an `HStack` and horizontal anywhere else. Set it anyway, so Android draws the same.
14
+ */
15
+ axis?: DividerAxis;
5
16
  /** The line's colour. `border.tertiary` by default. */
6
17
  color?: ColorToken;
7
- /** Test identifier, forwarded to the native view on iOS. Android ignores it. */
18
+ /** Test identifier, forwarded to the native view. */
8
19
  testID?: string;
9
20
  };
10
21
  export type DividerComponent = (props: DividerProps) => ReactNode;
@@ -1,22 +1,39 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import type { IconName } from '../icon';
3
+ /** Material's three floating action buttons: 40, 56 and 96 across. */
4
+ export type FabSize = 'large' | 'regular' | 'small';
3
5
  /**
4
- * A floating action button: Material's `FloatingActionButton` on Android, a 56pt accent circle (a plain SwiftUI
5
- * `Button`) on iOS. It renders inline; pinning it to a corner is up to the screen.
6
+ * A floating action button: Material's `FloatingActionButton` on Android, an accent circle (a plain SwiftUI `Button`)
7
+ * on iOS. With a `label` it is the extended one, the icon and the text side by side: Material's
8
+ * `ExtendedFloatingActionButton`, an accent capsule on iOS. It renders inline; pinning it to a corner is up to the
9
+ * screen.
6
10
  */
7
11
  export type FabProps = {
8
12
  /**
9
13
  * What VoiceOver and TalkBack say for the button, since an icon has no words of its own: "Share", "Add to
10
- * favourites". Required for that reason.
14
+ * favourites". Required for that reason. With a `label` it is still what they say, in place of the label, so give
15
+ * it the label's words (or words that start with them), and Voice Control finds the button by what it shows.
11
16
  */
12
17
  accessibilityLabel: string;
13
18
  /** What pressing it does, when the label alone does not say. See `AccessibilityProps`. */
14
19
  accessibilityHint?: string;
20
+ /**
21
+ * Text beside the icon, which makes it an extended FAB: "Compose", "New post". For a screen whose main action needs
22
+ * its words. Material's `ExtendedFloatingActionButton` on Android; on iOS the same accent, 56pt tall, as a capsule.
23
+ */
24
+ label?: string;
15
25
  /** The icon, one of the app's, drawn in `content.on.accent`. */
16
26
  name: IconName;
17
27
  /** Called when the button is pressed. */
18
28
  onPress?: () => void;
19
- /** Test identifier, forwarded to the native view on iOS. Android ignores it. */
29
+ /**
30
+ * `regular` by default, 56 across. `small` is 40, for a secondary action beside a regular one; `large` is 96, with a
31
+ * 36 icon, for a screen built around one action. Material's `SmallFloatingActionButton` and
32
+ * `LargeFloatingActionButton` on Android, the same sizes of circle on iOS. A FAB with a `label` has one size and
33
+ * ignores it.
34
+ */
35
+ size?: FabSize;
36
+ /** Test identifier, forwarded to the native view. */
20
37
  testID?: string;
21
38
  };
22
39
  export type FabComponent = (props: FabProps) => ReactNode;
@@ -1,9 +1,15 @@
1
+ import type { ColorToken } from '@hzblj/kara-theme';
1
2
  import type { ReactNode } from 'react';
2
3
  import type { IconName } from '../icon';
3
4
  /**
4
- * A button that is just an icon: a plain SwiftUI `Button` on iOS, Material's `IconButton` on Android. The icon sits
5
- * centred in a tap target the size each platform asks for, 44pt on iOS and 48dp on Android, so a row of them spaces
6
- * itself the same way on both.
5
+ * How much the button stands out: just the icon (`plain`), on a fill in the accent (`filled`), on a muted fill
6
+ * (`tonal`), in a ring (`outlined`) or on Liquid Glass (`glass`).
7
+ */
8
+ export type IconButtonVariant = 'filled' | 'glass' | 'outlined' | 'plain' | 'tonal';
9
+ /**
10
+ * A button that is just an icon: a SwiftUI `Button` on iOS, one of Material's icon buttons on Android. A `plain` one
11
+ * sits centred in a tap target the size each platform asks for, 44pt on iOS and 48dp on Android, so a row of them
12
+ * spaces itself the same way on both; the other variants draw a circle around the icon.
7
13
  */
8
14
  export type IconButtonProps = {
9
15
  /**
@@ -13,13 +19,26 @@ export type IconButtonProps = {
13
19
  accessibilityLabel: string;
14
20
  /** What pressing it does, when the label alone does not say. See `AccessibilityProps`. */
15
21
  accessibilityHint?: string;
22
+ /**
23
+ * The icon's colour, `content.primary` by default. On `filled` it is the fill instead (`fill.accent.primary` by
24
+ * default) and the icon picks a colour that reads on it, as a `Button`'s `tint` does on a prominent style. On iOS a
25
+ * `tonal` button's circle takes a pale shade of it too.
26
+ */
27
+ color?: ColorToken;
16
28
  /** Dims the icon (iOS's own disabled look, `btn.content.disabled` on Android) and stops the button responding. */
17
29
  disabled?: boolean;
18
30
  /** The icon, one of the app's. */
19
31
  name: IconName;
20
32
  /** Called when the button is pressed. */
21
33
  onPress?: () => void;
22
- /** Test identifier, forwarded to the native view on iOS. Android ignores it. */
34
+ /** Test identifier, forwarded to the native view. */
23
35
  testID?: string;
36
+ /**
37
+ * The look. `plain` by default. iOS draws the others as SwiftUI button styles in a circle: `borderedProminent` for
38
+ * `filled`, `bordered` for `tonal`, `glass` for `glass` (`bordered` below iOS 26), and `outlined` as a plain button
39
+ * in a hairline ring. Android draws Material's `IconButton`, `FilledIconButton`, `FilledTonalIconButton` and
40
+ * `OutlinedIconButton`; Material has no glass, so there `glass` is the tonal one.
41
+ */
42
+ variant?: IconButtonVariant;
24
43
  };
25
44
  export type IconButtonComponent = (props: IconButtonProps) => ReactNode;
@@ -1,4 +1,6 @@
1
1
  import type { ReactNode } from 'react';
2
+ /** How the rows are laid out: in a rounded card inset from the edges, or edge to edge. */
3
+ export type ListVariant = 'insetGrouped' | 'plain';
2
4
  /**
3
5
  * A scrolling list: SwiftUI `List`, Compose `LazyColumn`. It has no height of its own, so it needs one from outside:
4
6
  * a `Screen`, or an `Island` with `matchContents={false}` and a height. In an island that sizes itself to its content
@@ -16,7 +18,19 @@ export type ListProps = {
16
18
  * until the promise settles, so neither platform needs a `refreshing` flag kept in sync by hand.
17
19
  */
18
20
  onRefresh?: () => Promise<void>;
19
- /** Test identifier, forwarded to the native view on iOS. Android ignores it. */
21
+ /**
22
+ * Draws a line between rows. On by default. Off, iOS hides SwiftUI's row separators and Android draws no `Divider`,
23
+ * for rows that carry their own spacing (cards, media).
24
+ */
25
+ separators?: boolean;
26
+ /** Test identifier, forwarded to the native view. */
20
27
  testID?: string;
28
+ /**
29
+ * The layout. Each platform's own list by default: `insetGrouped` on iOS, `plain` on Android. `insetGrouped` sets
30
+ * the rows in a rounded card inset from the edges (SwiftUI's `insetGrouped` list style; on Android a `Card` inside the
31
+ * column, the way `Form` draws its sections). `plain` runs the rows edge to edge (SwiftUI's `plain` style; Android's
32
+ * column as it is).
33
+ */
34
+ variant?: ListVariant;
21
35
  };
22
36
  export type ListComponent = (props: ListProps) => ReactNode;
@@ -1,7 +1,9 @@
1
1
  import type { PickerComponent } from './picker.types';
2
2
  /**
3
- * A SwiftUI wheel. On its own it is `@expo/ui`'s community picker, which brings a host of its own. Inside a `Screen` or
4
- * `Island` it is the same wheel rendered into that host instead (see `useInsideHost`): a host nested in the island's
5
- * stack is given no height there, and the wheel spills over the views around it.
3
+ * A SwiftUI picker: a wheel, or with `pickerStyle="menu"` a button with the selection that opens the options as a
4
+ * menu, in the accent. On its own the wheel is `@expo/ui`'s community picker, which brings a host of its own, and the
5
+ * menu sits in a host sized to its button on both axes, as the date picker's pill does, so it drops into a row the way
6
+ * a `Text` does. Inside a `Screen` or `Island` either renders into that host instead (see `useInsideHost`): a host
7
+ * nested in the island's stack is given no height there, and the wheel spills over the views around it.
6
8
  */
7
9
  export declare const Picker: PickerComponent;
@@ -6,10 +6,12 @@ export type PickerOption = {
6
6
  /** What `onValueChange` reports. It also keys the option, so it must be unique. */
7
7
  value: string;
8
8
  };
9
+ /** How SwiftUI shows the picker: a wheel, or a button that opens the options as a menu. */
10
+ export type PickerStyleName = 'menu' | 'wheel';
9
11
  /**
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. Inside one it renders into that host instead, so it
12
- * can share a stack with other native views.
12
+ * A single choice from a list: a SwiftUI picker on iOS (a wheel, or a menu with `pickerStyle`), Material's exposed
13
+ * dropdown on Android. It brings its own host, so it renders outside `Screen` and `Island` as well. Inside one it
14
+ * renders into that host instead, so it can share a stack with other native views.
13
15
  */
14
16
  export type PickerProps = {
15
17
  /** Stops the user changing the selection, and dims the picker. */
@@ -18,6 +20,12 @@ export type PickerProps = {
18
20
  onValueChange?: (value: string) => void;
19
21
  /** The choices, in order. */
20
22
  options: PickerOption[];
23
+ /**
24
+ * SwiftUI's picker style. `wheel` by default: the options on a wheel, always in view. `menu` is a button with the
25
+ * selection, in the accent, that opens the options as a menu: what a screen with more than one picker, or a picker
26
+ * in a row, wants. iOS only. Android ignores it: its exposed dropdown is a menu already.
27
+ */
28
+ pickerStyle?: PickerStyleName;
21
29
  /**
22
30
  * Android: the dropdown field's test tag. iOS: the wheel's, inside a `Screen` or `Island` only; on its own,
23
31
  * `@expo/ui`'s wheel picker drops it.
@@ -1,13 +1,24 @@
1
+ import type { ColorToken } from '@hzblj/kara-theme';
1
2
  import type { ReactNode } from 'react';
2
3
  /**
3
- * A progress bar or ring, tinted `fill.accent.primary`: SwiftUI `ProgressView` (a capacity `Gauge` for a ring with a
4
- * value, which `ProgressView` cannot draw on iOS) / Compose's `LinearProgressIndicator` and `CircularProgressIndicator`.
4
+ * A progress bar or ring, tinted `fill.accent.primary` unless `color` names another: SwiftUI `ProgressView` (a capacity
5
+ * `Gauge` for a ring with a value, which `ProgressView` cannot draw on iOS) / Compose's `LinearProgressIndicator` and
6
+ * `CircularProgressIndicator`.
5
7
  */
6
8
  export type ProgressProps = {
7
9
  /** What is in progress, for VoiceOver and TalkBack: "Uploading". They read how far along it is themselves. */
8
10
  accessibilityLabel?: string;
9
11
  /** A circular indicator instead of a bar. Off by default. */
10
12
  circular?: boolean;
13
+ /**
14
+ * Its colour: `fill.destructive.primary` for storage nearly full, `fill.success.primary` for a goal reached.
15
+ * `fill.accent.primary` by default. iOS tints the bar or ring with it. Android draws the indicator in it and, for any
16
+ * colour but the accent, the track in the same colour faded (Material's own track stays under the accent, and an
17
+ * indeterminate ring has none).
18
+ */
19
+ color?: ColorToken;
20
+ /** Test identifier, forwarded to the native view. */
21
+ testID?: string;
11
22
  /** Between `0` and `1`. Leave it unset for an indeterminate indicator. */
12
23
  value?: number;
13
24
  };
@@ -1,2 +1,6 @@
1
1
  import type { SliderComponent } from './slider.types';
2
+ /**
3
+ * SwiftUI's slider. `onValueChangeEnd` is its `onEditingChanged(false)`, with the last value the drag reported: the
4
+ * controlled `value` can still be a render behind when the finger lifts.
5
+ */
2
6
  export declare const Slider: SliderComponent;
@@ -9,8 +9,15 @@ export type SliderProps = {
9
9
  min?: number;
10
10
  /** Called with the new value as the thumb moves. */
11
11
  onValueChange?: (value: number) => void;
12
+ /**
13
+ * Called once with the final value when the user lets go of the slider: where a seek or a volume commits, rather
14
+ * than at every step of the drag.
15
+ */
16
+ onValueChangeEnd?: (value: number) => void;
12
17
  /** The increment between stops; leave it unset for a continuous slider. On Android every stop plays a `tick`. */
13
18
  step?: number;
19
+ /** Test identifier, forwarded to the native view. */
20
+ testID?: string;
14
21
  /** Between `min` and `max`. Controlled: pass back what `onValueChange` reports. */
15
22
  value: number;
16
23
  };
@@ -10,6 +10,8 @@ export type SwitchProps = {
10
10
  label?: string;
11
11
  /** Called with the new value when the user flips it. On Android a flip plays `toggleOn` / `toggleOff`. */
12
12
  onValueChange?: (value: boolean) => void;
13
+ /** Test identifier, forwarded to the native switch (on Android the switch itself, not the labelled row). */
14
+ testID?: string;
13
15
  /** Whether it is on. Controlled: pass back what `onValueChange` reports. */
14
16
  value: boolean;
15
17
  };
@@ -5,6 +5,8 @@ export type TextSpan = {
5
5
  color?: ColorToken;
6
6
  text: string;
7
7
  };
8
+ /** The string and number children, joined: the text of a `Text` without spans, however JSX split it. */
9
+ export declare const textOf: (children: ReactNode) => string;
8
10
  /**
9
11
  * The children as runs when any of them is a nested `Text` (`type`, the platform's own component), `null` when they
10
12
  * are only text. A span keeps its `color`; anything else it sets is the outer text's.
@@ -4,6 +4,8 @@ import type { ReactNode } from 'react';
4
4
  export type TextAlign = 'center' | 'left' | 'right';
5
5
  export type TextDecoration = 'none' | 'strikethrough' | 'underline';
6
6
  export type TextTransform = 'lowercase' | 'uppercase';
7
+ /** Where the ellipsis goes in a text cut short: its start, its middle or its end. */
8
+ export type TextTruncation = 'head' | 'middle' | 'tail';
7
9
  /**
8
10
  * SwiftUI `Text` / Compose `Text` in a theme typography variant. A native atom: outside a host, use `RnText`. It takes
9
11
  * the native `sx` surface too: padding, a frame (`wide` lines it up by `align`), a background, and the `ios` bucket's
@@ -29,7 +31,7 @@ export type TextProps = ResponsiveSx & AccessibilityProps & {
29
31
  color?: ColorToken;
30
32
  /** An underline or a strikethrough. */
31
33
  decoration?: TextDecoration;
32
- /** The most lines it wraps to. iOS truncates the last with an ellipsis; Android clips it. */
34
+ /** The most lines it wraps to. A text cut short ends with an ellipsis, where `truncation` puts it. */
33
35
  numberOfLines?: number;
34
36
  /**
35
37
  * Sets it in the theme's fixed-width face, at the variant's size and weight: the app's `fonts.mono`, else Menlo on
@@ -46,6 +48,12 @@ export type TextProps = ResponsiveSx & AccessibilityProps & {
46
48
  testID?: string;
47
49
  /** Upper- or lower-cases the text. Android applies it only when `children` is a plain string. */
48
50
  transform?: TextTransform;
51
+ /**
52
+ * Where the ellipsis goes in a text cut short. `tail` by default: the end of the last line. `head` keeps the end of
53
+ * the text and `middle` both of its ends, for a file name, a path or an address. Android puts it at the head or in
54
+ * the middle of a single line only (`numberOfLines={1}`), as Compose does; a longer text there ends at the tail.
55
+ */
56
+ truncation?: TextTruncation;
49
57
  /** The typography variant. `body` by default. */
50
58
  variant?: TextVariant;
51
59
  };
@@ -0,0 +1,7 @@
1
+ import type { TextFieldAutoCapitalize, TextFieldKeyboard } from './text-field.types';
2
+ /** The capitalisation asked for, else `none` for an address; `undefined` leaves the platform's own. */
3
+ export declare const capitalizationFor: (keyboard: TextFieldKeyboard, autoCapitalize: TextFieldAutoCapitalize | undefined) => TextFieldAutoCapitalize | undefined;
4
+ /** Autocorrection as asked for, else on for everything but an address. */
5
+ export declare const autoCorrectFor: (keyboard: TextFieldKeyboard, autoCorrect: boolean | undefined) => boolean;
6
+ /** A no-op for a ref call that lands after the native view has gone. */
7
+ export declare const ignoreDetachedView: () => undefined;
@@ -1,9 +1,50 @@
1
- import type { ReactNode } from 'react';
1
+ import type { ReactNode, Ref } from 'react';
2
+ /** The keyboard a field brings up. */
3
+ export type TextFieldKeyboard = 'decimal' | 'default' | 'email' | 'number' | 'phone' | 'url';
4
+ /** When the keyboard turns Shift on by itself. */
5
+ export type TextFieldAutoCapitalize = 'characters' | 'none' | 'sentences' | 'words';
6
+ /** What the return key says. */
7
+ export type TextFieldSubmitLabel = 'done' | 'go' | 'next' | 'search' | 'send';
8
+ /**
9
+ * What a field holds, so the system can offer to fill it in: an account's email or password, a new strong password,
10
+ * the code from a text message, the user's own name, phone number or address.
11
+ */
12
+ export type TextFieldContentType = 'addressCity' | 'countryName' | 'creditCardNumber' | 'emailAddress' | 'familyName' | 'fullStreetAddress' | 'givenName' | 'name' | 'newPassword' | 'oneTimeCode' | 'password' | 'postalCode' | 'streetAddressLine1' | 'streetAddressLine2' | 'telephoneNumber' | 'username';
13
+ /** Drives a `TextField` from code, as when `onSubmit` moves on to the next field. */
14
+ export type TextFieldRef = {
15
+ /** Ends editing: the field gives up focus and the keyboard goes down. */
16
+ blur: () => void;
17
+ /** Empties the field and calls `onChangeText` with `''`. */
18
+ clear: () => void;
19
+ /** Starts editing: the field takes focus and brings up the keyboard. */
20
+ focus: () => void;
21
+ };
2
22
  /**
3
23
  * An uncontrolled text field with an optional label above it: SwiftUI `TextField` (`SecureField` when `secure`) /
4
- * Compose `OutlinedTextField`.
24
+ * Compose `OutlinedTextField`. `keyboard`, `autoCapitalize`, `autoCorrect` and `contentType` fit it to the text it
25
+ * takes; `submitLabel`, `onSubmit` and `ref` chain fields so the return key moves on to the next.
5
26
  */
6
27
  export type TextFieldProps = {
28
+ /**
29
+ * When the keyboard turns Shift on by itself: never (`none`), at the start of `sentences`, of `words`, or for all
30
+ * `characters`. Unset, it is `none` for the `email` and `url` keyboards, and otherwise each platform's own:
31
+ * `sentences` on iOS, `none` on Android.
32
+ */
33
+ autoCapitalize?: TextFieldAutoCapitalize;
34
+ /**
35
+ * Lets the keyboard correct words as they are typed and suggest the next. On unless the keyboard is `email` or
36
+ * `url`, where a correction would only break an address. A `secure` field never corrects.
37
+ */
38
+ autoCorrect?: boolean;
39
+ /** Takes focus, and brings up the keyboard, as soon as the field appears. Off by default. */
40
+ autoFocus?: boolean;
41
+ /**
42
+ * What the field holds, so the system can offer to fill it in: a saved `username` or `password` from the keychain
43
+ * or a password manager, a strong `newPassword` for a sign-up, the `oneTimeCode` from a text message, the user's own
44
+ * `emailAddress`, `name`, `telephoneNumber` or address. iOS's `textContentType`; on Android a Compose autofill
45
+ * hint, which an autofill service (Google's, a password manager) answers.
46
+ */
47
+ contentType?: TextFieldContentType;
7
48
  /** The text it starts with. Read once, on mount: the field is uncontrolled. */
8
49
  defaultValue?: string;
9
50
  /** Stops editing and dims the field. On iOS it outranks `error`. */
@@ -14,15 +55,47 @@ export type TextFieldProps = {
14
55
  * colour is a pale red in dark mode. `true` marks it without a message.
15
56
  */
16
57
  error?: boolean | string;
58
+ /**
59
+ * The keyboard it brings up. `default` by default. `email` and `url` add their `@` and `.` keys and turn
60
+ * capitals and corrections off unless `autoCapitalize` or `autoCorrect` say otherwise; `number` is a pad of digits,
61
+ * `decimal` adds the locale's decimal separator, `phone` is a dial pad. With `secure`, Android brings up its password
62
+ * keyboard (a numeric one for `number`).
63
+ */
64
+ keyboard?: TextFieldKeyboard;
17
65
  /** Shown above the field, in `labelMedium`. */
18
66
  label?: string;
67
+ /**
68
+ * The most characters it takes. What is typed past it is cut off as the user types; `defaultValue` is not. No limit
69
+ * by default.
70
+ */
71
+ maxLength?: number;
19
72
  /** Wraps the text and grows the field to fit it. iOS ignores it when `secure`. */
20
73
  multiline?: boolean;
21
- /** Called with the whole text after every change. */
74
+ /** Called with the whole text after every change, `clear()` included. */
22
75
  onChangeText?: (text: string) => void;
76
+ /** Called with `true` when the field starts editing and `false` when it stops. */
77
+ onFocusChange?: (focused: boolean) => void;
78
+ /**
79
+ * Called with the whole text when the return key is pressed. A `multiline` field never calls it: its return key
80
+ * starts a new line. Neither do iOS's `number`, `decimal` and `phone` pads, which have no return key.
81
+ */
82
+ onSubmit?: (text: string) => void;
83
+ /**
84
+ * Shown in the empty field, in the platform's placeholder colour, until the first character is typed. A hint at
85
+ * the format (`name@example.com`), not a replacement for `label`.
86
+ */
87
+ placeholder?: string;
88
+ /** `focus`, `blur` and `clear`, for moving to the next field from `onSubmit`. */
89
+ ref?: Ref<TextFieldRef>;
23
90
  /** Masks the text, for a password. */
24
91
  secure?: boolean;
25
- /** iOS: forwarded to the native field. Android ignores it. */
92
+ /**
93
+ * What the return key says. Unset, each platform's own (`return` on iOS). It names the key; what pressing it does
94
+ * is up to `onSubmit`, so a `next` focuses the following field through its `ref`. Android's `next` also moves focus
95
+ * to the next field in the same host by itself. A `multiline` field ignores it: its return key starts a new line.
96
+ */
97
+ submitLabel?: TextFieldSubmitLabel;
98
+ /** Test identifier, forwarded to the native field (not the label above it). */
26
99
  testID?: string;
27
100
  };
28
101
  export type TextFieldComponent = (props: TextFieldProps) => ReactNode;
@@ -12,5 +12,7 @@ export type CollapsibleProps = {
12
12
  label: string;
13
13
  /** The user pressed the row; it passes the state the row asks for. */
14
14
  onExpandedChange: (expanded: boolean) => void;
15
+ /** Test identifier: on SwiftUI's `DisclosureGroup` on iOS, on the pressable row on Android. */
16
+ testID?: string;
15
17
  };
16
18
  export type CollapsibleComponent = (props: CollapsibleProps) => ReactNode;
@@ -11,10 +11,14 @@ export type RadioOption = {
11
11
  * native atom: it renders inside `<Screen>` or `<Island>`.
12
12
  */
13
13
  export type RadioGroupProps = {
14
+ /** Stops the user changing the selection, and dims the options. */
15
+ disabled?: boolean;
14
16
  /** The user pressed an option; it passes that option's `value`. */
15
17
  onValueChange?: (value: string) => void;
16
18
  /** The choices, top to bottom. */
17
19
  options: RadioOption[];
20
+ /** Test identifier, on the whole group. Reach an option by its label. */
21
+ testID?: string;
18
22
  /** The selected option's `value`. Update it from `onValueChange`. */
19
23
  value: string;
20
24
  };