react-native-platform-components 1.3.0 → 1.4.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 (181) hide show
  1. package/README.md +24 -30
  2. package/android/src/main/java/com/platformcomponents/PCButtonGroupView.kt +498 -0
  3. package/android/src/main/java/com/platformcomponents/PCButtonGroupViewManager.kt +191 -0
  4. package/android/src/main/java/com/platformcomponents/PCButtonSupport.kt +127 -0
  5. package/android/src/main/java/com/platformcomponents/PCButtonView.kt +345 -0
  6. package/android/src/main/java/com/platformcomponents/PCButtonViewManager.kt +126 -0
  7. package/android/src/main/java/com/platformcomponents/PCExpressive.kt +107 -0
  8. package/android/src/main/java/com/platformcomponents/PCFloatingToolbarView.kt +115 -0
  9. package/android/src/main/java/com/platformcomponents/PCFloatingToolbarViewManager.kt +65 -0
  10. package/android/src/main/java/com/platformcomponents/PCSegmentedControlView.kt +11 -3
  11. package/android/src/main/java/com/platformcomponents/PCSegmentedControlViewManager.kt +6 -1
  12. package/android/src/main/java/com/platformcomponents/PCTextFieldView.kt +1018 -0
  13. package/android/src/main/java/com/platformcomponents/PCTextFieldViewManager.kt +248 -0
  14. package/android/src/main/java/com/platformcomponents/PlatformComponentsPackage.kt +4 -0
  15. package/android/src/main/res/values/attrs.xml +13 -0
  16. package/android/src/main/res/values/styles.xml +183 -0
  17. package/ios/PCButton.h +10 -0
  18. package/ios/PCButton.mm +196 -0
  19. package/ios/PCButtonGroup.h +10 -0
  20. package/ios/PCButtonGroup.mm +256 -0
  21. package/ios/PCButtonGroupView.swift +254 -0
  22. package/ios/PCButtonSupport.swift +141 -0
  23. package/ios/PCButtonView.swift +155 -0
  24. package/ios/PCFloatingToolbar.h +10 -0
  25. package/ios/PCFloatingToolbar.mm +76 -0
  26. package/ios/PCFloatingToolbarView.swift +95 -0
  27. package/ios/PCTextField.h +10 -0
  28. package/ios/PCTextField.mm +391 -0
  29. package/ios/PCTextFieldView.swift +1012 -0
  30. package/lib/commonjs/Button.js +77 -0
  31. package/lib/commonjs/Button.js.map +1 -0
  32. package/lib/commonjs/ButtonGroup.js +99 -0
  33. package/lib/commonjs/ButtonGroup.js.map +1 -0
  34. package/lib/commonjs/ButtonGroupNativeComponent.ts +121 -0
  35. package/lib/commonjs/ButtonNativeComponent.ts +76 -0
  36. package/lib/commonjs/FloatingToolbar.js +69 -0
  37. package/lib/commonjs/FloatingToolbar.js.map +1 -0
  38. package/lib/commonjs/FloatingToolbarNativeComponent.ts +31 -0
  39. package/lib/commonjs/SegmentedControl.js +11 -85
  40. package/lib/commonjs/SegmentedControl.js.map +1 -1
  41. package/lib/commonjs/SegmentedControlNativeComponent.ts +3 -0
  42. package/lib/commonjs/TextField.js +195 -0
  43. package/lib/commonjs/TextField.js.map +1 -0
  44. package/lib/commonjs/TextFieldNativeComponent.ts +218 -0
  45. package/lib/commonjs/focusRegistry.js +78 -0
  46. package/lib/commonjs/focusRegistry.js.map +1 -0
  47. package/lib/commonjs/icons.js +92 -0
  48. package/lib/commonjs/icons.js.map +1 -0
  49. package/lib/commonjs/index.js +66 -0
  50. package/lib/commonjs/index.js.map +1 -1
  51. package/lib/commonjs/index.web.js +32 -2
  52. package/lib/commonjs/index.web.js.map +1 -1
  53. package/lib/commonjs/labelStyle.js +27 -0
  54. package/lib/commonjs/labelStyle.js.map +1 -0
  55. package/lib/commonjs/reactNativeInternals.d.js +2 -0
  56. package/lib/commonjs/reactNativeInternals.d.js.map +1 -0
  57. package/lib/module/Button.js +70 -0
  58. package/lib/module/Button.js.map +1 -0
  59. package/lib/module/ButtonGroup.js +92 -0
  60. package/lib/module/ButtonGroup.js.map +1 -0
  61. package/lib/module/ButtonGroupNativeComponent.ts +121 -0
  62. package/lib/module/ButtonNativeComponent.ts +76 -0
  63. package/lib/module/FloatingToolbar.js +62 -0
  64. package/lib/module/FloatingToolbar.js.map +1 -0
  65. package/lib/module/FloatingToolbarNativeComponent.ts +31 -0
  66. package/lib/module/SegmentedControl.js +12 -87
  67. package/lib/module/SegmentedControl.js.map +1 -1
  68. package/lib/module/SegmentedControlNativeComponent.ts +3 -0
  69. package/lib/module/TextField.js +189 -0
  70. package/lib/module/TextField.js.map +1 -0
  71. package/lib/module/TextFieldNativeComponent.ts +218 -0
  72. package/lib/module/focusRegistry.js +74 -0
  73. package/lib/module/focusRegistry.js.map +1 -0
  74. package/lib/module/icons.js +87 -0
  75. package/lib/module/icons.js.map +1 -0
  76. package/lib/module/index.js +6 -0
  77. package/lib/module/index.js.map +1 -1
  78. package/lib/module/index.web.js +28 -0
  79. package/lib/module/index.web.js.map +1 -1
  80. package/lib/module/labelStyle.js +23 -0
  81. package/lib/module/labelStyle.js.map +1 -0
  82. package/lib/module/reactNativeInternals.d.js +2 -0
  83. package/lib/module/reactNativeInternals.d.js.map +1 -0
  84. package/lib/typescript/commonjs/docs/sidebars.d.ts.map +1 -1
  85. package/lib/typescript/commonjs/src/Button.d.ts +76 -0
  86. package/lib/typescript/commonjs/src/Button.d.ts.map +1 -0
  87. package/lib/typescript/commonjs/src/ButtonGroup.d.ts +102 -0
  88. package/lib/typescript/commonjs/src/ButtonGroup.d.ts.map +1 -0
  89. package/lib/typescript/commonjs/src/ButtonGroupNativeComponent.d.ts +93 -0
  90. package/lib/typescript/commonjs/src/ButtonGroupNativeComponent.d.ts.map +1 -0
  91. package/lib/typescript/commonjs/src/ButtonNativeComponent.d.ts +57 -0
  92. package/lib/typescript/commonjs/src/ButtonNativeComponent.d.ts.map +1 -0
  93. package/lib/typescript/commonjs/src/FloatingToolbar.d.ts +45 -0
  94. package/lib/typescript/commonjs/src/FloatingToolbar.d.ts.map +1 -0
  95. package/lib/typescript/commonjs/src/FloatingToolbarNativeComponent.d.ts +24 -0
  96. package/lib/typescript/commonjs/src/FloatingToolbarNativeComponent.d.ts.map +1 -0
  97. package/lib/typescript/commonjs/src/SegmentedControl.d.ts +17 -46
  98. package/lib/typescript/commonjs/src/SegmentedControl.d.ts.map +1 -1
  99. package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts +2 -0
  100. package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts.map +1 -1
  101. package/lib/typescript/commonjs/src/TextField.d.ts +174 -0
  102. package/lib/typescript/commonjs/src/TextField.d.ts.map +1 -0
  103. package/lib/typescript/commonjs/src/TextFieldNativeComponent.d.ts +162 -0
  104. package/lib/typescript/commonjs/src/TextFieldNativeComponent.d.ts.map +1 -0
  105. package/lib/typescript/commonjs/src/focusRegistry.d.ts +13 -0
  106. package/lib/typescript/commonjs/src/focusRegistry.d.ts.map +1 -0
  107. package/lib/typescript/commonjs/src/icons.d.ts +52 -0
  108. package/lib/typescript/commonjs/src/icons.d.ts.map +1 -0
  109. package/lib/typescript/commonjs/src/index.d.ts +6 -0
  110. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  111. package/lib/typescript/commonjs/src/index.web.d.ts +121 -0
  112. package/lib/typescript/commonjs/src/index.web.d.ts.map +1 -1
  113. package/lib/typescript/commonjs/src/labelStyle.d.ts +20 -0
  114. package/lib/typescript/commonjs/src/labelStyle.d.ts.map +1 -0
  115. package/lib/typescript/commonjs/src/sharedTypes.d.ts +6 -1
  116. package/lib/typescript/commonjs/src/sharedTypes.d.ts.map +1 -1
  117. package/lib/typescript/module/docs/sidebars.d.ts.map +1 -1
  118. package/lib/typescript/module/src/Button.d.ts +76 -0
  119. package/lib/typescript/module/src/Button.d.ts.map +1 -0
  120. package/lib/typescript/module/src/ButtonGroup.d.ts +102 -0
  121. package/lib/typescript/module/src/ButtonGroup.d.ts.map +1 -0
  122. package/lib/typescript/module/src/ButtonGroupNativeComponent.d.ts +93 -0
  123. package/lib/typescript/module/src/ButtonGroupNativeComponent.d.ts.map +1 -0
  124. package/lib/typescript/module/src/ButtonNativeComponent.d.ts +57 -0
  125. package/lib/typescript/module/src/ButtonNativeComponent.d.ts.map +1 -0
  126. package/lib/typescript/module/src/FloatingToolbar.d.ts +45 -0
  127. package/lib/typescript/module/src/FloatingToolbar.d.ts.map +1 -0
  128. package/lib/typescript/module/src/FloatingToolbarNativeComponent.d.ts +24 -0
  129. package/lib/typescript/module/src/FloatingToolbarNativeComponent.d.ts.map +1 -0
  130. package/lib/typescript/module/src/SegmentedControl.d.ts +17 -46
  131. package/lib/typescript/module/src/SegmentedControl.d.ts.map +1 -1
  132. package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts +2 -0
  133. package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts.map +1 -1
  134. package/lib/typescript/module/src/TextField.d.ts +174 -0
  135. package/lib/typescript/module/src/TextField.d.ts.map +1 -0
  136. package/lib/typescript/module/src/TextFieldNativeComponent.d.ts +162 -0
  137. package/lib/typescript/module/src/TextFieldNativeComponent.d.ts.map +1 -0
  138. package/lib/typescript/module/src/focusRegistry.d.ts +13 -0
  139. package/lib/typescript/module/src/focusRegistry.d.ts.map +1 -0
  140. package/lib/typescript/module/src/icons.d.ts +52 -0
  141. package/lib/typescript/module/src/icons.d.ts.map +1 -0
  142. package/lib/typescript/module/src/index.d.ts +6 -0
  143. package/lib/typescript/module/src/index.d.ts.map +1 -1
  144. package/lib/typescript/module/src/index.web.d.ts +121 -0
  145. package/lib/typescript/module/src/index.web.d.ts.map +1 -1
  146. package/lib/typescript/module/src/labelStyle.d.ts +20 -0
  147. package/lib/typescript/module/src/labelStyle.d.ts.map +1 -0
  148. package/lib/typescript/module/src/sharedTypes.d.ts +6 -1
  149. package/lib/typescript/module/src/sharedTypes.d.ts.map +1 -1
  150. package/package.json +25 -4
  151. package/react-native.config.js +3 -0
  152. package/shared/PCButtonComponentDescriptors-custom.h +22 -0
  153. package/shared/PCButtonGroupComponentDescriptors-custom.h +22 -0
  154. package/shared/PCButtonGroupShadowNode-custom.cpp +48 -0
  155. package/shared/PCButtonGroupShadowNode-custom.h +55 -0
  156. package/shared/PCButtonGroupState-custom.h +61 -0
  157. package/shared/PCButtonShadowNode-custom.cpp +48 -0
  158. package/shared/PCButtonShadowNode-custom.h +55 -0
  159. package/shared/PCButtonState-custom.h +61 -0
  160. package/shared/PCTextFieldComponentDescriptors-custom.h +22 -0
  161. package/shared/PCTextFieldShadowNode-custom.cpp +47 -0
  162. package/shared/PCTextFieldShadowNode-custom.h +55 -0
  163. package/shared/PCTextFieldState-custom.h +61 -0
  164. package/shared/react/renderer/components/PlatformComponentsViewSpec/ComponentDescriptors.h +3 -0
  165. package/src/Button.tsx +144 -0
  166. package/src/ButtonGroup.tsx +233 -0
  167. package/src/ButtonGroupNativeComponent.ts +121 -0
  168. package/src/ButtonNativeComponent.ts +76 -0
  169. package/src/FloatingToolbar.tsx +113 -0
  170. package/src/FloatingToolbarNativeComponent.ts +31 -0
  171. package/src/SegmentedControl.tsx +26 -118
  172. package/src/SegmentedControlNativeComponent.ts +3 -0
  173. package/src/TextField.tsx +494 -0
  174. package/src/TextFieldNativeComponent.ts +218 -0
  175. package/src/focusRegistry.ts +89 -0
  176. package/src/icons.ts +116 -0
  177. package/src/index.tsx +6 -0
  178. package/src/index.web.tsx +194 -0
  179. package/src/labelStyle.ts +36 -0
  180. package/src/reactNativeInternals.d.ts +22 -0
  181. package/src/sharedTypes.ts +7 -1
@@ -0,0 +1,89 @@
1
+ // focusRegistry.ts
2
+ //
3
+ // TextField's link to React Native's focused-input bookkeeping. The core
4
+ // TextInput registers its host node with `TextInputState`, and that registry is
5
+ // what `Keyboard.dismiss()`, a ScrollView's `keyboardShouldPersistTaps` and
6
+ // `keyboardDismissMode`, and `KeyboardAvoidingView` act on. Registering the
7
+ // same way makes a TextField behave like a TextInput for all of them.
8
+ //
9
+ // `TextInputState` is a stable internal (it has kept this shape since 0.63),
10
+ // but React Native's Babel preset adds a dev-time warning to every static
11
+ // `import` or `require` of a deep path. A dynamic `import()` is resolved by
12
+ // Metro the same way and carries no warning; it settles in a microtask at
13
+ // startup, so a node registered before then is kept and registered once the
14
+ // module arrives. If a future release drops the path, the registry is simply
15
+ // absent and the field falls back to the public `TextInput.State` calls for
16
+ // focus and blur, keeping `Keyboard.dismiss()` working.
17
+ import { TextInput } from 'react-native';
18
+
19
+ type HostNode = object;
20
+
21
+ type Registry = {
22
+ currentlyFocusedInput(): HostNode | null | undefined;
23
+ focusInput(input: HostNode | null | undefined): void;
24
+ blurInput(input: HostNode | null | undefined): void;
25
+ registerInput(input: HostNode): void;
26
+ unregisterInput(input: HostNode): void;
27
+ isTextInput(input: HostNode): boolean;
28
+ };
29
+
30
+ let registry: Registry | undefined;
31
+ const pendingRegistrations = new Set<HostNode>();
32
+
33
+ // A stable internal without a public counterpart; see reactNativeInternals.d.ts.
34
+
35
+ import('react-native/Libraries/Components/TextInput/TextInputState')
36
+ .then((module) => {
37
+ registry = module.default;
38
+ pendingRegistrations.forEach((node) => registry?.registerInput(node));
39
+ pendingRegistrations.clear();
40
+ })
41
+ .catch(() => {
42
+ // Not available: focus and blur still go through TextInput.State below.
43
+ });
44
+
45
+ export const focusRegistry = {
46
+ /** Called when the field mounts. */
47
+ register(node: HostNode): void {
48
+ if (registry) {
49
+ registry.registerInput(node);
50
+ } else {
51
+ pendingRegistrations.add(node);
52
+ }
53
+ },
54
+
55
+ /** Called when the field unmounts; drops the focus if the field held it. */
56
+ unregister(node: HostNode): void {
57
+ pendingRegistrations.delete(node);
58
+ if (registry) {
59
+ registry.unregisterInput(node);
60
+ if (registry.currentlyFocusedInput() === node) {
61
+ registry.blurInput(node);
62
+ }
63
+ } else if (TextInput.State.currentlyFocusedInput() === node) {
64
+ TextInput.State.blurTextInput(node as never);
65
+ }
66
+ },
67
+
68
+ /** The field gained focus natively. */
69
+ focused(node: HostNode | null): void {
70
+ if (node == null) return;
71
+ if (registry) {
72
+ registry.focusInput(node);
73
+ } else {
74
+ // Also re-sends the focus command, which the focused field ignores
75
+ TextInput.State.focusTextInput(node as never);
76
+ }
77
+ },
78
+
79
+ /** The field lost focus natively. */
80
+ blurred(node: HostNode | null): void {
81
+ if (node == null) return;
82
+ if (registry) {
83
+ registry.blurInput(node);
84
+ } else {
85
+ // Also re-sends the blur command, which the unfocused field ignores
86
+ TextInput.State.blurTextInput(node as never);
87
+ }
88
+ },
89
+ };
package/src/icons.ts ADDED
@@ -0,0 +1,116 @@
1
+ // icons.ts
2
+ //
3
+ // Icon props shared by SegmentedControl, Button and ButtonGroup. Icons are
4
+ // resolved on the JS side so native only deals with flat strings.
5
+ import {
6
+ Image,
7
+ Platform,
8
+ type ImageRequireSource,
9
+ type ImageURISource,
10
+ } from 'react-native';
11
+
12
+ /**
13
+ * A single icon source.
14
+ *
15
+ * - `string`: shorthand for an SF Symbol name on iOS and a drawable resource
16
+ * name on Android.
17
+ * - `{ type: 'sfSymbol' }`: an SF Symbol. iOS only; ignored on Android.
18
+ * - `{ type: 'drawable' }`: a drawable from the app's `res/drawable`.
19
+ * Android only; ignored on iOS.
20
+ * - `{ type: 'image' }`: an image asset (`require('./icon.png')`) or a
21
+ * `{ uri }` source. Works on both platforms. Images are drawn as tinted
22
+ * templates unless `tinted` is `false`.
23
+ */
24
+ export type PlatformIconSource =
25
+ | string
26
+ | { type: 'sfSymbol'; name: string }
27
+ | { type: 'drawable'; name: string }
28
+ | {
29
+ type: 'image';
30
+ source: ImageRequireSource | ImageURISource;
31
+ tinted?: boolean;
32
+ };
33
+
34
+ /**
35
+ * An icon: a single source used on both platforms, or a per-platform pair so
36
+ * callers don't need to branch on `Platform.OS`.
37
+ */
38
+ export type PlatformIcon =
39
+ | PlatformIconSource
40
+ | {
41
+ ios?: PlatformIconSource;
42
+ android?: PlatformIconSource;
43
+ };
44
+
45
+ /** The flat icon fields the native specs expect. */
46
+ export type NativeIconFields = {
47
+ /** '' | 'sfSymbol' | 'drawable' | 'image' */
48
+ iconType: string;
49
+ /** SF Symbol (iOS) or drawable resource name (Android) */
50
+ iconName: string;
51
+ /** Resolved image URI when iconType === 'image' */
52
+ iconUri: string;
53
+ /** Resolved image scale when iconType === 'image' */
54
+ iconScale: number;
55
+ /** 'true' | 'false': draw the image as a tinted template */
56
+ iconTinted: string;
57
+ };
58
+
59
+ export const NO_ICON: NativeIconFields = {
60
+ iconType: '',
61
+ iconName: '',
62
+ iconUri: '',
63
+ iconScale: 1,
64
+ iconTinted: 'true',
65
+ };
66
+
67
+ function pickIconSource(
68
+ icon: PlatformIcon | undefined
69
+ ): PlatformIconSource | undefined {
70
+ if (icon === undefined || typeof icon === 'string' || 'type' in icon) {
71
+ return icon;
72
+ }
73
+ return Platform.OS === 'ios' ? icon.ios : icon.android;
74
+ }
75
+
76
+ /**
77
+ * Flattens the public icon shape into the strings native expects, dropping
78
+ * sources that don't apply to the current platform.
79
+ */
80
+ export function resolveIcon(icon: PlatformIcon | undefined): NativeIconFields {
81
+ const source = pickIconSource(icon);
82
+ if (source === undefined) return NO_ICON;
83
+
84
+ if (typeof source === 'string') {
85
+ if (source.length === 0) return NO_ICON;
86
+ return {
87
+ ...NO_ICON,
88
+ iconType: Platform.OS === 'ios' ? 'sfSymbol' : 'drawable',
89
+ iconName: source,
90
+ };
91
+ }
92
+
93
+ switch (source.type) {
94
+ case 'sfSymbol':
95
+ return Platform.OS === 'ios'
96
+ ? { ...NO_ICON, iconType: 'sfSymbol', iconName: source.name }
97
+ : NO_ICON;
98
+ case 'drawable':
99
+ return Platform.OS === 'android'
100
+ ? { ...NO_ICON, iconType: 'drawable', iconName: source.name }
101
+ : NO_ICON;
102
+ case 'image': {
103
+ const resolved = Image.resolveAssetSource(source.source);
104
+ if (!resolved?.uri) return NO_ICON;
105
+ return {
106
+ iconType: 'image',
107
+ iconName: '',
108
+ iconUri: resolved.uri,
109
+ iconScale: resolved.scale > 0 ? resolved.scale : 1,
110
+ iconTinted: source.tinted === false ? 'false' : 'true',
111
+ };
112
+ }
113
+ default:
114
+ return NO_ICON;
115
+ }
116
+ }
package/src/index.tsx CHANGED
@@ -2,6 +2,12 @@ export * from './DatePicker';
2
2
  export * from './SelectionMenu';
3
3
  export * from './ContextMenu';
4
4
  export * from './SegmentedControl';
5
+ export * from './Button';
6
+ export * from './ButtonGroup';
7
+ export * from './FloatingToolbar';
5
8
  export * from './LiquidGlass';
9
+ export * from './TextField';
10
+ export * from './icons';
11
+ export * from './labelStyle';
6
12
  export * from './sharedTypes';
7
13
  export * from './NativeTheme';
package/src/index.web.tsx CHANGED
@@ -6,6 +6,8 @@
6
6
  import React from 'react';
7
7
  import type { ReactNode } from 'react';
8
8
  import type { ColorValue, StyleProp, ViewStyle, ViewProps } from 'react-native';
9
+ import type { PlatformIcon } from './icons';
10
+ import type { LabelStyle } from './labelStyle';
9
11
 
10
12
  // ============================================================================
11
13
  // Shared Types (duplicated to avoid importing from files with native deps)
@@ -164,6 +166,90 @@ export const SegmentedControl = (
164
166
  _props: SegmentedControlProps
165
167
  ): React.ReactElement | null => null;
166
168
 
169
+ // ============================================================================
170
+ // Button, ButtonGroup, FloatingToolbar
171
+ // ============================================================================
172
+
173
+ export type {
174
+ PlatformIcon,
175
+ PlatformIconSource,
176
+ NativeIconFields,
177
+ } from './icons';
178
+ export type { LabelStyle, NativeLabelStyle } from './labelStyle';
179
+
180
+ export type ButtonVariant =
181
+ 'filled' | 'tonal' | 'outlined' | 'text' | 'elevated';
182
+ export type ButtonSize = 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge';
183
+ export type ButtonShape = 'round' | 'square';
184
+
185
+ export interface ButtonProps extends ViewProps {
186
+ label?: string;
187
+ icon?: PlatformIcon;
188
+ variant?: ButtonVariant;
189
+ size?: ButtonSize;
190
+ shape?: ButtonShape;
191
+ disabled?: boolean;
192
+ color?: ColorValue;
193
+ tintColor?: ColorValue;
194
+ labelStyle?: LabelStyle;
195
+ accessibilityLabel?: string;
196
+ onPress?: () => void;
197
+ android?: Record<string, unknown>;
198
+ }
199
+
200
+ export const Button = (_props: ButtonProps): React.ReactElement | null => null;
201
+
202
+ export type ButtonGroupSelection = 'none' | 'single' | 'multiple';
203
+ export type ButtonGroupOverflow = 'none' | 'menu' | 'wrap';
204
+
205
+ export interface ButtonGroupButtonProps {
206
+ label?: string;
207
+ value: string;
208
+ disabled?: boolean;
209
+ icon?: PlatformIcon;
210
+ accessibilityLabel?: string;
211
+ }
212
+
213
+ export interface ButtonGroupProps extends ViewProps {
214
+ buttons: readonly ButtonGroupButtonProps[];
215
+ variant?: ButtonVariant;
216
+ size?: ButtonSize;
217
+ shape?: ButtonShape;
218
+ connected?: boolean;
219
+ spacing?: number;
220
+ selection?: ButtonGroupSelection;
221
+ selectedValues?: readonly string[];
222
+ selectionRequired?: boolean;
223
+ disabled?: boolean;
224
+ color?: ColorValue;
225
+ tintColor?: ColorValue;
226
+ labelStyle?: LabelStyle;
227
+ onPress?: (value: string, index: number) => void;
228
+ onSelectionChange?: (values: string[]) => void;
229
+ android?: Record<string, unknown>;
230
+ }
231
+
232
+ export const ButtonGroup = (
233
+ _props: ButtonGroupProps
234
+ ): React.ReactElement | null => null;
235
+
236
+ export type FloatingToolbarIOSEffect = 'regular' | 'clear';
237
+ export type FloatingToolbarAndroidVariant = 'standard' | 'vibrant';
238
+
239
+ export interface FloatingToolbarProps extends ViewProps {
240
+ orientation?: 'horizontal' | 'vertical';
241
+ color?: ColorValue;
242
+ ios?: Record<string, unknown>;
243
+ android?: Record<string, unknown>;
244
+ children?: ReactNode;
245
+ }
246
+
247
+ export const FloatingToolbar = ({
248
+ children,
249
+ }: FloatingToolbarProps): React.ReactElement | null => {
250
+ return <>{children}</>;
251
+ };
252
+
167
253
  // ============================================================================
168
254
  // LiquidGlass
169
255
  // ============================================================================
@@ -183,6 +269,114 @@ export const LiquidGlass = ({
183
269
 
184
270
  export const isLiquidGlassSupported = false;
185
271
 
272
+ // ============================================================================
273
+ // TextField
274
+ // ============================================================================
275
+
276
+ export type TextFieldKeyboardType =
277
+ | 'default'
278
+ | 'number-pad'
279
+ | 'decimal-pad'
280
+ | 'numeric'
281
+ | 'email-address'
282
+ | 'phone-pad'
283
+ | 'url'
284
+ | 'ascii-capable'
285
+ | 'numbers-and-punctuation'
286
+ | 'name-phone-pad'
287
+ | 'twitter'
288
+ | 'web-search'
289
+ | 'visible-password';
290
+ export type TextFieldReturnKeyType =
291
+ 'default' | 'done' | 'go' | 'next' | 'search' | 'send' | 'none' | 'previous';
292
+ export type TextFieldAutoComplete =
293
+ | 'off'
294
+ | 'username'
295
+ | 'password'
296
+ | 'new-password'
297
+ | 'one-time-code'
298
+ | 'email'
299
+ | 'name'
300
+ | 'given-name'
301
+ | 'family-name'
302
+ | 'tel'
303
+ | 'street-address'
304
+ | 'postal-code'
305
+ | 'country'
306
+ | 'cc-number'
307
+ | 'cc-exp'
308
+ | 'cc-csc'
309
+ | 'url';
310
+ export type TextFieldAutoCapitalize =
311
+ 'none' | 'sentences' | 'words' | 'characters';
312
+ export type TextFieldClearButtonMode =
313
+ 'never' | 'while-editing' | 'unless-editing' | 'always';
314
+ export type TextFieldIOSChoice = 'default' | 'yes' | 'no';
315
+ export type TextFieldEvent = { nativeEvent: { text: string } };
316
+ export type TextFieldChangeEvent = {
317
+ nativeEvent: { text: string; eventCount: number };
318
+ };
319
+
320
+ export interface TextFieldRef {
321
+ focus(): void;
322
+ blur(): void;
323
+ clear(): void;
324
+ isFocused(): boolean;
325
+ }
326
+
327
+ export interface TextFieldProps extends Omit<
328
+ ViewProps,
329
+ 'onFocus' | 'onBlur' | 'children'
330
+ > {
331
+ value?: string;
332
+ defaultValue?: string;
333
+ onChangeText?: (text: string) => void;
334
+ onChange?: (event: TextFieldChangeEvent) => void;
335
+ onFocus?: (event: TextFieldEvent) => void;
336
+ onBlur?: (event: TextFieldEvent) => void;
337
+ onSubmitEditing?: (event: TextFieldEvent) => void;
338
+ label?: string;
339
+ placeholder?: string;
340
+ supportingText?: string;
341
+ error?: boolean | string;
342
+ prefix?: string;
343
+ suffix?: string;
344
+ leadingIcon?: PlatformIcon;
345
+ trailingIcon?: PlatformIcon;
346
+ onTrailingIconPress?: () => void;
347
+ clearButtonMode?: TextFieldClearButtonMode;
348
+ passwordToggle?: boolean;
349
+ showCharacterCount?: boolean;
350
+ maxLength?: number;
351
+ keyboardType?: TextFieldKeyboardType;
352
+ returnKeyType?: TextFieldReturnKeyType;
353
+ autoCapitalize?: TextFieldAutoCapitalize;
354
+ autoCorrect?: boolean;
355
+ secureTextEntry?: boolean;
356
+ multiline?: boolean;
357
+ editable?: boolean;
358
+ autoFocus?: boolean;
359
+ selectTextOnFocus?: boolean;
360
+ autoComplete?: TextFieldAutoComplete;
361
+ keyboardAppearance?: 'default' | 'light' | 'dark';
362
+ textStyle?: LabelStyle;
363
+ accessibilityLabel?: string;
364
+ ios?: Record<string, unknown>;
365
+ android?: Record<string, unknown>;
366
+ }
367
+
368
+ export const TextField = React.forwardRef<TextFieldRef, TextFieldProps>(
369
+ function TextFieldComponent(_props, ref): React.ReactElement | null {
370
+ React.useImperativeHandle(ref, () => ({
371
+ focus: () => {},
372
+ blur: () => {},
373
+ clear: () => {},
374
+ isFocused: () => false,
375
+ }));
376
+ return null;
377
+ }
378
+ );
379
+
186
380
  // ============================================================================
187
381
  // Native theme
188
382
  // ============================================================================
@@ -0,0 +1,36 @@
1
+ // labelStyle.ts
2
+ //
3
+ // Label font props shared by SegmentedControl, Button and ButtonGroup.
4
+ import type { TextStyle } from 'react-native';
5
+
6
+ /**
7
+ * Font for a control's labels. Each field falls back to the platform default.
8
+ */
9
+ export interface LabelStyle {
10
+ fontFamily?: string;
11
+ fontSize?: number;
12
+ fontWeight?: TextStyle['fontWeight'];
13
+ fontStyle?: 'normal' | 'italic';
14
+ }
15
+
16
+ /** The flat font fields the native specs expect; empty / 0 = default. */
17
+ export type NativeLabelStyle = {
18
+ fontFamily: string;
19
+ fontSize: number;
20
+ fontWeight: string;
21
+ fontStyle: string;
22
+ };
23
+
24
+ /** Normalizes a label font for native; `undefined` keeps the platform font. */
25
+ export function normalizeLabelStyle(
26
+ labelStyle: LabelStyle | undefined
27
+ ): NativeLabelStyle | undefined {
28
+ if (!labelStyle) return undefined;
29
+ return {
30
+ fontFamily: labelStyle.fontFamily ?? '',
31
+ fontSize: labelStyle.fontSize ?? 0,
32
+ fontWeight:
33
+ labelStyle.fontWeight === undefined ? '' : String(labelStyle.fontWeight),
34
+ fontStyle: labelStyle.fontStyle ?? '',
35
+ };
36
+ }
@@ -0,0 +1,22 @@
1
+ // reactNativeInternals.d.ts
2
+ //
3
+ // React Native's focus registry for text inputs. `Keyboard.dismiss()`, a
4
+ // ScrollView's `keyboardShouldPersistTaps` and `KeyboardAvoidingView` all act
5
+ // on the input registered here, so TextField registers itself like the core
6
+ // TextInput does. The module is a stable internal (it has kept this shape
7
+ // since 0.63), but it is not part of the strict API's type exports, hence this
8
+ // declaration.
9
+ declare module 'react-native/Libraries/Components/TextInput/TextInputState' {
10
+ type HostInput = object;
11
+
12
+ const TextInputState: {
13
+ currentlyFocusedInput(): HostInput | null | undefined;
14
+ focusInput(input: HostInput | null | undefined): void;
15
+ blurInput(input: HostInput | null | undefined): void;
16
+ registerInput(input: HostInput): void;
17
+ unregisterInput(input: HostInput): void;
18
+ isTextInput(input: HostInput): boolean;
19
+ };
20
+
21
+ export default TextInputState;
22
+ }
@@ -7,9 +7,15 @@ export type Visible = 'open' | 'closed';
7
7
  /** Shared presentation mode for pickers/menus. */
8
8
  export type Presentation = 'modal' | 'embedded';
9
9
 
10
- /** Shared Material preference (Android). */
10
+ /** Shared Material preference (Android): the platform widget or the Material one. */
11
11
  export type AndroidMaterialMode = 'system' | 'm3';
12
12
 
13
+ /**
14
+ * Shared Material style for the Material-only components (Android):
15
+ * Material 3, or Material 3 Expressive (the default).
16
+ */
17
+ export type AndroidMaterialStyle = 'm3' | 'expressive';
18
+
13
19
  /** Common event empty payload type. */
14
20
  export type EmptyEvent = Readonly<{}>;
15
21