@symbiote-native/angular 3.0.2 → 3.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.
- package/build/angular/callback-host.d.ts +2 -5
- package/build/angular/callback-host.js +11 -36
- package/build/angular/callback-host.js.map +1 -1
- package/build/angular/change-detection-flush.d.ts +1 -0
- package/build/angular/change-detection-flush.js +58 -14
- package/build/angular/change-detection-flush.js.map +1 -1
- package/build/angular/components/flat-list/index.d.ts +4 -2
- package/build/angular/components/flat-list/index.js +28 -78
- package/build/angular/components/flat-list/index.js.map +1 -1
- package/build/angular/components/image-shared.d.ts +8 -2
- package/build/angular/components/modal/index.d.ts +1 -0
- package/build/angular/components/modal/index.js +23 -16
- package/build/angular/components/modal/index.js.map +1 -1
- package/build/angular/components/section-list/index.d.ts +3 -1
- package/build/angular/components/section-list/index.js +10 -2
- package/build/angular/components/section-list/index.js.map +1 -1
- package/build/angular/components/virtualized-list/directives.js +7 -4
- package/build/angular/components/virtualized-list/directives.js.map +1 -1
- package/build/angular/components/virtualized-list/index.d.ts +10 -2
- package/build/angular/components/virtualized-list/index.js +45 -25
- package/build/angular/components/virtualized-list/index.js.map +1 -1
- package/build/angular/components/virtualized-section-list/index.d.ts +5 -1
- package/build/angular/components/virtualized-section-list/index.js +10 -2
- package/build/angular/components/virtualized-section-list/index.js.map +1 -1
- package/build/angular/element-props.d.ts +16 -5
- package/build/angular/elements.d.ts +5 -21
- package/build/angular/elements.js +18 -26
- package/build/angular/elements.js.map +1 -1
- package/build/angular/index.d.ts +0 -1
- package/build/angular/index.js +5 -7
- package/build/angular/index.js.map +1 -1
- package/build/angular/renderer/index.d.ts +11 -0
- package/build/angular/renderer/index.js +97 -12
- package/build/angular/renderer/index.js.map +1 -1
- package/build/angular/runtime-matching.d.ts +0 -1
- package/build/angular/runtime-matching.js +6 -29
- package/build/angular/runtime-matching.js.map +1 -1
- package/package.json +4 -4
- package/src/callback-host.ts +10 -43
- package/src/change-detection-flush.ts +67 -14
- package/src/components/flat-list/index.ts +22 -54
- package/src/components/modal/index.ts +22 -16
- package/src/components/section-list/index.ts +4 -0
- package/src/components/virtualized-list/directives.ts +10 -8
- package/src/components/virtualized-list/index.ts +38 -13
- package/src/components/virtualized-section-list/index.ts +6 -0
- package/src/element-props.ts +22 -13
- package/src/elements.ts +21 -56
- package/src/index.ts +5 -7
- package/src/renderer/index.ts +107 -11
- package/src/runtime-matching.ts +6 -30
- package/build/angular/style-host.d.ts +0 -11
- package/build/angular/style-host.js +0 -86
- package/build/angular/style-host.js.map +0 -1
- package/src/style-host.ts +0 -94
|
@@ -177,6 +177,8 @@ export type ISectionListInputs<ItemT> = Omit<
|
|
|
177
177
|
[scrollEventThrottle]="scrollEventThrottle"
|
|
178
178
|
[keyboardShouldPersistTaps]="keyboardShouldPersistTaps"
|
|
179
179
|
[keyboardDismissMode]="keyboardDismissMode"
|
|
180
|
+
[removeClippedSubviews]="removeClippedSubviews"
|
|
181
|
+
[nestedScrollEnabled]="nestedScrollEnabled"
|
|
180
182
|
[style]="resolvedStyle"
|
|
181
183
|
[contentContainerStyle]="contentContainerStyle"
|
|
182
184
|
[testID]="testID"
|
|
@@ -343,6 +345,8 @@ export class SectionList<ItemT = unknown>
|
|
|
343
345
|
@Input() scrollEventThrottle?: number;
|
|
344
346
|
@Input() keyboardShouldPersistTaps?: boolean | 'always' | 'never' | 'handled';
|
|
345
347
|
@Input() keyboardDismissMode?: 'none' | 'on-drag' | 'interactive';
|
|
348
|
+
@Input() removeClippedSubviews?: boolean;
|
|
349
|
+
@Input() nestedScrollEnabled?: boolean;
|
|
346
350
|
@Input() style?: IStyleProp<IViewStyle>;
|
|
347
351
|
@Input() contentContainerStyle?: IStyleProp<IViewStyle>;
|
|
348
352
|
@Input() testID?: string;
|
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
type OnDestroy,
|
|
36
36
|
type SimpleChanges,
|
|
37
37
|
} from '@angular/core';
|
|
38
|
-
import { dlog } from '@symbiote-native/engine';
|
|
38
|
+
import { dlog, isDebug } from '@symbiote-native/engine';
|
|
39
39
|
import { countAngular } from '../../diagnostics';
|
|
40
40
|
import type { ISeparators } from '@symbiote-native/components';
|
|
41
41
|
|
|
@@ -129,9 +129,10 @@ export class VListOutletDirective<C = unknown> implements OnChanges, OnDestroy {
|
|
|
129
129
|
|
|
130
130
|
ngOnChanges(changes: SimpleChanges): void {
|
|
131
131
|
if (changes['templateRef'] !== undefined) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
if (isDebug())
|
|
133
|
+
dlog(
|
|
134
|
+
`Angular VListOutlet#${this.instanceId} templateRef CHANGED (was=${changes['templateRef'].previousValue !== undefined} now=${this.templateRef !== undefined}) -> clear + recreate`,
|
|
135
|
+
);
|
|
135
136
|
this.viewContainer.clear();
|
|
136
137
|
countAngular('outletCreates');
|
|
137
138
|
this.viewRef =
|
|
@@ -145,9 +146,10 @@ export class VListOutletDirective<C = unknown> implements OnChanges, OnDestroy {
|
|
|
145
146
|
}
|
|
146
147
|
if (this.viewRef !== null && this.context !== undefined) {
|
|
147
148
|
countAngular('outletUpdates');
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
149
|
+
if (isDebug())
|
|
150
|
+
dlog(
|
|
151
|
+
`Angular VListOutlet#${this.instanceId} context updated, markForCheck`,
|
|
152
|
+
);
|
|
151
153
|
this.updateContext(this.viewRef.context, this.context);
|
|
152
154
|
this.viewRef.markForCheck();
|
|
153
155
|
}
|
|
@@ -155,7 +157,7 @@ export class VListOutletDirective<C = unknown> implements OnChanges, OnDestroy {
|
|
|
155
157
|
|
|
156
158
|
ngOnDestroy(): void {
|
|
157
159
|
countAngular('outletDestroys');
|
|
158
|
-
dlog(`Angular VListOutlet#${this.instanceId} destroyed`);
|
|
160
|
+
if (isDebug()) dlog(`Angular VListOutlet#${this.instanceId} destroyed`);
|
|
159
161
|
this.viewContainer.clear();
|
|
160
162
|
}
|
|
161
163
|
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
EventEmitter,
|
|
35
35
|
Input,
|
|
36
36
|
Output,
|
|
37
|
+
TemplateRef,
|
|
37
38
|
ViewChild,
|
|
38
39
|
computed,
|
|
39
40
|
inject,
|
|
@@ -183,6 +184,8 @@ export interface IVirtualizedListProps<ItemT>
|
|
|
183
184
|
scrollEventThrottle?: number;
|
|
184
185
|
keyboardShouldPersistTaps?: boolean | 'always' | 'never' | 'handled';
|
|
185
186
|
keyboardDismissMode?: 'none' | 'on-drag' | 'interactive';
|
|
187
|
+
removeClippedSubviews?: boolean;
|
|
188
|
+
nestedScrollEnabled?: boolean;
|
|
186
189
|
style?: IStyleProp<IViewStyle>;
|
|
187
190
|
contentContainerStyle?: IStyleProp<IViewStyle>;
|
|
188
191
|
}
|
|
@@ -267,7 +270,7 @@ interface IWindowCell<ItemT> {
|
|
|
267
270
|
[style]="cellStyle"
|
|
268
271
|
>
|
|
269
272
|
<ng-container
|
|
270
|
-
[vListOutlet]="
|
|
273
|
+
[vListOutlet]="cellTemplate"
|
|
271
274
|
[vListOutletContext]="forcedStickyCell.context"
|
|
272
275
|
></ng-container>
|
|
273
276
|
</sticky-header>
|
|
@@ -282,12 +285,12 @@ interface IWindowCell<ItemT> {
|
|
|
282
285
|
[style]="cellStyle"
|
|
283
286
|
>
|
|
284
287
|
<ng-container
|
|
285
|
-
[vListOutlet]="
|
|
288
|
+
[vListOutlet]="cellTemplate"
|
|
286
289
|
[vListOutletContext]="cell.context"
|
|
287
290
|
></ng-container>
|
|
288
291
|
@if (cell.separatorContext !== undefined) {
|
|
289
292
|
<ng-container
|
|
290
|
-
[vListOutlet]="
|
|
293
|
+
[vListOutlet]="separatorTemplate"
|
|
291
294
|
[vListOutletContext]="cell.separatorContext"
|
|
292
295
|
></ng-container>
|
|
293
296
|
}
|
|
@@ -298,12 +301,12 @@ interface IWindowCell<ItemT> {
|
|
|
298
301
|
[style]="cellStyle"
|
|
299
302
|
>
|
|
300
303
|
<ng-container
|
|
301
|
-
[vListOutlet]="
|
|
304
|
+
[vListOutlet]="cellTemplate"
|
|
302
305
|
[vListOutletContext]="cell.context"
|
|
303
306
|
></ng-container>
|
|
304
307
|
@if (cell.separatorContext !== undefined) {
|
|
305
308
|
<ng-container
|
|
306
|
-
[vListOutlet]="
|
|
309
|
+
[vListOutlet]="separatorTemplate"
|
|
307
310
|
[vListOutletContext]="cell.separatorContext"
|
|
308
311
|
></ng-container>
|
|
309
312
|
}
|
|
@@ -351,7 +354,7 @@ interface IWindowCell<ItemT> {
|
|
|
351
354
|
[style]="cellStyle"
|
|
352
355
|
>
|
|
353
356
|
<ng-container
|
|
354
|
-
[vListOutlet]="
|
|
357
|
+
[vListOutlet]="cellTemplate"
|
|
355
358
|
[vListOutletContext]="forcedStickyCell.context"
|
|
356
359
|
></ng-container>
|
|
357
360
|
</sticky-header>
|
|
@@ -373,12 +376,12 @@ interface IWindowCell<ItemT> {
|
|
|
373
376
|
[style]="cellStyle"
|
|
374
377
|
>
|
|
375
378
|
<ng-container
|
|
376
|
-
[vListOutlet]="
|
|
379
|
+
[vListOutlet]="cellTemplate"
|
|
377
380
|
[vListOutletContext]="cell.context"
|
|
378
381
|
></ng-container>
|
|
379
382
|
@if (cell.separatorContext !== undefined) {
|
|
380
383
|
<ng-container
|
|
381
|
-
[vListOutlet]="
|
|
384
|
+
[vListOutlet]="separatorTemplate"
|
|
382
385
|
[vListOutletContext]="cell.separatorContext"
|
|
383
386
|
></ng-container>
|
|
384
387
|
}
|
|
@@ -389,12 +392,12 @@ interface IWindowCell<ItemT> {
|
|
|
389
392
|
[style]="cellStyle"
|
|
390
393
|
>
|
|
391
394
|
<ng-container
|
|
392
|
-
[vListOutlet]="
|
|
395
|
+
[vListOutlet]="cellTemplate"
|
|
393
396
|
[vListOutletContext]="cell.context"
|
|
394
397
|
></ng-container>
|
|
395
398
|
@if (cell.separatorContext !== undefined) {
|
|
396
399
|
<ng-container
|
|
397
|
-
[vListOutlet]="
|
|
400
|
+
[vListOutlet]="separatorTemplate"
|
|
398
401
|
[vListOutletContext]="cell.separatorContext"
|
|
399
402
|
></ng-container>
|
|
400
403
|
}
|
|
@@ -500,6 +503,8 @@ export class VirtualizedList<ItemT = unknown>
|
|
|
500
503
|
@Input() scrollEventThrottle?: number;
|
|
501
504
|
@Input() keyboardShouldPersistTaps?: boolean | 'always' | 'never' | 'handled';
|
|
502
505
|
@Input() keyboardDismissMode?: 'none' | 'on-drag' | 'interactive';
|
|
506
|
+
@Input() removeClippedSubviews?: boolean;
|
|
507
|
+
@Input() nestedScrollEnabled?: boolean;
|
|
503
508
|
@Input() style?: IStyleProp<IViewStyle>;
|
|
504
509
|
@Input() contentContainerStyle?: IStyleProp<IViewStyle>;
|
|
505
510
|
@Input() testID?: string;
|
|
@@ -550,6 +555,20 @@ export class VirtualizedList<ItemT = unknown>
|
|
|
550
555
|
@ContentChild(VListSeparatorDirective)
|
|
551
556
|
separatorDir?: VListSeparatorDirective<ItemT>;
|
|
552
557
|
|
|
558
|
+
// A wrapping list (FlatList) hands its app's cell/separator templates straight in, so a cell is
|
|
559
|
+
// one outlet deep instead of a wrapper outlet around the app's own; each wins over projection.
|
|
560
|
+
@Input() itemTemplate?: TemplateRef<IVListItemContext<ItemT>>;
|
|
561
|
+
@Input() itemSeparatorTemplate?: TemplateRef<IVListSeparatorContext<ItemT>>;
|
|
562
|
+
|
|
563
|
+
get cellTemplate(): TemplateRef<IVListItemContext<ItemT>> | undefined {
|
|
564
|
+
return this.itemTemplate ?? this.itemDir?.templateRef;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
get separatorTemplate():
|
|
568
|
+
TemplateRef<IVListSeparatorContext<ItemT>> | undefined {
|
|
569
|
+
return this.itemSeparatorTemplate ?? this.separatorDir?.templateRef;
|
|
570
|
+
}
|
|
571
|
+
|
|
553
572
|
// The inner scroll TAG's own engine node — a template ref on a bare intrinsic hands back the
|
|
554
573
|
// host node directly (`isSymbioteNode(elementRef.nativeElement)`, matching `anchorHostStyle`'s
|
|
555
574
|
// own reader below), so there is no wrapper component left to read a handle off. Present from
|
|
@@ -739,6 +758,11 @@ export class VirtualizedList<ItemT = unknown>
|
|
|
739
758
|
scrollEventThrottle: this.scrollEventThrottle,
|
|
740
759
|
keyboardShouldPersistTaps: this.keyboardShouldPersistTaps,
|
|
741
760
|
keyboardDismissMode: this.keyboardDismissMode,
|
|
761
|
+
// RN's VirtualizedList spreads its props onto the ScrollView, this one included.
|
|
762
|
+
removeClippedSubviews: this.removeClippedSubviews,
|
|
763
|
+
nestedScrollEnabled: this.nestedScrollEnabled,
|
|
764
|
+
// VirtualizedList.js:1111 — Android moves the scrollbar back after the `scale: -1` flip.
|
|
765
|
+
isInvertedVirtualizedList: this.isInverted ? true : undefined,
|
|
742
766
|
contentOffset: this.commandedOffset,
|
|
743
767
|
// `stickyHeaderIndices` is deliberately NOT forwarded — it numbers the scroll view's PAINT
|
|
744
768
|
// children, and a windowed list paints a header, a spacer and a slice, so the positions move
|
|
@@ -1041,7 +1065,7 @@ export class VirtualizedList<ItemT = unknown>
|
|
|
1041
1065
|
this.headerDir !== undefined,
|
|
1042
1066
|
this.footerDir !== undefined,
|
|
1043
1067
|
this.emptyDir !== undefined,
|
|
1044
|
-
this.
|
|
1068
|
+
this.separatorTemplate !== undefined,
|
|
1045
1069
|
];
|
|
1046
1070
|
const previous = this.lastRecompute;
|
|
1047
1071
|
this.lastRecompute = recomputeInputs;
|
|
@@ -1076,7 +1100,7 @@ export class VirtualizedList<ItemT = unknown>
|
|
|
1076
1100
|
const m = this.listState.metrics;
|
|
1077
1101
|
this.itemCount = m.count;
|
|
1078
1102
|
const hasHeader = this.headerDir !== undefined;
|
|
1079
|
-
const hasSeparators = this.
|
|
1103
|
+
const hasSeparators = this.separatorTemplate !== undefined;
|
|
1080
1104
|
const stickySet =
|
|
1081
1105
|
this.stickyHeaderIndices !== undefined
|
|
1082
1106
|
? new Set(this.stickyHeaderIndices)
|
|
@@ -1087,8 +1111,9 @@ export class VirtualizedList<ItemT = unknown>
|
|
|
1087
1111
|
: this.contentContainerStyle;
|
|
1088
1112
|
this.resolvedStyle = flattenStyle([
|
|
1089
1113
|
anchorHostStyle(this.elementRef),
|
|
1114
|
+
// VirtualizedList.js: `[inversionStyle, style]` — the app's style can override the flip.
|
|
1090
1115
|
this.isInverted
|
|
1091
|
-
? [this.
|
|
1116
|
+
? [this.isHorizontal ? INVERTED_X_STYLE : INVERTED_Y_STYLE, this.style]
|
|
1092
1117
|
: this.style,
|
|
1093
1118
|
]);
|
|
1094
1119
|
this.cellStyle = this.isInverted
|
|
@@ -146,6 +146,8 @@ export interface IVirtualizedSectionListProps<ItemT>
|
|
|
146
146
|
scrollEventThrottle?: number;
|
|
147
147
|
keyboardShouldPersistTaps?: boolean | 'always' | 'never' | 'handled';
|
|
148
148
|
keyboardDismissMode?: 'none' | 'on-drag' | 'interactive';
|
|
149
|
+
removeClippedSubviews?: boolean;
|
|
150
|
+
nestedScrollEnabled?: boolean;
|
|
149
151
|
style?: IStyleProp<IViewStyle>;
|
|
150
152
|
contentContainerStyle?: IStyleProp<IViewStyle>;
|
|
151
153
|
}
|
|
@@ -213,6 +215,8 @@ export type IVirtualizedSectionListInputs<ItemT> = Omit<
|
|
|
213
215
|
[scrollEventThrottle]="scrollEventThrottle"
|
|
214
216
|
[keyboardShouldPersistTaps]="keyboardShouldPersistTaps"
|
|
215
217
|
[keyboardDismissMode]="keyboardDismissMode"
|
|
218
|
+
[removeClippedSubviews]="removeClippedSubviews"
|
|
219
|
+
[nestedScrollEnabled]="nestedScrollEnabled"
|
|
216
220
|
[style]="resolvedStyle"
|
|
217
221
|
[contentContainerStyle]="contentContainerStyle"
|
|
218
222
|
[testID]="testID"
|
|
@@ -375,6 +379,8 @@ export class VirtualizedSectionList<ItemT = unknown>
|
|
|
375
379
|
@Input() scrollEventThrottle?: number;
|
|
376
380
|
@Input() keyboardShouldPersistTaps?: boolean | 'always' | 'never' | 'handled';
|
|
377
381
|
@Input() keyboardDismissMode?: 'none' | 'on-drag' | 'interactive';
|
|
382
|
+
@Input() removeClippedSubviews?: boolean;
|
|
383
|
+
@Input() nestedScrollEnabled?: boolean;
|
|
378
384
|
@Input() style?: IStyleProp<IViewStyle>;
|
|
379
385
|
@Input() contentContainerStyle?: IStyleProp<IViewStyle>;
|
|
380
386
|
@Input() testID?: string;
|
package/src/element-props.ts
CHANGED
|
@@ -8,13 +8,9 @@
|
|
|
8
8
|
// differ, since a bare tag takes children from the template and a handle from `#ref`, so neither
|
|
9
9
|
// `children` nor `ref` appears here.
|
|
10
10
|
//
|
|
11
|
-
// `style`
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// aborting the enclosing template update — which is what an app writes, and what every deleted
|
|
15
|
-
// wrapper component accepted. The claim that a directive can reclaim it "solely by executing a
|
|
16
|
-
// linked AOT artifact" was answered rather than assumed: `elements.test.ts` compiles the binding
|
|
17
|
-
// through real ngtsc and runs the LINKED output. See `SymbioteElement.style`.
|
|
11
|
+
// `style` and `styleProp` are TWO bindings. `[style]` is Angular's styling binding: an object or CSS
|
|
12
|
+
// string, as on a DOM element, unclaimed because a claim is a directive instance per element. An RN
|
|
13
|
+
// array or press-state callback throws in that engine, so it travels as `[styleProp]`.
|
|
18
14
|
import type {
|
|
19
15
|
IAccessibilityProps,
|
|
20
16
|
IAriaProps,
|
|
@@ -31,6 +27,17 @@ import type {
|
|
|
31
27
|
|
|
32
28
|
type IEventHandler = (event: ISymbioteEvent) => void;
|
|
33
29
|
|
|
30
|
+
/**
|
|
31
|
+
* What `[style]` carries on a tag: Angular's own styling binding, decomposed key by key into
|
|
32
|
+
* `Renderer2.setStyle` exactly as on a DOM element. A style OBJECT or a CSS string - never an array
|
|
33
|
+
* or a function, which that engine cannot represent. Those are `[styleProp]`.
|
|
34
|
+
*/
|
|
35
|
+
export type IAngularStyleBinding<TStyle> = TStyle | string | null | undefined;
|
|
36
|
+
|
|
37
|
+
/** RN's full StyleProp, press-state callback included: the `[styleProp]` binding. */
|
|
38
|
+
export type IElementStyleProp =
|
|
39
|
+
IStyleProp<IViewStyle> | ((state: IPressState) => IStyleProp<IViewStyle>);
|
|
40
|
+
|
|
34
41
|
export interface IElementProps
|
|
35
42
|
extends IAccessibilityProps, IAriaProps, IResponderProps {
|
|
36
43
|
/** RN's modern W3C-named alias for `nativeID`; the renderer folds it (`PROP_ALIASES`). */
|
|
@@ -43,13 +50,14 @@ export interface IElementProps
|
|
|
43
50
|
renderToHardwareTextureAndroid?: boolean;
|
|
44
51
|
shouldRasterizeIOS?: boolean;
|
|
45
52
|
needsOffscreenAlphaCompositing?: boolean;
|
|
53
|
+
style?: IAngularStyleBinding<IViewStyle>;
|
|
46
54
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
55
|
+
* An RN StyleProp as ONE property binding: arrays, falsy entries, and the press-state callback.
|
|
56
|
+
* The callback is in the union because a subclass cannot widen an inherited property and
|
|
57
|
+
* `<pressable>`/`<touchable-*>` are the tags that take one; on every other tag the engine resolves
|
|
58
|
+
* it at `pressed: false`.
|
|
50
59
|
*/
|
|
51
|
-
|
|
52
|
-
IStyleProp<IViewStyle> | ((state: IPressState) => IStyleProp<IViewStyle>);
|
|
60
|
+
styleProp?: IElementStyleProp;
|
|
53
61
|
onPress?: IEventHandler;
|
|
54
62
|
onPressIn?: IEventHandler;
|
|
55
63
|
onPressOut?: IEventHandler;
|
|
@@ -63,7 +71,8 @@ export interface IElementProps
|
|
|
63
71
|
/** Text's own surface on top of the shared one. `onTextLayout` is an event, so it is not here. */
|
|
64
72
|
export interface ITextElementProps {
|
|
65
73
|
/** Narrows the shared `style` so `fontSize` / `fontWeight` type-check on a `<text>`. */
|
|
66
|
-
style?:
|
|
74
|
+
style?: IAngularStyleBinding<ITextStyle>;
|
|
75
|
+
styleProp?: IStyleProp<ITextStyle>;
|
|
67
76
|
numberOfLines?: number;
|
|
68
77
|
ellipsizeMode?: 'head' | 'middle' | 'tail' | 'clip';
|
|
69
78
|
selectable?: boolean;
|
package/src/elements.ts
CHANGED
|
@@ -58,7 +58,6 @@ import {
|
|
|
58
58
|
} from './change-detection-flush';
|
|
59
59
|
import { SymbioteCallbackHost } from './callback-host';
|
|
60
60
|
import { withholdFromRuntimeMatching } from './runtime-matching';
|
|
61
|
-
import { SymbioteStyleHost } from './style-host';
|
|
62
61
|
import type {
|
|
63
62
|
IActivityIndicatorProps,
|
|
64
63
|
IImageProps,
|
|
@@ -190,44 +189,21 @@ export abstract class SymbioteElement implements OnChanges {
|
|
|
190
189
|
@Input() shouldRasterizeIOS?: IElementProps['shouldRasterizeIOS'];
|
|
191
190
|
@Input()
|
|
192
191
|
needsOffscreenAlphaCompositing?: IElementProps['needsOffscreenAlphaCompositing'];
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
//
|
|
196
|
-
//
|
|
197
|
-
//
|
|
198
|
-
//
|
|
199
|
-
// in examples/angular painted as an empty bordered box, because the throw aborted the update
|
|
200
|
-
// before its `<text>` child was ever reached.
|
|
201
|
-
//
|
|
202
|
-
// A declared input CLAIMS the binding at compile time, so it never reaches the styling engine —
|
|
203
|
-
// the same mechanism the primitive host COMPONENTS have always relied on
|
|
204
|
-
// (`primitives/shared.ts`), which is why `<Pressable [style]>` worked and its replacement tag did
|
|
205
|
-
// not. `[style.borderWidth.px]` is a different instruction (`ɵɵstyleProp`) and is untouched: it
|
|
206
|
-
// still reaches `Renderer2.setStyle`, which merges per key.
|
|
192
|
+
// `[style]` and `[class]` are declared for the TYPE CHECK only. Withheld from run-time matching, no
|
|
193
|
+
// input claims them, so Angular's own styling engine decomposes them into `setStyle`/`addClass`
|
|
194
|
+
// exactly as on a DOM element - which is why `style` is typed as the object/string that engine can
|
|
195
|
+
// hold. An RN style ARRAY or press-state FUNCTION throws in there ("indexOf is not a function",
|
|
196
|
+
// "Unsupported styling type: function"), so it is `[styleProp]`: an ordinary property binding the
|
|
197
|
+
// renderer routes to `style` whole. A claim would cost a directive instance per element.
|
|
207
198
|
//
|
|
208
199
|
// The press-state callback rides the BASE type rather than `PressableElement` alone: a subclass
|
|
209
200
|
// cannot widen an inherited property, and only the pressables have a `pressed` to read — so on
|
|
210
|
-
// any other tag the engine resolves it at `pressed: false
|
|
211
|
-
// in what commits.
|
|
201
|
+
// any other tag the engine resolves it at `pressed: false`.
|
|
212
202
|
@Input() style?: IElementProps['style'];
|
|
203
|
+
@Input() styleProp?: IElementProps['styleProp'];
|
|
213
204
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
*
|
|
217
|
-
* A styling binding goes to a directive input when the directive declares that exact public name
|
|
218
|
-
* — `setShadowStylingInputFlags` sets `hasClassInput`/`hasStyleInput` off the input map, and
|
|
219
|
-
* `checkStylingMap` then hands the whole value over and never calls the renderer per key
|
|
220
|
-
* (`view/directives.ts`, `instructions/styling.ts`). `style` has been declared here all along and
|
|
221
|
-
* is shadowed; `class` was not, so every `[class]` reached the renderer one TOKEN at a time — on
|
|
222
|
-
* the element-directive path as much as the bare one. Measured at ~3.3 us per class binding
|
|
223
|
-
* (`adapter-create-cost.itest.ts`, "prices the class channel"), on the channel every example app
|
|
224
|
-
* uses for its static look.
|
|
225
|
-
*
|
|
226
|
-
* `[class.foo]` and `[ngClass]` are NOT shadowed and keep arriving as `addClass`, so a node can
|
|
227
|
-
* now be told its classes both ways at once; the renderer unions the two sources
|
|
228
|
-
* (`classStringFor`). Typed as a string rather than RN's `className`, because that is what
|
|
229
|
-
* `ɵɵclassMap` hands over after it concatenates any static `class=` prefix.
|
|
230
|
-
*/
|
|
205
|
+
// `ɵɵclassMap` hands over a string after joining any static `class=` prefix; `[class.foo]` and
|
|
206
|
+
// `[ngClass]` arrive as `addClass`. The renderer unions both sources (`classStringFor`).
|
|
231
207
|
@Input() class?: string;
|
|
232
208
|
|
|
233
209
|
// The flat-bag spelling of the events below. `(press)` and `[onPress]` are both supported and
|
|
@@ -422,6 +398,7 @@ export class TextElement extends SymbioteElement {
|
|
|
422
398
|
// initializer is what TS2612 asks for to accept a redeclaration as deliberate; `declare` would
|
|
423
399
|
// be the other answer and cannot carry a decorator.
|
|
424
400
|
@Input() override style?: ITextElementProps['style'] = undefined;
|
|
401
|
+
@Input() override styleProp?: ITextElementProps['styleProp'] = undefined;
|
|
425
402
|
@Input() numberOfLines?: ITextElementProps['numberOfLines'];
|
|
426
403
|
@Input() ellipsizeMode?: ITextElementProps['ellipsizeMode'];
|
|
427
404
|
@Input() selectable?: ITextElementProps['selectable'];
|
|
@@ -927,39 +904,27 @@ export const SYMBIOTE_ELEMENTS = [
|
|
|
927
904
|
// bind one and carries the `ChangeDetectorRef` their wrapper needs. It rides this list for the same
|
|
928
905
|
// reason the accessors do, and `elements.test.ts` subtracts it from the tag-coverage check by name.
|
|
929
906
|
SymbioteCallbackHost,
|
|
930
|
-
// The other attribute-matched one: it claims `[style]` and `[class]` so an RN style ARRAY never
|
|
931
|
-
// reaches Angular's styling engine, which cannot represent one and throws. See `style-host.ts`.
|
|
932
|
-
SymbioteStyleHost,
|
|
933
907
|
] as const;
|
|
934
908
|
|
|
935
909
|
// THE DIRECTIVES THAT GO ON MATCHING, and the list is the exceptions rather than the rule.
|
|
936
910
|
//
|
|
937
|
-
//
|
|
938
|
-
//
|
|
939
|
-
//
|
|
940
|
-
// check at ~8.5-9.4 us of run time per element, and `./runtime-matching` keeps the check while
|
|
941
|
-
// dropping the instance.
|
|
942
|
-
//
|
|
943
|
-
// These four cannot go, because they DO something when they are built:
|
|
911
|
+
// EVERY TAG DIRECTIVE IS WITHHELD. Each is `@Input()` declarations over one inherited `ngOnChanges`
|
|
912
|
+
// forwarding to the renderer (the call `ɵɵproperty` makes directly on an unclaimed element), so the
|
|
913
|
+
// instance bought a compile-time check at ~8 us of run time per element.
|
|
944
914
|
//
|
|
945
|
-
//
|
|
946
|
-
//
|
|
947
|
-
//
|
|
948
|
-
// refresh-control `ReadBackElement`, the same flush for the same reason
|
|
915
|
+
// The read-back tags (text-input, text-input-multiline, switch, refresh-control) need a synchronous
|
|
916
|
+
// view flush; the renderer marks them at creation and the flush finds their view lazily
|
|
917
|
+
// (`change-detection-flush.ts`). `[(value)]` reaches the renderer's `listen('valueChange')` bridge.
|
|
949
918
|
//
|
|
950
|
-
//
|
|
951
|
-
//
|
|
919
|
+
// `[style]`/`[class]` stay unclaimed as on a DOM element (see `SymbioteElement.style`). What still
|
|
920
|
+
// matches is selected on an ATTRIBUTE an app writes: the two form accessors and
|
|
921
|
+
// `SymbioteCallbackHost`.
|
|
952
922
|
withholdFromRuntimeMatching(
|
|
953
923
|
SYMBIOTE_ELEMENTS.filter(
|
|
954
924
|
directive =>
|
|
955
|
-
directive !== TextInputElement &&
|
|
956
|
-
directive !== MultilineTextInputElement &&
|
|
957
|
-
directive !== SwitchElement &&
|
|
958
|
-
directive !== RefreshControlElement &&
|
|
959
925
|
directive !== TextInputValueAccessor &&
|
|
960
926
|
directive !== SwitchValueAccessor &&
|
|
961
|
-
directive !== SymbioteCallbackHost
|
|
962
|
-
directive !== SymbioteStyleHost,
|
|
927
|
+
directive !== SymbioteCallbackHost,
|
|
963
928
|
),
|
|
964
929
|
);
|
|
965
930
|
|
package/src/index.ts
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
// `@Component`s on the `view` and `text` SELECTORS — a second mechanism on the same tags
|
|
10
10
|
// `SYMBIOTE_ELEMENTS` covers, kept for one stated reason their own header gives: "Declaring `style`
|
|
11
11
|
// as a real Angular input prevents Angular's CSS style engine from decomposing RN `StyleProp`
|
|
12
|
-
// arrays".
|
|
13
|
-
//
|
|
12
|
+
// arrays". A tag takes an array or press-state callback as `[styleProp]`, a plain property binding
|
|
13
|
+
// with no instance behind it.
|
|
14
14
|
//
|
|
15
15
|
// An app loses nothing it cannot spell better: `@ViewChild('ref')` on a template reference returns
|
|
16
16
|
// Angular's own `ElementRef<IHostInstance>`, whose `nativeElement` IS the engine host node — the same
|
|
@@ -146,10 +146,9 @@ export { setImageSourceResolver } from './components';
|
|
|
146
146
|
//
|
|
147
147
|
// They were removed on 2026-09-18 and put back the same hour. The reason to remove them is real: a
|
|
148
148
|
// withheld tag directive (`./runtime-matching`) is a compile-time declaration and nothing else, so
|
|
149
|
-
// what makes `<view [
|
|
150
|
-
//
|
|
151
|
-
//
|
|
152
|
-
// and then fails on a device the first time the app writes an array style.
|
|
149
|
+
// what makes `<view [onPress]="fn">` work at all is `SymbioteCallbackHost` claiming the name before
|
|
150
|
+
// `setDomProperty` throws NG0306. It rides this array, so a narrow `imports: [ViewElement]`
|
|
151
|
+
// type-checks and then fails on a device the first time the app binds an `on*` prop.
|
|
153
152
|
//
|
|
154
153
|
// WHAT PUTS THEM BACK is NG3004: `Unable to import directive ViewElement — the symbol is not
|
|
155
154
|
// exported from index.d.ts`. ngtsc resolves every directive reachable through an imported array to an
|
|
@@ -198,7 +197,6 @@ export {
|
|
|
198
197
|
CALLBACK_ATTRIBUTE_SELECTOR,
|
|
199
198
|
SymbioteCallbackHost,
|
|
200
199
|
} from './callback-host';
|
|
201
|
-
export { STYLE_HOST_SELECTOR, SymbioteStyleHost } from './style-host';
|
|
202
200
|
export type {
|
|
203
201
|
IElementProps,
|
|
204
202
|
IStickyHeaderElementProps,
|