@symbiote-native/components 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +110 -0
  3. package/build/accessibility-props.d.ts +64 -0
  4. package/build/accessibility-props.js +150 -0
  5. package/build/component-names/index.android.d.ts +3 -0
  6. package/build/component-names/index.android.js +32 -0
  7. package/build/component-names/index.d.ts +1 -0
  8. package/build/component-names/index.ios.d.ts +3 -0
  9. package/build/component-names/index.ios.js +26 -0
  10. package/build/component-names/index.js +5 -0
  11. package/build/component-names/shared.d.ts +7 -0
  12. package/build/component-names/shared.js +36 -0
  13. package/build/descriptor.d.ts +11 -0
  14. package/build/descriptor.js +17 -0
  15. package/build/index.d.ts +51 -0
  16. package/build/index.js +63 -0
  17. package/build/responder-props.d.ts +18 -0
  18. package/build/responder-props.js +9 -0
  19. package/build/scroll-view-commands.d.ts +23 -0
  20. package/build/scroll-view-commands.js +123 -0
  21. package/build/state/drawer-layout-android.d.ts +22 -0
  22. package/build/state/drawer-layout-android.js +53 -0
  23. package/build/state/flat-list.d.ts +12 -0
  24. package/build/state/flat-list.js +40 -0
  25. package/build/state/modal.d.ts +11 -0
  26. package/build/state/modal.js +28 -0
  27. package/build/state/pressable.d.ts +90 -0
  28. package/build/state/pressable.js +236 -0
  29. package/build/state/section-list.d.ts +46 -0
  30. package/build/state/section-list.js +51 -0
  31. package/build/state/switch.d.ts +12 -0
  32. package/build/state/switch.js +31 -0
  33. package/build/state/text-input.d.ts +103 -0
  34. package/build/state/text-input.js +205 -0
  35. package/build/state/touchable.d.ts +15 -0
  36. package/build/state/touchable.js +22 -0
  37. package/build/state/virtualized-list.d.ts +161 -0
  38. package/build/state/virtualized-list.js +306 -0
  39. package/build/view/render-activity-indicator.d.ts +25 -0
  40. package/build/view/render-activity-indicator.js +54 -0
  41. package/build/view/render-button.d.ts +19 -0
  42. package/build/view/render-button.js +24 -0
  43. package/build/view/render-drawer-layout-android.d.ts +23 -0
  44. package/build/view/render-drawer-layout-android.js +56 -0
  45. package/build/view/render-image-background.d.ts +9 -0
  46. package/build/view/render-image-background.js +48 -0
  47. package/build/view/render-image.d.ts +86 -0
  48. package/build/view/render-image.js +298 -0
  49. package/build/view/render-input-accessory-view.d.ts +9 -0
  50. package/build/view/render-input-accessory-view.js +18 -0
  51. package/build/view/render-keyboard-avoiding-view.d.ts +30 -0
  52. package/build/view/render-keyboard-avoiding-view.js +75 -0
  53. package/build/view/render-modal.d.ts +23 -0
  54. package/build/view/render-modal.js +70 -0
  55. package/build/view/render-pressable.d.ts +8 -0
  56. package/build/view/render-pressable.js +42 -0
  57. package/build/view/render-scroll-sticky.d.ts +24 -0
  58. package/build/view/render-scroll-sticky.js +81 -0
  59. package/build/view/render-scroll-view.d.ts +18 -0
  60. package/build/view/render-scroll-view.js +85 -0
  61. package/build/view/render-switch.d.ts +29 -0
  62. package/build/view/render-switch.js +33 -0
  63. package/build/view/render-text-input.d.ts +11 -0
  64. package/build/view/render-text-input.js +35 -0
  65. package/build/view/render-touchable-native-feedback.d.ts +17 -0
  66. package/build/view/render-touchable-native-feedback.js +39 -0
  67. package/package.json +38 -0
@@ -0,0 +1,236 @@
1
+ // Pressable, the logic half (framework-agnostic, zero render, zero framework imports). The
2
+ // press lifecycle RN's Pressability runs in JS (pressIn/pressOut/press synthesis, the
3
+ // long-press timer, unstable_pressDelay deferral, and the pressRetentionOffset drift test)
4
+ // lives here as a pure state machine over a mutable runtime plus an adapter-supplied host. The
5
+ // adapter owns only the lifecycle wiring: React holds the runtime in a ref and flips `pressed`
6
+ // via setState; Vue holds it in setup scope and flips a ref. Both call the SAME handlers.
7
+ //
8
+ // Framework-specific, stays in the adapter: the `pressed` state cell (it drives a
9
+ // re-render, so each framework owns its reactive primitive) and the raw frame-measure (the host
10
+ // node plus its measure call). The rest (the timers, the geometry, the suppression flags,
11
+ // the decision of when each callback fires) is here, shared by every adapter.
12
+ import { dlog, Platform } from '@symbiote-native/engine';
13
+ export const DEFAULT_DELAY_LONG_PRESS_MS = 500;
14
+ // RN's default extra slop kept around a press once it is active, before a drift fires pressOut.
15
+ // The PressRect extension (Pressability.js DEFAULT_PRESS_RECT_OFFSETS). Per-edge, deeper bottom.
16
+ export const DEFAULT_PRESS_RECT_OFFSETS = { top: 20, left: 20, bottom: 30, right: 20 };
17
+ // ---- geometry (pure) --------------------------------------------------------------------------
18
+ // A rect offset is a per-edge object (not the scalar shorthand). Reads the asymmetric form
19
+ // without a cast.
20
+ function isEdgeInsets(value) {
21
+ return typeof value === 'object';
22
+ }
23
+ // Normalize a scalar-or-rect offset to a per-edge rect: a number expands all four edges,
24
+ // mirroring RN's normalizeRect (StyleSheet/Rect.js). Absent edges read 0.
25
+ export function normalizeRect(offset) {
26
+ if (offset === undefined)
27
+ return { top: 0, left: 0, bottom: 0, right: 0 };
28
+ if (isEdgeInsets(offset)) {
29
+ const { top = 0, left = 0, bottom = 0, right = 0 } = offset;
30
+ return { top, left, bottom, right };
31
+ }
32
+ return { top: offset, left: offset, bottom: offset, right: offset };
33
+ }
34
+ // The widest single edge, for the radius fallback when no measured rect is available (headless).
35
+ export function maxEdge(insets) {
36
+ return Math.max(insets.top, insets.left, insets.bottom, insets.right);
37
+ }
38
+ // Is a touch page-point inside the measured responder region, expanded per-edge by hitSlop then
39
+ // pressRectOffset? Direct port of Pressability.js `_isTouchWithinResponderRegion`: left/top
40
+ // shrink the bound, right/bottom grow it; strict inequalities.
41
+ export function isTouchWithinRegion(point, region, hitSlop, pressRectOffset) {
42
+ const left = region.left - hitSlop.left - pressRectOffset.left;
43
+ const right = region.right + hitSlop.right + pressRectOffset.right;
44
+ const top = region.top - hitSlop.top - pressRectOffset.top;
45
+ const bottom = region.bottom + hitSlop.bottom + pressRectOffset.bottom;
46
+ return point.x > left && point.x < right && point.y > top && point.y < bottom;
47
+ }
48
+ // Page coordinate of a single-touch native event, or undefined when it carried no numeric coords
49
+ // (then the retention drift check is skipped, never guessed).
50
+ export function readPoint(event) {
51
+ const { pageX, pageY } = event.nativeEvent;
52
+ if (typeof pageX === 'number' && typeof pageY === 'number')
53
+ return { x: pageX, y: pageY };
54
+ return undefined;
55
+ }
56
+ // Build the responder region from a measured frame, or undefined for an all-zero frame (the view
57
+ // is not laid out, RN's _measureCallback ignores it).
58
+ export function computeRegion(width, height, pageX, pageY) {
59
+ if (!width && !height && !pageX && !pageY)
60
+ return undefined;
61
+ return { left: pageX, top: pageY, right: pageX + width, bottom: pageY + height };
62
+ }
63
+ // Build the Android native-feedback prop the inner View carries from the ripple config. RN runs
64
+ // the color through processColor → a native int; we have no native bridge in JS, so we keep the
65
+ // string and let Android resolve it (a null color is the documented "no tint"). Inert on iOS.
66
+ export function rippleProps(config) {
67
+ if (Platform.OS !== 'android')
68
+ return undefined;
69
+ const background = {
70
+ type: 'RippleAndroid',
71
+ color: config.color ?? null,
72
+ borderless: config.borderless === true,
73
+ rippleRadius: config.radius,
74
+ };
75
+ return config.foreground === true
76
+ ? { nativeForegroundAndroid: background }
77
+ : { nativeBackgroundAndroid: background };
78
+ }
79
+ export function createPressRuntime() {
80
+ return {
81
+ longPressCancel: undefined,
82
+ longPressFired: false,
83
+ pressDelayCancel: undefined,
84
+ pressOrigin: undefined,
85
+ driftedOut: false,
86
+ region: undefined,
87
+ };
88
+ }
89
+ // Measure the responder's on-screen frame and cache it as the retention region for the life of
90
+ // the press (RN measures on responder grant, _measureResponderRegion). When measure is
91
+ // unavailable (no node yet, an uncommitted node, or a host slot without a measure method,
92
+ // headless) the region stays undefined and the move test falls back to the radius bound. The
93
+ // try/catch guards that last case: a slot lacking measure throws rather than no-opping.
94
+ function measureRegion(runtime, measureFn) {
95
+ runtime.region = undefined;
96
+ if (measureFn === undefined)
97
+ return;
98
+ dlog('Pressable measuring responder region');
99
+ try {
100
+ measureFn((_x, _y, width, height, pageX, pageY) => {
101
+ const region = computeRegion(width, height, pageX, pageY);
102
+ if (region === undefined)
103
+ return;
104
+ runtime.region = region;
105
+ dlog('Pressable responder region measured');
106
+ });
107
+ }
108
+ catch {
109
+ dlog('Pressable measure unavailable — retention falls back to radius');
110
+ }
111
+ }
112
+ // Build the four responder handlers over the config + runtime + host. The whole press lifecycle
113
+ // (the React adapter's useMemo body) lives here, shared by every adapter. The adapter rebuilds
114
+ // these per render (the closures capture the live config) while the runtime persists across them.
115
+ export function createPressHandlers(config, runtime, host) {
116
+ const { onPress, onPressIn, onPressOut, onPressMove, onLongPress, delayLongPress, unstable_pressDelay, } = config;
117
+ // Per-edge offsets for the measured-rect retention test (RN's hitSlop + pressRectOffset).
118
+ // pressRetentionOffset defaults to RN's DEFAULT_PRESS_RECT_OFFSETS when unset; hitSlop to zero.
119
+ const hitSlopRect = normalizeRect(config.hitSlop);
120
+ const pressRectOffset = config.pressRetentionOffset === undefined
121
+ ? DEFAULT_PRESS_RECT_OFFSETS
122
+ : normalizeRect(config.pressRetentionOffset);
123
+ // Radius fallback bound (headless): widest hitSlop edge + widest retention edge.
124
+ const fallbackThreshold = maxEdge(hitSlopRect) + maxEdge(pressRectOffset);
125
+ // True iff the touch still belongs to the active press: against the measured rect when we have
126
+ // one (the RN-faithful path), else the symmetric radius fallback.
127
+ function isWithinRetention(point) {
128
+ const region = runtime.region;
129
+ if (region !== undefined) {
130
+ return isTouchWithinRegion(point, region, hitSlopRect, pressRectOffset);
131
+ }
132
+ const origin = runtime.pressOrigin;
133
+ if (origin === undefined)
134
+ return true;
135
+ return Math.hypot(point.x - origin.x, point.y - origin.y) <= fallbackThreshold;
136
+ }
137
+ function clearLongPress() {
138
+ if (runtime.longPressCancel !== undefined) {
139
+ runtime.longPressCancel();
140
+ runtime.longPressCancel = undefined;
141
+ }
142
+ }
143
+ // The real activation: flip pressed-state on, arm the long-press timer, fire onPressIn. Split
144
+ // out so unstable_pressDelay can defer it behind a timer while an early release flushes it.
145
+ function activate(event) {
146
+ dlog('Pressable pressIn');
147
+ host.setPressed(true);
148
+ runtime.longPressFired = false;
149
+ if (onLongPress) {
150
+ runtime.longPressCancel = host.schedule(() => {
151
+ runtime.longPressCancel = undefined;
152
+ runtime.longPressFired = true;
153
+ dlog('Pressable longPress timer fired');
154
+ onLongPress(event);
155
+ }, delayLongPress);
156
+ }
157
+ onPressIn?.(event);
158
+ }
159
+ // Flush a still-pending pressDelay timer immediately, so a pressOut/press that arrives before
160
+ // the delay elapsed still sees an activated press.
161
+ function flushPressDelay(event) {
162
+ if (runtime.pressDelayCancel !== undefined) {
163
+ runtime.pressDelayCancel();
164
+ runtime.pressDelayCancel = undefined;
165
+ activate(event);
166
+ }
167
+ }
168
+ return {
169
+ handlePressIn(event) {
170
+ runtime.pressOrigin = readPoint(event);
171
+ runtime.driftedOut = false;
172
+ // Measure now so the move stream tests against the real frame, not a press-start radius.
173
+ measureRegion(runtime, host.getMeasureFn());
174
+ if (unstable_pressDelay > 0) {
175
+ dlog(`Pressable pressIn deferred ${unstable_pressDelay}ms`);
176
+ runtime.pressDelayCancel = host.schedule(() => {
177
+ runtime.pressDelayCancel = undefined;
178
+ activate(event);
179
+ }, unstable_pressDelay);
180
+ return;
181
+ }
182
+ activate(event);
183
+ },
184
+ handlePressOut(event) {
185
+ dlog('Pressable pressOut');
186
+ flushPressDelay(event);
187
+ clearLongPress();
188
+ runtime.pressOrigin = undefined;
189
+ runtime.region = undefined;
190
+ host.setPressed(false);
191
+ onPressOut?.(event);
192
+ },
193
+ handlePress(event) {
194
+ dlog('Pressable press');
195
+ flushPressDelay(event);
196
+ clearLongPress();
197
+ // A drift past the retention region cancels the tap (RN); reset and suppress.
198
+ if (runtime.driftedOut) {
199
+ runtime.driftedOut = false;
200
+ dlog('Pressable press suppressed by drift past retention region');
201
+ return;
202
+ }
203
+ // A fired long press cancels the tap: reset the flag and suppress onPress.
204
+ if (runtime.longPressFired) {
205
+ runtime.longPressFired = false;
206
+ dlog('Pressable press suppressed by prior longPress');
207
+ return;
208
+ }
209
+ onPress?.(event);
210
+ },
211
+ // Responder-move stream of the Pressable's own View. onPressMove fires on every move while
212
+ // the press is live (RN). Then the retention test: a move outside the measured region
213
+ // (expanded by hitSlop+pressRectOffset) fires an early pressOut and marks the tap suppressed;
214
+ // a move back inside re-activates.
215
+ handleResponderMove(event) {
216
+ onPressMove?.(event);
217
+ const here = readPoint(event);
218
+ if (!here)
219
+ return;
220
+ if (!isWithinRetention(here)) {
221
+ if (!runtime.driftedOut) {
222
+ dlog('Pressable drifted past retention region — deactivating');
223
+ runtime.driftedOut = true;
224
+ clearLongPress();
225
+ host.setPressed(false);
226
+ onPressOut?.(event);
227
+ }
228
+ }
229
+ else if (runtime.driftedOut) {
230
+ dlog('Pressable returned inside retention region — reactivating');
231
+ runtime.driftedOut = false;
232
+ activate(event);
233
+ }
234
+ },
235
+ };
236
+ }
@@ -0,0 +1,46 @@
1
+ import type { ISymbioteNode } from '@symbiote-native/engine';
2
+ import type { IScrollViewHandle } from '../scroll-view-commands';
3
+ export interface ISection<ItemT> {
4
+ title: string;
5
+ data: readonly ItemT[];
6
+ }
7
+ export type ISectionEntry<ItemT> = {
8
+ kind: 'header';
9
+ section: ISection<ItemT>;
10
+ sectionIndex: number;
11
+ } | {
12
+ kind: 'item';
13
+ item: ItemT;
14
+ section: ISection<ItemT>;
15
+ sectionIndex: number;
16
+ itemIndex: number;
17
+ } | {
18
+ kind: 'footer';
19
+ section: ISection<ItemT>;
20
+ sectionIndex: number;
21
+ } | {
22
+ kind: 'section-separator';
23
+ sectionIndex: number;
24
+ };
25
+ export interface IVirtualizedSectionListHandle {
26
+ scrollToLocation(params: {
27
+ sectionIndex: number;
28
+ itemIndex: number;
29
+ viewOffset?: number;
30
+ viewPosition?: number;
31
+ animated?: boolean;
32
+ }): void;
33
+ flashScrollIndicators(): void;
34
+ getNativeScrollRef(): IScrollViewHandle | null;
35
+ getScrollableNode(): IScrollViewHandle | null;
36
+ getScrollResponder(): IScrollViewHandle | null;
37
+ getScrollNode(): ISymbioteNode | null;
38
+ recordInteraction(): void;
39
+ }
40
+ export declare function flattenSections<ItemT>(sections: ReadonlyArray<ISection<ItemT>>, withSeparators: boolean): {
41
+ entries: ISectionEntry<ItemT>[];
42
+ headerIndices: number[];
43
+ };
44
+ export declare function unwrapEntryItem<ItemT>(entry: ISectionEntry<ItemT> | undefined): ItemT | undefined;
45
+ export declare function sectionEntryKey<ItemT>(entry: ISectionEntry<ItemT>, index: number, keyExtractor?: (item: ItemT, index: number) => string): string;
46
+ export declare function scrollLocationToFlatIndex(headerIndices: number[], sectionIndex: number, itemIndex: number): number | undefined;
@@ -0,0 +1,51 @@
1
+ // SectionList logic: the framework-agnostic section flattening over VirtualizedList. Each
2
+ // section contributes a header row, its item rows, then a footer row (RN counts 2 per
3
+ // section around the items); the flattened sequence feeds VirtualizedList as one tagged
4
+ // stream, so headers, items, and footers are windowed by the same machinery. All of this
5
+ // is pure transform — every adapter reuses it; the adapter supplies only the per-entry
6
+ // element creation (renderSectionHeader / renderItem / …) and the ref wiring.
7
+ // Flatten sections into entries AND record where each section header lands in the flat
8
+ // stream, so scrollToLocation can map (sectionIndex, itemIndex) -> flat index without
9
+ // re-deriving the layout. withSeparators inserts a section separator between adjacent
10
+ // sections (never before the first / after the last).
11
+ export function flattenSections(sections, withSeparators) {
12
+ const entries = [];
13
+ const headerIndices = [];
14
+ sections.forEach((section, sectionIndex) => {
15
+ if (withSeparators && sectionIndex > 0) {
16
+ entries.push({ kind: 'section-separator', sectionIndex });
17
+ }
18
+ headerIndices[sectionIndex] = entries.length;
19
+ entries.push({ kind: 'header', section, sectionIndex });
20
+ section.data.forEach((item, itemIndex) => {
21
+ entries.push({ kind: 'item', item, section, sectionIndex, itemIndex });
22
+ });
23
+ entries.push({ kind: 'footer', section, sectionIndex });
24
+ });
25
+ return { entries, headerIndices };
26
+ }
27
+ // Unwrap an entry separator-prop into its underlying ItemT (or undefined for a non-item
28
+ // entry: header/footer/section-separator gaps have no item), so the user's
29
+ // ItemSeparatorComponent, typed on ItemT, sees real items.
30
+ export function unwrapEntryItem(entry) {
31
+ return entry !== undefined && entry.kind === 'item' ? entry.item : undefined;
32
+ }
33
+ export function sectionEntryKey(entry, index, keyExtractor) {
34
+ if (entry.kind === 'header')
35
+ return `section-${entry.sectionIndex}`;
36
+ if (entry.kind === 'footer')
37
+ return `section-${entry.sectionIndex}:footer`;
38
+ if (entry.kind === 'section-separator')
39
+ return `section-${entry.sectionIndex}:separator`;
40
+ if (keyExtractor)
41
+ return keyExtractor(entry.item, entry.itemIndex);
42
+ return `entry-${index}`;
43
+ }
44
+ // RN's itemIndex is offset by 1 so itemIndex 0 targets the header and itemIndex >= 1
45
+ // targets that section's items. Returns undefined when the section is out of range.
46
+ export function scrollLocationToFlatIndex(headerIndices, sectionIndex, itemIndex) {
47
+ const headerFlatIndex = headerIndices[sectionIndex];
48
+ if (headerFlatIndex === undefined)
49
+ return undefined;
50
+ return headerFlatIndex + itemIndex;
51
+ }
@@ -0,0 +1,12 @@
1
+ import type { ISymbioteEvent } from '@symbiote-native/engine';
2
+ export type ISwitchState = {
3
+ lastNativeReport: boolean | null;
4
+ };
5
+ export type ISwitchAction = {
6
+ type: 'native-reported';
7
+ value: boolean;
8
+ };
9
+ export declare function createInitialSwitchState(): ISwitchState;
10
+ export declare function switchReducer(state: ISwitchState, action: ISwitchAction): ISwitchState;
11
+ export declare function valueFromChange(event: ISymbioteEvent): boolean | undefined;
12
+ export declare function shouldSnapBack(state: ISwitchState, fabricValue: boolean): boolean;
@@ -0,0 +1,31 @@
1
+ // Switch: the logic half (framework-agnostic, zero render). Switch is controlled exactly
2
+ // like RN's: `value` is a real Fabric prop the parent owns, so the only state the component
3
+ // itself holds is what native LAST reported, kept so the lifecycle layer can detect a
4
+ // rejected toggle and snap native back. The reducer + the two pure predicates here are the
5
+ // whole state machine; the adapter supplies the hook (useReducer / ref / watch) around it.
6
+ export function createInitialSwitchState() {
7
+ return { lastNativeReport: null };
8
+ }
9
+ export function switchReducer(state, action) {
10
+ switch (action.type) {
11
+ case 'native-reported':
12
+ // Always a fresh object, even when the boolean is unchanged from the prior report:
13
+ // the snap-back effect keys on state identity so it re-fires on every report (native
14
+ // may re-toggle to a value JS keeps rejecting, and must be commanded back each time).
15
+ return { lastNativeReport: action.value };
16
+ }
17
+ }
18
+ // The change payload carries the new boolean as nativeEvent.value; a non-boolean payload is
19
+ // ignored upstream (no onValueChange, no report). nativeEvent is an untyped Record, so narrow.
20
+ export function valueFromChange(event) {
21
+ const value = event.nativeEvent.value;
22
+ return typeof value === 'boolean' ? value : undefined;
23
+ }
24
+ // Snap-back fires only when native reported a value that disagrees with the JS-held value:
25
+ // the parent rejected the toggle (its onValueChange did not update `value`). A plain prop
26
+ // re-push cannot cover this: when the handler is a no-op the prop never changes, so the
27
+ // retained tree never diverges and nothing re-commits. The imperative command is the only
28
+ // correction path. No report yet (null) or agreement → no command.
29
+ export function shouldSnapBack(state, fabricValue) {
30
+ return state.lastNativeReport !== null && state.lastNativeReport !== fabricValue;
31
+ }
@@ -0,0 +1,103 @@
1
+ import type { ISymbioteEvent, ITextStyle } from '@symbiote-native/engine';
2
+ import type { IAccessibilityProps, IAriaProps } from '../accessibility-props';
3
+ export type IInputMode = 'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url';
4
+ export type IEnterKeyHint = 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send';
5
+ export type ISubmitBehavior = 'submit' | 'blurAndSubmit' | 'newline';
6
+ export type ITextInputSelection = {
7
+ start: number;
8
+ end?: number;
9
+ };
10
+ export type ITextInputEventHandler = (event: ISymbioteEvent) => void;
11
+ export declare const INITIAL_EVENT_COUNT = 0;
12
+ export declare const SELECTION_NONE = -1;
13
+ export declare function mapAutoComplete(map: Record<string, string>, token: string): string | undefined;
14
+ export declare function foldAutoComplete(token: string | undefined): {
15
+ autoComplete: string | undefined;
16
+ textContentType: string | undefined;
17
+ };
18
+ export declare function foldSubmitBehavior(submitBehavior: string | undefined, blurOnSubmit: boolean | undefined, multiline: boolean): string;
19
+ export declare function foldText(value: string | undefined, defaultValue: string | undefined): string | undefined;
20
+ export declare function textFromChange(event: ISymbioteEvent): string | undefined;
21
+ export declare function eventCountFromChange(event: ISymbioteEvent): number | undefined;
22
+ export declare function shouldCommandText(lastNativeText: string | undefined, value: string | undefined): value is string;
23
+ export type ITextInputFoldInput = {
24
+ inputMode?: string;
25
+ keyboardType?: string;
26
+ enterKeyHint?: string;
27
+ returnKeyType?: string;
28
+ readOnly?: boolean;
29
+ editable?: boolean;
30
+ submitBehavior?: string;
31
+ blurOnSubmit?: boolean;
32
+ multiline: boolean;
33
+ cursorColor?: string;
34
+ selectionColor?: string;
35
+ selectionHandleColor?: string;
36
+ autoComplete?: string;
37
+ textContentType?: string;
38
+ showSoftInputOnFocus?: boolean;
39
+ underlineColorAndroid?: string;
40
+ };
41
+ export type IFoldedTextInputProps = {
42
+ keyboardType: string | undefined;
43
+ returnKeyType: string | undefined;
44
+ editable: boolean | undefined;
45
+ submitBehavior: string;
46
+ selectionColor: string | undefined;
47
+ cursorColor: string | undefined;
48
+ selectionHandleColor: string | undefined;
49
+ underlineColorAndroid: string;
50
+ autoComplete: string | undefined;
51
+ textContentType: string | undefined;
52
+ showSoftInputOnFocus: boolean | undefined;
53
+ };
54
+ export declare function resolveTextInputProps(input: ITextInputFoldInput): IFoldedTextInputProps;
55
+ export type ITextInputProps = IAccessibilityProps & IAriaProps & {
56
+ value?: string;
57
+ defaultValue?: string;
58
+ placeholder?: string;
59
+ placeholderTextColor?: string;
60
+ editable?: boolean;
61
+ keyboardType?: string;
62
+ secureTextEntry?: boolean;
63
+ maxLength?: number;
64
+ multiline?: boolean;
65
+ selection?: ITextInputSelection;
66
+ autoCapitalize?: 'none' | 'sentences' | 'words' | 'characters';
67
+ autoCorrect?: boolean;
68
+ autoComplete?: string;
69
+ textContentType?: string;
70
+ autoFocus?: boolean;
71
+ showSoftInputOnFocus?: boolean;
72
+ returnKeyType?: string;
73
+ selectTextOnFocus?: boolean;
74
+ scrollEnabled?: boolean;
75
+ numberOfLines?: number;
76
+ textAlign?: 'left' | 'center' | 'right';
77
+ blurOnSubmit?: boolean;
78
+ inputMode?: IInputMode;
79
+ enterKeyHint?: IEnterKeyHint;
80
+ readOnly?: boolean;
81
+ submitBehavior?: ISubmitBehavior;
82
+ cursorColor?: string;
83
+ selectionColor?: string;
84
+ selectionHandleColor?: string;
85
+ underlineColorAndroid?: string;
86
+ inputAccessoryViewID?: string;
87
+ style?: ITextStyle;
88
+ onValueChange?: (text: string, event: ISymbioteEvent) => void;
89
+ onFocus?: ITextInputEventHandler;
90
+ onBlur?: ITextInputEventHandler;
91
+ onEndEditing?: ITextInputEventHandler;
92
+ onSubmitEditing?: ITextInputEventHandler;
93
+ onKeyPress?: ITextInputEventHandler;
94
+ onSelectionChange?: ITextInputEventHandler;
95
+ onContentSizeChange?: ITextInputEventHandler;
96
+ };
97
+ export type ITextInputHandle = {
98
+ focus(): void;
99
+ blur(): void;
100
+ clear(): void;
101
+ isFocused(): boolean;
102
+ setSelection(start: number, end: number): void;
103
+ };