@symbiote-native/components 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -9
- package/build/accessibility-props.d.ts +1 -1
- package/build/accessibility-props.js +2 -2
- package/build/behaviors/activity-indicator/shared.js +41 -70
- package/build/behaviors/button.d.ts +11 -0
- package/build/behaviors/button.js +101 -89
- package/build/behaviors/image-background.d.ts +1 -0
- package/build/behaviors/image-background.js +97 -81
- package/build/behaviors/image.d.ts +0 -1
- package/build/behaviors/image.js +24 -105
- package/build/behaviors/input-accessory-view.d.ts +0 -1
- package/build/behaviors/input-accessory-view.js +47 -53
- package/build/behaviors/pressable.d.ts +1 -1
- package/build/behaviors/pressable.js +68 -97
- package/build/behaviors/refresh-control.js +15 -2
- package/build/behaviors/scroll-view/index.android.js +25 -37
- package/build/behaviors/scroll-view/index.d.ts +1 -0
- package/build/behaviors/scroll-view/index.js +3 -0
- package/build/behaviors/scroll-view/responder.d.ts +4 -0
- package/build/behaviors/scroll-view/responder.js +202 -0
- package/build/behaviors/scroll-view/shared.d.ts +1 -3
- package/build/behaviors/scroll-view/shared.js +95 -95
- package/build/behaviors/scroll-view/sticky.d.ts +1 -0
- package/build/behaviors/scroll-view/sticky.js +62 -49
- package/build/behaviors/switch.js +43 -86
- package/build/behaviors/text-input.js +219 -107
- package/build/behaviors/touchable-highlight.js +74 -61
- package/build/behaviors/touchable-native-feedback.js +43 -122
- package/build/behaviors/touchable-opacity.js +71 -59
- package/build/behaviors/touchable-without-feedback.js +35 -100
- package/build/component-names/index.android.js +7 -11
- package/build/component-names/index.ios.js +0 -7
- package/build/component-names/shared.d.ts +1 -1
- package/build/index.d.ts +15 -21
- package/build/index.js +21 -28
- package/build/resolve-intrinsic.js +3 -9
- package/build/scroll-view-commands.d.ts +1 -9
- package/build/scroll-view-commands.js +13 -74
- package/build/state/flat-list.d.ts +2 -2
- package/build/state/flat-list.js +10 -2
- package/build/state/pressable.d.ts +6 -1
- package/build/state/pressable.js +63 -28
- package/build/state/section-list.d.ts +2 -0
- package/build/state/section-list.js +14 -7
- package/build/state/text-input.d.ts +7 -40
- package/build/state/text-input.js +17 -186
- package/build/state/touchable.d.ts +1 -0
- package/build/state/touchable.js +11 -8
- package/build/state/virtualized-list-reducer.d.ts +2 -2
- package/build/state/virtualized-list.d.ts +6 -6
- package/build/state/virtualized-list.js +71 -37
- package/build/text-props.d.ts +0 -8
- package/build/text-props.js +14 -25
- package/build/view/render-button.d.ts +1 -29
- package/build/view/render-button.js +44 -81
- package/build/view/render-image/index.d.ts +14 -1
- package/build/view/render-image/index.js +22 -147
- package/build/view/render-input-accessory-view.d.ts +1 -5
- package/build/view/render-input-accessory-view.js +26 -48
- package/build/view/render-keyboard-avoiding-view.d.ts +7 -1
- package/build/view/render-keyboard-avoiding-view.js +40 -1
- package/build/view/render-modal.d.ts +1 -1
- package/build/view/render-modal.js +15 -5
- package/build/view/render-pressable/index.d.ts +1 -0
- package/build/view/render-pressable/index.js +4 -0
- package/build/view/render-scroll-view.d.ts +0 -4
- package/build/view/render-scroll-view.js +3 -49
- package/build/view/render-switch.d.ts +0 -14
- package/build/view/render-switch.js +4 -42
- package/build/view/render-touchable-highlight.d.ts +1 -0
- package/build/view/render-touchable-native-feedback.d.ts +0 -1
- package/build/view/render-touchable-native-feedback.js +15 -9
- package/host-primitives.cjs +49 -203
- package/host-primitives.d.cts +0 -1
- package/package.json +3 -7
- package/build/fold-host-bag.d.ts +0 -15
- package/build/fold-host-bag.js +0 -99
- package/build/view/render-text-input.d.ts +0 -11
- package/build/view/render-text-input.js +0 -39
|
@@ -3,11 +3,10 @@ import type { ISymbioteEvent } from '@symbiote-native/engine';
|
|
|
3
3
|
import type { IScrollRoutingHandle } from './scroll-routing-handle';
|
|
4
4
|
export declare const DEFAULT_WINDOW_SIZE = 21;
|
|
5
5
|
export declare const DEFAULT_INITIAL_NUM_TO_RENDER = 10;
|
|
6
|
-
export declare const DEFAULT_END_REACHED_THRESHOLD = 2;
|
|
7
6
|
export declare const DEFAULT_MAX_TO_RENDER_PER_BATCH = 10;
|
|
8
7
|
export declare const DEFAULT_UPDATE_CELLS_BATCHING_PERIOD = 50;
|
|
9
8
|
export declare const DEFAULT_VIEW_AREA_COVERAGE_PERCENT_THRESHOLD = 0;
|
|
10
|
-
export declare const
|
|
9
|
+
export declare const DEFAULT_EDGE_REACHED_THRESHOLD_PX = 2;
|
|
11
10
|
export declare const FIRST_INDEX = 0;
|
|
12
11
|
export declare const EMPTY_OFFSET = 0;
|
|
13
12
|
export declare const NO_INDEX = -1;
|
|
@@ -41,6 +40,7 @@ export interface IViewToken<ItemT> {
|
|
|
41
40
|
export interface IViewableItemsChangedInfo<ItemT> {
|
|
42
41
|
viewableItems: IViewToken<ItemT>[];
|
|
43
42
|
changed: IViewToken<ItemT>[];
|
|
43
|
+
viewabilityConfig?: IViewabilityConfig;
|
|
44
44
|
}
|
|
45
45
|
export interface IViewabilityConfig {
|
|
46
46
|
minimumViewTime?: number;
|
|
@@ -94,19 +94,18 @@ export declare function throttleWindow(target: {
|
|
|
94
94
|
first: number;
|
|
95
95
|
last: number;
|
|
96
96
|
};
|
|
97
|
-
export declare function
|
|
98
|
-
export declare function isCellViewable(percent: number, config: IViewabilityConfig): boolean;
|
|
97
|
+
export declare function isCellViewable(cellOffset: number, cellLength: number, scrollOffset: number, viewportLength: number, config: IViewabilityConfig): boolean;
|
|
99
98
|
export declare function offsetForIndex(index: number, viewPosition: number, viewOffset: number, count: number, offsets: number[], lengths: number[], viewportLength: number): number;
|
|
100
99
|
export declare const LAYOUT_EPSILON = 0.01;
|
|
101
100
|
export declare function isSettledLayout(known: number | undefined, reported: number): boolean;
|
|
102
101
|
export declare function averageMeasuredLength(measured: Map<number, number>): number;
|
|
103
102
|
export declare function averageMeasuredStride(measuredOffsets: Map<number, number>, fallback: number): number;
|
|
104
103
|
export declare function highestMeasuredIndex(measured: Map<number, number>): number;
|
|
105
|
-
export declare function computeEndReached(total: number, scrollOffset: number, viewportLength: number, thresholdMultiplier: number): {
|
|
104
|
+
export declare function computeEndReached(total: number, scrollOffset: number, viewportLength: number, thresholdMultiplier: number | undefined): {
|
|
106
105
|
distanceFromEnd: number;
|
|
107
106
|
withinThreshold: boolean;
|
|
108
107
|
};
|
|
109
|
-
export declare function computeStartReached(scrollOffset: number, viewportLength: number, thresholdMultiplier: number): {
|
|
108
|
+
export declare function computeStartReached(scrollOffset: number, viewportLength: number, thresholdMultiplier: number | undefined): {
|
|
110
109
|
distanceFromStart: number;
|
|
111
110
|
withinThreshold: boolean;
|
|
112
111
|
};
|
|
@@ -181,6 +180,7 @@ export interface IMvcpAdjustmentResult {
|
|
|
181
180
|
action: IMvcpAction;
|
|
182
181
|
}
|
|
183
182
|
export declare function computeMvcpAdjustment(params: IMvcpAdjustmentParams): IMvcpAdjustmentResult;
|
|
183
|
+
export declare function defaultKeyExtractor<ItemT>(item: ItemT, index: number): string;
|
|
184
184
|
export declare function resolveItemKey<ItemT>(item: ItemT, index: number, keyExtractor: ((item: ItemT, index: number) => string) | undefined): string;
|
|
185
185
|
export declare function indexOfItem(data: unknown, getItem: (data: unknown, index: number) => unknown, count: number, item: unknown): number;
|
|
186
186
|
export declare function offsetForEnd(total: number, viewportLength: number): number;
|
|
@@ -21,18 +21,20 @@
|
|
|
21
21
|
// module, not a view/render-*.ts.
|
|
22
22
|
import { dlog } from '@symbiote-native/engine';
|
|
23
23
|
// Defaults match RN. windowSize is measured in viewport-lengths (21 => ten screens
|
|
24
|
-
// of buffer on each side of the visible region).
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
// maxToRenderPerBatch / batching period mirror RN's incremental fill defaults.
|
|
24
|
+
// of buffer on each side of the visible region). initialNumToRender bounds the first
|
|
25
|
+
// paint before any layout is measured. maxToRenderPerBatch / batching period mirror
|
|
26
|
+
// RN's incremental fill defaults.
|
|
28
27
|
export const DEFAULT_WINDOW_SIZE = 21;
|
|
29
28
|
export const DEFAULT_INITIAL_NUM_TO_RENDER = 10;
|
|
30
|
-
export const DEFAULT_END_REACHED_THRESHOLD = 2;
|
|
31
29
|
export const DEFAULT_MAX_TO_RENDER_PER_BATCH = 10;
|
|
32
30
|
export const DEFAULT_UPDATE_CELLS_BATCHING_PERIOD = 50;
|
|
33
31
|
export const DEFAULT_VIEW_AREA_COVERAGE_PERCENT_THRESHOLD = 0;
|
|
34
|
-
//
|
|
35
|
-
|
|
32
|
+
// `_maybeCallOnEdgeReached`'s OWN fallback (`VirtualizedList.js:1567`) for whether to actually
|
|
33
|
+
// FIRE onEndReached/onStartReached when the app gives no threshold — a flat 2 PIXELS. This is a
|
|
34
|
+
// different RN default from `onEndReachedThresholdOrDefault`'s `?? 2`, which is a MULTIPLE of the
|
|
35
|
+
// visible length used only for internal render-ahead windowing (a concern this engine does not
|
|
36
|
+
// separate out); conflating the two here used to fire the callback two whole screens early.
|
|
37
|
+
export const DEFAULT_EDGE_REACHED_THRESHOLD_PX = 2;
|
|
36
38
|
export const FIRST_INDEX = 0;
|
|
37
39
|
export const EMPTY_OFFSET = 0;
|
|
38
40
|
export const NO_INDEX = -1;
|
|
@@ -178,26 +180,39 @@ export function throttleWindow(target, previous, maxToRenderPerBatch) {
|
|
|
178
180
|
return target;
|
|
179
181
|
return { first, last };
|
|
180
182
|
}
|
|
181
|
-
//
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
//
|
|
191
|
-
//
|
|
192
|
-
//
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
183
|
+
// A cell is viewable when its visible fraction clears the configured threshold
|
|
184
|
+
// (`ViewabilityHelper.js`'s `_isViewable` + `computeViewableItems`). Two percents exist and they
|
|
185
|
+
// are NOT interchangeable: `viewAreaCoveragePercentThreshold` is a fraction of the VIEWPORT,
|
|
186
|
+
// `itemVisiblePercentThreshold` a fraction of the CELL's own length — a short cell mostly visible
|
|
187
|
+
// in a tall viewport clears the second easily while failing the first. Area wins whenever it is
|
|
188
|
+
// set (vendor checks `viewAreaCoveragePercentThreshold != null` first); item only when it is not.
|
|
189
|
+
export function isCellViewable(cellOffset, cellLength, scrollOffset, viewportLength, config) {
|
|
190
|
+
const top = cellOffset - scrollOffset;
|
|
191
|
+
const bottom = top + cellLength;
|
|
192
|
+
// No overlap at all: RN's own caller loop never reaches `_isViewable` for such a cell
|
|
193
|
+
// (`top < viewportHeight && bottom > 0` gates the whole scan), so this is exclusion by
|
|
194
|
+
// construction, not a zero percent happening to clear a zero threshold.
|
|
195
|
+
if (bottom <= EMPTY_OFFSET || top >= viewportLength)
|
|
196
|
+
return false;
|
|
197
|
+
// RN's own `_isEntirelyVisible` shortcut: viewable in EITHER mode regardless of the cell's
|
|
198
|
+
// share of the viewport, since an area threshold sized to the viewport could otherwise reject
|
|
199
|
+
// every fully-visible cell smaller than that share. `bottom > top` excludes a zero-length cell
|
|
200
|
+
// (no measurement yet), which vendor falls through to the percent math instead.
|
|
201
|
+
if (top >= EMPTY_OFFSET && bottom <= viewportLength && bottom > top) {
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
const visiblePixels = Math.min(bottom, viewportLength) - Math.max(top, EMPTY_OFFSET);
|
|
205
|
+
const areaThreshold = config.viewAreaCoveragePercentThreshold;
|
|
206
|
+
const areaMode = areaThreshold !== undefined;
|
|
207
|
+
const threshold = areaMode
|
|
208
|
+
? areaThreshold
|
|
209
|
+
: (config.itemVisiblePercentThreshold ??
|
|
210
|
+
DEFAULT_VIEW_AREA_COVERAGE_PERCENT_THRESHOLD);
|
|
211
|
+
const denominator = areaMode ? viewportLength : cellLength;
|
|
212
|
+
if (denominator <= EMPTY_OFFSET)
|
|
213
|
+
return false;
|
|
214
|
+
const percent = (visiblePixels / denominator) * FULLY_VISIBLE_PERCENT;
|
|
215
|
+
return percent >= threshold;
|
|
201
216
|
}
|
|
202
217
|
// Resolve an index to a pixel offset, optionally biasing where in the viewport the item
|
|
203
218
|
// lands (viewPosition 0=top, 1=bottom, 0.5=center) and an absolute viewOffset nudge,
|
|
@@ -271,11 +286,17 @@ export function highestMeasuredIndex(measured) {
|
|
|
271
286
|
// onEndReached distance + threshold test (RN _maybeCallOnEdgeReached). The adapter still
|
|
272
287
|
// gates on "the last cell is actually rendered" and dedups by content length via its own
|
|
273
288
|
// ref; this returns only the pure geometry.
|
|
289
|
+
//
|
|
290
|
+
// `thresholdMultiplier` is `undefined` for "the app gave no onEndReachedThreshold" — RN's own
|
|
291
|
+
// unset-case answer is a flat `DEFAULT_EDGE_REACHED_THRESHOLD_PX`, never a viewport-length
|
|
292
|
+
// multiple, so `undefined` must NOT be defaulted to a multiplier at the call site.
|
|
274
293
|
export function computeEndReached(total, scrollOffset, viewportLength, thresholdMultiplier) {
|
|
275
294
|
let distanceFromEnd = total - (scrollOffset + viewportLength);
|
|
276
295
|
if (distanceFromEnd < ON_EDGE_REACHED_EPSILON)
|
|
277
296
|
distanceFromEnd = EMPTY_OFFSET;
|
|
278
|
-
const threshold = thresholdMultiplier
|
|
297
|
+
const threshold = thresholdMultiplier != null
|
|
298
|
+
? thresholdMultiplier * viewportLength
|
|
299
|
+
: DEFAULT_EDGE_REACHED_THRESHOLD_PX;
|
|
279
300
|
return { distanceFromEnd, withinThreshold: distanceFromEnd <= threshold };
|
|
280
301
|
}
|
|
281
302
|
// onStartReached twin of computeEndReached. distanceFromStart is just the scroll offset.
|
|
@@ -283,7 +304,9 @@ export function computeStartReached(scrollOffset, viewportLength, thresholdMulti
|
|
|
283
304
|
let distanceFromStart = scrollOffset;
|
|
284
305
|
if (distanceFromStart < ON_EDGE_REACHED_EPSILON)
|
|
285
306
|
distanceFromStart = EMPTY_OFFSET;
|
|
286
|
-
const threshold = thresholdMultiplier
|
|
307
|
+
const threshold = thresholdMultiplier != null
|
|
308
|
+
? thresholdMultiplier * viewportLength
|
|
309
|
+
: DEFAULT_EDGE_REACHED_THRESHOLD_PX;
|
|
287
310
|
return { distanceFromStart, withinThreshold: distanceFromStart <= threshold };
|
|
288
311
|
}
|
|
289
312
|
// Fold the single-config and pairs forms into one list (RN supports either, not both).
|
|
@@ -306,18 +329,15 @@ export function computeViewableSet(params) {
|
|
|
306
329
|
const tokens = [];
|
|
307
330
|
const map = new Map();
|
|
308
331
|
for (let index = params.first; index <= params.last && index < params.count; index += 1) {
|
|
309
|
-
const percent = visiblePercent(params.offsets[index], params.lengths[index], params.scrollOffset, params.viewportLength);
|
|
310
332
|
const item = params.getItem(params.data, index);
|
|
311
|
-
const key = params.keyExtractor
|
|
312
|
-
? params.keyExtractor(item, index)
|
|
313
|
-
: String(index);
|
|
333
|
+
const key = resolveItemKey(item, index, params.keyExtractor);
|
|
314
334
|
let anyViewable = false;
|
|
315
335
|
for (const pair of params.pairs) {
|
|
316
336
|
if (pair.viewabilityConfig.waitForInteraction === true &&
|
|
317
337
|
!params.hasInteracted) {
|
|
318
338
|
continue;
|
|
319
339
|
}
|
|
320
|
-
if (isCellViewable(
|
|
340
|
+
if (isCellViewable(params.offsets[index], params.lengths[index], params.scrollOffset, params.viewportLength, pair.viewabilityConfig)) {
|
|
321
341
|
anyViewable = true;
|
|
322
342
|
break;
|
|
323
343
|
}
|
|
@@ -488,10 +508,24 @@ export function computeMvcpAdjustment(params) {
|
|
|
488
508
|
action: { kind: 'shift', offset: params.scrollOffset + insertedExtent },
|
|
489
509
|
};
|
|
490
510
|
}
|
|
491
|
-
//
|
|
492
|
-
//
|
|
511
|
+
// RN's real default (`VirtualizeUtils.js`'s `keyExtractor`): an object item's own `key`, else its
|
|
512
|
+
// `id`, else the index. Most apps never pass `keyExtractor` at all and rely on this to keep list
|
|
513
|
+
// identity stable across inserts/removes — falling straight to the index (what this used to do)
|
|
514
|
+
// silently breaks that the moment two items swap position.
|
|
515
|
+
export function defaultKeyExtractor(item, index) {
|
|
516
|
+
if (typeof item === 'object' && item !== null) {
|
|
517
|
+
const record = item;
|
|
518
|
+
if (record.key !== undefined && record.key !== null)
|
|
519
|
+
return String(record.key);
|
|
520
|
+
if (record.id !== undefined && record.id !== null)
|
|
521
|
+
return String(record.id);
|
|
522
|
+
}
|
|
523
|
+
return String(index);
|
|
524
|
+
}
|
|
525
|
+
// The default key extractor: the caller's keyExtractor when set, else `defaultKeyExtractor`.
|
|
526
|
+
// Centralized so every adapter's keyForIndex resolves keys identically.
|
|
493
527
|
export function resolveItemKey(item, index, keyExtractor) {
|
|
494
|
-
return keyExtractor
|
|
528
|
+
return (keyExtractor ?? defaultKeyExtractor)(item, index);
|
|
495
529
|
}
|
|
496
530
|
// Linear item -> index lookup for scrollToItem (RN scans by reference identity). NO_INDEX when the
|
|
497
531
|
// item is not in data.
|
package/build/text-props.d.ts
CHANGED
|
@@ -1,9 +1 @@
|
|
|
1
1
|
export type IEllipsizeMode = 'head' | 'middle' | 'tail' | 'clip';
|
|
2
|
-
export interface ITextDefaultableProps {
|
|
3
|
-
ellipsizeMode?: IEllipsizeMode;
|
|
4
|
-
allowFontScaling?: boolean;
|
|
5
|
-
}
|
|
6
|
-
export declare function resolveTextProps<T extends ITextDefaultableProps>(props: T): T & {
|
|
7
|
-
ellipsizeMode: IEllipsizeMode;
|
|
8
|
-
allowFontScaling: boolean;
|
|
9
|
-
};
|
package/build/text-props.js
CHANGED
|
@@ -1,25 +1,14 @@
|
|
|
1
|
-
// The
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
-
// stable. A fold with two branches that emit different key sets is the exact hazard
|
|
16
|
-
// .claude/rules/solid-descriptor-bridge.md §1 exists for, and Svelte's shim diffs the same way.
|
|
17
|
-
export function resolveTextProps(props) {
|
|
18
|
-
return {
|
|
19
|
-
...props,
|
|
20
|
-
ellipsizeMode: props.ellipsizeMode ?? 'tail',
|
|
21
|
-
// `!== false`, not `?? true`: RN treats an explicit `undefined` and a missing prop alike, and
|
|
22
|
-
// only a literal `false` opts out.
|
|
23
|
-
allowFontScaling: props.allowFontScaling !== false,
|
|
24
|
-
};
|
|
25
|
-
}
|
|
1
|
+
// The ellipsize modes a Text accepts. THE DEFAULTS THAT USED TO BE APPLIED HERE ARE GONE (2026-09-18)
|
|
2
|
+
// — they are the platform's, so they live in the engine's payload builder and reach every `RCTText`
|
|
3
|
+
// whoever authored it: `foldTextDefaults`, `SymbioteFabricProps.cpp`.
|
|
4
|
+
//
|
|
5
|
+
// `resolveTextProps` was the third implementation of a two-line rule. Its one runtime caller was
|
|
6
|
+
// Button's label, which wrote both keys onto a node the builder was about to default anyway — the
|
|
7
|
+
// same seed shape `seedTextDefaults` had in three adapters, at a smaller scale. The rule reaches
|
|
8
|
+
// that node by being keyed on the COMPONENT, so nothing has to hand it down.
|
|
9
|
+
//
|
|
10
|
+
// Why the original fold existed at all, kept because the bug is easy to reintroduce: we declared both
|
|
11
|
+
// props in all four adapters and applied NEITHER default, so native fell back to its own `clip`.
|
|
12
|
+
// Device-observed 2026-08-19 on examples/svelte — a Text with `numberOfLines={1}` cut mid-word with
|
|
13
|
+
// no ellipsis. Nothing failed; the text was simply wrong.
|
|
14
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ISymbioteEvent } from '@symbiote-native/engine';
|
|
2
2
|
import type { IAccessibilityProps, IAriaProps } from '../accessibility-props';
|
|
3
3
|
export interface IButtonProps extends IAccessibilityProps, IAriaProps {
|
|
4
4
|
title: string;
|
|
@@ -14,29 +14,6 @@ export interface IButtonProps extends IAccessibilityProps, IAriaProps {
|
|
|
14
14
|
nextFocusRight?: number;
|
|
15
15
|
nextFocusUp?: number;
|
|
16
16
|
}
|
|
17
|
-
export declare const BUTTON_ACCESSIBILITY_ROLE = "button";
|
|
18
|
-
export declare const buttonTextStyle: ITextStyle;
|
|
19
|
-
export declare const buttonViewStyle: IViewStyle;
|
|
20
|
-
/**
|
|
21
|
-
* The label style with `color` and `disabled` folded in.
|
|
22
|
-
*
|
|
23
|
-
* `color` tints the TEXT on iOS and the BUTTON on Android (Button.js:318-324), so on Android this
|
|
24
|
-
* ignores it — see `resolveButtonViewStyle`, which is where it lands there. `disabled` wins over
|
|
25
|
-
* `color` on both, because RN pushes `textDisabled` after the tint.
|
|
26
|
-
*/
|
|
27
|
-
export declare function resolveButtonTextStyle(color: string | undefined, disabled: boolean | undefined): ITextStyle;
|
|
28
|
-
/**
|
|
29
|
-
* The inner view's style with `color` and `disabled` folded in — `{}` on iOS in every combination,
|
|
30
|
-
* which is RN's own answer there and the reason the node looked droppable.
|
|
31
|
-
*/
|
|
32
|
-
export declare function resolveButtonViewStyle(color: string | undefined, disabled: boolean | undefined): IViewStyle;
|
|
33
|
-
/**
|
|
34
|
-
* The label as it is rendered: UPPERCASE on Android (Button.js:352-353).
|
|
35
|
-
*
|
|
36
|
-
* RN also asserts the title is a string one line above. Not reproduced: the assert is a dev-only
|
|
37
|
-
* `invariant`, and every adapter here types `title: string`.
|
|
38
|
-
*/
|
|
39
|
-
export declare function resolveButtonTitle(title: string): string;
|
|
40
17
|
/**
|
|
41
18
|
* Whether the button is disabled, which `aria-disabled` may decide on its own.
|
|
42
19
|
*
|
|
@@ -47,8 +24,3 @@ export declare function resolveButtonTitle(title: string): string;
|
|
|
47
24
|
export declare function resolveButtonDisabled(disabled: boolean | undefined, ariaDisabled: boolean | undefined, accessibilityState: {
|
|
48
25
|
disabled?: boolean;
|
|
49
26
|
} | undefined): boolean | undefined;
|
|
50
|
-
/**
|
|
51
|
-
* Button.js:356-359 — `'no'` becomes `'no-hide-descendants'`, so the label inside cannot take
|
|
52
|
-
* focus separately from the button that contains it.
|
|
53
|
-
*/
|
|
54
|
-
export declare function resolveButtonImportantForAccessibility(value: IAccessibilityProps['importantForAccessibility']): IAccessibilityProps['importantForAccessibility'];
|
|
@@ -12,85 +12,55 @@
|
|
|
12
12
|
// fold RN performs in `Button.js:326-331`. The engine folds those for every node
|
|
13
13
|
// (`core/engine/src/accessibility-props.ts`), so repeating it here would fold twice.
|
|
14
14
|
import { Platform } from '@symbiote-native/engine';
|
|
15
|
-
// Button.js:394-437, one constant per literal so a value cannot drift silently.
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
// Button.js:394-437, one constant per literal so a value cannot drift silently. The LABEL's seven
|
|
16
|
+
// went with `resolveButtonTextStyle` on 2026-09-18 — they live in `SymbioteFabricProps.cpp` beside
|
|
17
|
+
// the rule that reads them and are deliberately not duplicated here.
|
|
18
18
|
const ANDROID_BUTTON_BLUE = '#2196F3';
|
|
19
19
|
const ANDROID_DISABLED_BACKGROUND = '#dfdfdf';
|
|
20
|
-
const ANDROID_DISABLED_TEXT = '#a1a1a1';
|
|
21
|
-
const ANDROID_TEXT = 'white';
|
|
22
20
|
const ANDROID_ELEVATION = 4;
|
|
23
21
|
const ANDROID_DISABLED_ELEVATION = 0;
|
|
24
22
|
const ANDROID_BORDER_RADIUS = 2;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
// `
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// `
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
return style;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* The inner view's style with `color` and `disabled` folded in — `{}` on iOS in every combination,
|
|
71
|
-
* which is RN's own answer there and the reason the node looked droppable.
|
|
72
|
-
*/
|
|
73
|
-
export function resolveButtonViewStyle(color, disabled) {
|
|
74
|
-
if (Platform.OS !== 'android')
|
|
75
|
-
return buttonViewStyle;
|
|
76
|
-
const style = { ...buttonViewStyle };
|
|
77
|
-
if (color !== undefined)
|
|
78
|
-
style.backgroundColor = color;
|
|
79
|
-
if (disabled === true) {
|
|
80
|
-
style.elevation = ANDROID_DISABLED_ELEVATION;
|
|
81
|
-
style.backgroundColor = ANDROID_DISABLED_BACKGROUND;
|
|
82
|
-
}
|
|
83
|
-
return style;
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* The label as it is rendered: UPPERCASE on Android (Button.js:352-353).
|
|
87
|
-
*
|
|
88
|
-
* RN also asserts the title is a string one line above. Not reproduced: the assert is a dev-only
|
|
89
|
-
* `invariant`, and every adapter here types `title: string`.
|
|
90
|
-
*/
|
|
91
|
-
export function resolveButtonTitle(title) {
|
|
92
|
-
return Platform.OS === 'android' ? title.toUpperCase() : title;
|
|
93
|
-
}
|
|
23
|
+
// `BUTTON_ACCESSIBILITY_ROLE` and `resolveButtonImportantForAccessibility` WERE HERE and are gone
|
|
24
|
+
// (2026-09-18). Both are `foldButtonProps` in `SymbioteFabricProps.cpp` now, and neither had a
|
|
25
|
+
// caller left afterwards — only its own unit test, which is the shape this project calls a mirror:
|
|
26
|
+
// a JS copy of a rule that runs elsewhere, kept alive by the test that asserts it. It would have
|
|
27
|
+
// stayed green forever while meaning nothing.
|
|
28
|
+
// `buttonTextStyle` AND `resolveButtonTextStyle` ARE GONE (2026-09-18) — the label's style is
|
|
29
|
+
// `foldButtonLabelStyle` in `SymbioteFabricProps.cpp`, reached off the label text's own tag. Its
|
|
30
|
+
// constants live THERE now and are not mirrored here; this file keeps only what Android's own fold
|
|
31
|
+
// still needs.
|
|
32
|
+
//
|
|
33
|
+
// It was the last rule in this primitive to move and it needed a seam none of the others did. Its
|
|
34
|
+
// inputs are the BUTTON's `color` and `disabled`, and the node it hangs on is the button's
|
|
35
|
+
// GRANDCHILD on iOS (`button -> view -> text`) and its child on Android — so `ownerProps`, which
|
|
36
|
+
// answers "my parent", could not reach it. `IAncestorLookup` asks for the nearest ancestor carrying
|
|
37
|
+
// a tag instead, which is a CSS ancestor selector and makes one rule right on both trees.
|
|
38
|
+
// `buttonViewStyle` AND `resolveButtonViewStyle` ARE GONE (2026-09-18), and with them the last of
|
|
39
|
+
// Button's folds. The Material look is inside `foldButtonProps` in `SymbioteFabricProps.cpp`, behind
|
|
40
|
+
// `#ifdef ANDROID` — where it belongs, since `{}` on iOS was the whole of its other branch.
|
|
41
|
+
//
|
|
42
|
+
// Its five constants went too rather than staying as a copy nothing reads.
|
|
43
|
+
//
|
|
44
|
+
// WHAT MADE THIS ONE DIFFERENT from the four ports before it: the Android branch is no longer
|
|
45
|
+
// untestable. The test host grew an arm that compiles `#ifdef ANDROID`
|
|
46
|
+
// (`core/engine/cpp/tests/CMakeLists.txt`, `SYMBIOTE_PLATFORM_ANDROID`), so the style, the `color`
|
|
47
|
+
// override and the disabled greying are asserted against the COMMITTED PAYLOAD in
|
|
48
|
+
// `core/engine/cpp/tests/js/android-rules.itest.ts` — strictly better than the mocked-`Platform.OS`
|
|
49
|
+
// unit test that went with them, which asserted a JS function rather than what Fabric receives.
|
|
50
|
+
// `resolveButtonTitle` IS GONE (2026-09-18) — the uppercase-on-Android rule is `foldButtonLabel` in
|
|
51
|
+
// `SymbioteFabricProps.cpp`, reached off the label's own tag. It had no caller left but its own two
|
|
52
|
+
// unit tests, which is the orphan shape this migration keeps turning up: a JS copy of a rule that
|
|
53
|
+
// runs elsewhere, kept alive by the test asserting it, green forever and proving nothing.
|
|
54
|
+
//
|
|
55
|
+
// A COVERAGE GAP WENT WITH IT, recorded rather than hidden. The C++ rule is `#ifdef ANDROID` — a raw
|
|
56
|
+
// text commits as `RCTRawText` on both platforms, so unlike `Switch`/`AndroidSwitch` there is no view
|
|
57
|
+
// NAME for a rule to branch on — and this host is not Android. The deleted Android test reached the
|
|
58
|
+
// branch by mocking `Platform.OS`; what it mocked was a JS function that no longer exists. Same
|
|
59
|
+
// class as `android_ripple` and `decelerationRate`'s constants, and closing it means an Android arm
|
|
60
|
+
// of the test host, not a mock.
|
|
61
|
+
//
|
|
62
|
+
// One behaviour difference shipped with the move and is deliberate: RN uppercases through
|
|
63
|
+
// JavaScript's full-Unicode `toUpperCase`, and the C++ rule is ASCII-only. See `foldButtonLabel`.
|
|
94
64
|
/**
|
|
95
65
|
* Whether the button is disabled, which `aria-disabled` may decide on its own.
|
|
96
66
|
*
|
|
@@ -103,10 +73,3 @@ export function resolveButtonDisabled(disabled, ariaDisabled, accessibilityState
|
|
|
103
73
|
return disabled;
|
|
104
74
|
return ariaDisabled ?? accessibilityState?.disabled;
|
|
105
75
|
}
|
|
106
|
-
/**
|
|
107
|
-
* Button.js:356-359 — `'no'` becomes `'no-hide-descendants'`, so the label inside cannot take
|
|
108
|
-
* focus separately from the button that contains it.
|
|
109
|
-
*/
|
|
110
|
-
export function resolveButtonImportantForAccessibility(value) {
|
|
111
|
-
return value === 'no' ? 'no-hide-descendants' : value;
|
|
112
|
-
}
|
|
@@ -54,5 +54,18 @@ export type IImageViewProps = {
|
|
|
54
54
|
passthrough: Record<string, unknown>;
|
|
55
55
|
};
|
|
56
56
|
export declare const IMAGE_VIEW_PROP_NAMES: readonly ["source", "defaultSource", "loadingIndicatorSource", "style", "resizeMode", "tintColor", "src", "srcSet", "alt", "width", "height", "crossOrigin", "referrerPolicy"];
|
|
57
|
-
|
|
57
|
+
/**
|
|
58
|
+
* `mapImageProps` STOOD HERE and is now the engine's — `foldImageProps` in
|
|
59
|
+
* `SymbioteFabricProps.cpp`, with `core/engine/cpp/tests/js/image-payload.itest.ts` as its contract.
|
|
60
|
+
*
|
|
61
|
+
* WHAT IS LEFT IS A GATHER, NOT A FOLD, and the distinction is the whole change. This flattens a
|
|
62
|
+
* typed view object back into the bag an app authored — the `<image>` tag then receives those names
|
|
63
|
+
* verbatim and the engine resolves them at commit, once, for every adapter. Angular is the caller
|
|
64
|
+
* that kept this path alive (its `<Image>` component has typed `@Input()`s rather than a prop bag);
|
|
65
|
+
* it now hands the tag raw props like every other adapter does.
|
|
66
|
+
*
|
|
67
|
+
* So the aliases (`src`, `srcSet`, `alt`, `width`, `height`, `crossOrigin`, `referrerPolicy`) leave
|
|
68
|
+
* here UNRESOLVED on purpose. Resolving them would be the second implementation this file's own
|
|
69
|
+
* header spent four lines warning about.
|
|
70
|
+
*/
|
|
58
71
|
export declare function renderImage(view: IImageViewProps): IDescriptor;
|