@symbiote-native/angular 0.7.0 → 1.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 +3 -3
- package/babel-lower-host-primitives.cjs +636 -0
- package/babel-register-composed.cjs +21 -3
- package/build/angular/anchor-host-registry.js +3 -1
- package/build/angular/anchor-host-registry.js.map +1 -1
- package/build/angular/bootstrap.js +1 -1
- package/build/angular/bootstrap.js.map +1 -1
- package/build/angular/components/activity-indicator/index.android.js +7 -2
- package/build/angular/components/activity-indicator/index.android.js.map +1 -1
- package/build/angular/components/activity-indicator/index.ios.js +3 -1
- package/build/angular/components/activity-indicator/index.ios.js.map +1 -1
- package/build/angular/components/activity-indicator/shared.d.ts +1 -1
- package/build/angular/components/activity-indicator/shared.js +1 -1
- package/build/angular/components/activity-indicator/shared.js.map +1 -1
- package/build/angular/components/button.d.ts +3 -0
- package/build/angular/components/button.js +22 -5
- package/build/angular/components/button.js.map +1 -1
- package/build/angular/components/flat-list/index.d.ts +1 -1
- package/build/angular/components/flat-list/index.js +47 -14
- package/build/angular/components/flat-list/index.js.map +1 -1
- package/build/angular/components/image/index.android.js +4 -10
- package/build/angular/components/image/index.android.js.map +1 -1
- package/build/angular/components/image/index.ios.js +4 -10
- package/build/angular/components/image/index.ios.js.map +1 -1
- package/build/angular/components/image/shared.d.ts +4 -4
- package/build/angular/components/image/shared.js +51 -33
- package/build/angular/components/image/shared.js.map +1 -1
- package/build/angular/components/image-background.d.ts +3 -0
- package/build/angular/components/image-background.js +32 -9
- package/build/angular/components/image-background.js.map +1 -1
- package/build/angular/components/input-accessory-view/index.d.ts +2 -1
- package/build/angular/components/input-accessory-view/index.js +18 -16
- package/build/angular/components/input-accessory-view/index.js.map +1 -1
- package/build/angular/components/keyboard-avoiding-view/index.d.ts +3 -1
- package/build/angular/components/keyboard-avoiding-view/index.js +56 -19
- package/build/angular/components/keyboard-avoiding-view/index.js.map +1 -1
- package/build/angular/components/modal/index.d.ts +1 -0
- package/build/angular/components/modal/index.js +21 -10
- package/build/angular/components/modal/index.js.map +1 -1
- package/build/angular/components/pressable/index.d.ts +10 -5
- package/build/angular/components/pressable/index.js +61 -16
- package/build/angular/components/pressable/index.js.map +1 -1
- package/build/angular/components/refresh-control/index.d.ts +2 -1
- package/build/angular/components/refresh-control/index.js +13 -9
- package/build/angular/components/refresh-control/index.js.map +1 -1
- package/build/angular/components/safe-area-view/index.d.ts +3 -1
- package/build/angular/components/safe-area-view/index.js +22 -20
- package/build/angular/components/safe-area-view/index.js.map +1 -1
- package/build/angular/components/scroll-view/index.android.js +44 -14
- package/build/angular/components/scroll-view/index.android.js.map +1 -1
- package/build/angular/components/scroll-view/index.ios.js +13 -5
- package/build/angular/components/scroll-view/index.ios.js.map +1 -1
- package/build/angular/components/scroll-view/projection.d.ts +32 -0
- package/build/angular/components/scroll-view/projection.js +212 -47
- package/build/angular/components/scroll-view/projection.js.map +1 -1
- package/build/angular/components/scroll-view/shared.d.ts +2 -0
- package/build/angular/components/scroll-view/shared.js +48 -11
- package/build/angular/components/scroll-view/shared.js.map +1 -1
- package/build/angular/components/scroll-view/sticky-header.js +7 -3
- package/build/angular/components/scroll-view/sticky-header.js.map +1 -1
- package/build/angular/components/section-list/index.d.ts +9 -1
- package/build/angular/components/section-list/index.js +72 -18
- package/build/angular/components/section-list/index.js.map +1 -1
- package/build/angular/components/switch/index.android.js +23 -9
- package/build/angular/components/switch/index.android.js.map +1 -1
- package/build/angular/components/switch/index.ios.js +23 -9
- package/build/angular/components/switch/index.ios.js.map +1 -1
- package/build/angular/components/switch/shared.d.ts +1 -1
- package/build/angular/components/switch/shared.js +5 -2
- package/build/angular/components/switch/shared.js.map +1 -1
- package/build/angular/components/text-input.d.ts +8 -2
- package/build/angular/components/text-input.js +79 -34
- package/build/angular/components/text-input.js.map +1 -1
- package/build/angular/components/touchable/index.d.ts +36 -7
- package/build/angular/components/touchable/index.js +280 -72
- package/build/angular/components/touchable/index.js.map +1 -1
- package/build/angular/components/touchable-native-feedback/index.d.ts +2 -1
- package/build/angular/components/touchable-native-feedback/index.js +19 -17
- package/build/angular/components/touchable-native-feedback/index.js.map +1 -1
- package/build/angular/components/virtualized-list/directives.js +4 -0
- package/build/angular/components/virtualized-list/directives.js.map +1 -1
- package/build/angular/components/virtualized-list/index.d.ts +8 -2
- package/build/angular/components/virtualized-list/index.js +207 -61
- package/build/angular/components/virtualized-list/index.js.map +1 -1
- package/build/angular/components/virtualized-section-list/directives.js.map +1 -1
- package/build/angular/components/virtualized-section-list/index.d.ts +21 -1
- package/build/angular/components/virtualized-section-list/index.js +100 -22
- package/build/angular/components/virtualized-section-list/index.js.map +1 -1
- package/build/angular/components.d.ts +2 -2
- package/build/angular/components.js +1 -1
- package/build/angular/components.js.map +1 -1
- package/build/angular/create-portal/index.d.ts +11 -2
- package/build/angular/create-portal/index.js +42 -12
- package/build/angular/create-portal/index.js.map +1 -1
- package/build/angular/create-tunnel/index.js.map +1 -1
- package/build/angular/descriptor-to-angular/index.js +3 -1
- package/build/angular/descriptor-to-angular/index.js.map +1 -1
- package/build/angular/diagnostics.d.ts +33 -0
- package/build/angular/diagnostics.js +82 -0
- package/build/angular/diagnostics.js.map +1 -0
- package/build/angular/gate-demand.d.ts +37 -0
- package/build/angular/gate-demand.js +84 -0
- package/build/angular/gate-demand.js.map +1 -0
- package/build/angular/host-instance/index.js +1 -1
- package/build/angular/host-instance/index.js.map +1 -1
- package/build/angular/index.d.ts +6 -2
- package/build/angular/index.js +16 -1
- package/build/angular/index.js.map +1 -1
- package/build/angular/modules/animated/create-animated-component.d.ts +1 -0
- package/build/angular/modules/animated/create-animated-component.js +41 -18
- package/build/angular/modules/animated/create-animated-component.js.map +1 -1
- package/build/angular/modules/app-registry/index.js.map +1 -1
- package/build/angular/modules/status-bar/index.js +1 -1
- package/build/angular/modules/status-bar/index.js.map +1 -1
- package/build/angular/primitives/index.d.ts +31 -2
- package/build/angular/primitives/index.js +81 -3
- package/build/angular/primitives/index.js.map +1 -1
- package/build/angular/primitives/shared.d.ts +9 -1
- package/build/angular/primitives/shared.js +49 -3
- package/build/angular/primitives/shared.js.map +1 -1
- package/build/angular/register.d.ts +1 -0
- package/build/angular/register.js +35 -0
- package/build/angular/register.js.map +1 -0
- package/build/angular/render/index.js +51 -6
- package/build/angular/render/index.js.map +1 -1
- package/build/angular/renderer/index.d.ts +1 -0
- package/build/angular/renderer/index.js +157 -21
- package/build/angular/renderer/index.js.map +1 -1
- package/build/angular/services/color-scheme.service.js.map +1 -1
- package/build/angular/services/window-dimensions.service.js +1 -1
- package/build/angular/services/window-dimensions.service.js.map +1 -1
- package/build/angular/state-style.d.ts +9 -0
- package/build/angular/state-style.js +39 -0
- package/build/angular/state-style.js.map +1 -0
- package/metro-transformer.cjs +69 -0
- package/package.json +27 -8
- package/src/anchor-host-registry.ts +3 -1
- package/src/bootstrap.ts +4 -1
- package/src/components/activity-indicator/index.android.ts +7 -2
- package/src/components/activity-indicator/index.ios.ts +3 -1
- package/src/components/activity-indicator/shared.ts +32 -13
- package/src/components/button.ts +36 -6
- package/src/components/flat-list/index.ts +91 -29
- package/src/components/image/index.android.ts +9 -6
- package/src/components/image/index.ios.ts +9 -6
- package/src/components/image/shared.ts +110 -45
- package/src/components/image-background.ts +47 -10
- package/src/components/input-accessory-view/index.ts +41 -18
- package/src/components/keyboard-avoiding-view/index.ts +76 -22
- package/src/components/modal/index.ts +39 -12
- package/src/components/pressable/index.ts +121 -31
- package/src/components/refresh-control/index.ts +36 -13
- package/src/components/safe-area-view/index.ts +44 -19
- package/src/components/scroll-view/index.android.ts +31 -9
- package/src/components/scroll-view/index.ios.ts +17 -4
- package/src/components/scroll-view/projection.ts +290 -63
- package/src/components/scroll-view/shared.ts +124 -30
- package/src/components/scroll-view/sticky-header.ts +25 -8
- package/src/components/section-list/index.ts +79 -19
- package/src/components/switch/index.android.ts +18 -7
- package/src/components/switch/index.ios.ts +18 -7
- package/src/components/switch/shared.ts +15 -4
- package/src/components/text-input.ts +119 -31
- package/src/components/touchable/index.ts +339 -72
- package/src/components/touchable-native-feedback/index.ts +50 -18
- package/src/components/virtualized-list/directives.ts +19 -5
- package/src/components/virtualized-list/index.ts +292 -72
- package/src/components/virtualized-section-list/directives.ts +6 -3
- package/src/components/virtualized-section-list/index.ts +164 -34
- package/src/components.ts +6 -1
- package/src/create-portal/index.ts +47 -11
- package/src/create-tunnel/index.ts +3 -1
- package/src/descriptor-to-angular/index.ts +29 -8
- package/src/diagnostics.ts +138 -0
- package/src/gate-demand.ts +109 -0
- package/src/host-instance/index.ts +9 -3
- package/src/index.ts +33 -2
- package/src/modules/animated/create-animated-component.ts +67 -19
- package/src/modules/app-registry/index.ts +3 -1
- package/src/modules/status-bar/index.ts +13 -4
- package/src/primitives/index.ts +73 -2
- package/src/primitives/shared.ts +70 -9
- package/src/register.ts +43 -0
- package/src/render/index.ts +59 -7
- package/src/renderer/index.ts +209 -37
- package/src/services/color-scheme.service.ts +3 -1
- package/src/services/window-dimensions.service.ts +11 -4
- package/src/state-style.ts +39 -0
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
11
11
|
import {
|
|
12
12
|
anchorHostStyle,
|
|
13
|
-
|
|
13
|
+
ManagedSwitchHost,
|
|
14
14
|
SymbioteHostPropsDirective,
|
|
15
15
|
SymbioteStyleInputDirective,
|
|
16
16
|
} from '../../primitives';
|
|
@@ -20,10 +20,18 @@ export type { ISwitchProps, ISwitchTrackColor } from './shared';
|
|
|
20
20
|
@Component({
|
|
21
21
|
selector: 'Switch',
|
|
22
22
|
standalone: true,
|
|
23
|
-
hostDirectives: [
|
|
23
|
+
hostDirectives: [
|
|
24
|
+
{ directive: SymbioteStyleInputDirective, inputs: ['style'] },
|
|
25
|
+
],
|
|
24
26
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
25
|
-
imports: [
|
|
26
|
-
providers: [
|
|
27
|
+
imports: [ManagedSwitchHost, SymbioteHostPropsDirective],
|
|
28
|
+
providers: [
|
|
29
|
+
{
|
|
30
|
+
provide: NG_VALUE_ACCESSOR,
|
|
31
|
+
useExisting: forwardRef(() => Switch),
|
|
32
|
+
multi: true,
|
|
33
|
+
},
|
|
34
|
+
],
|
|
27
35
|
inputs: [
|
|
28
36
|
'value',
|
|
29
37
|
'disabled',
|
|
@@ -46,7 +54,7 @@ export type { ISwitchProps, ISwitchTrackColor } from './shared';
|
|
|
46
54
|
],
|
|
47
55
|
outputs: ['valueChange', 'change'],
|
|
48
56
|
template: `
|
|
49
|
-
<symbiote-switch
|
|
57
|
+
<symbiote-switch-managed
|
|
50
58
|
#nativeSwitch="symbioteHost"
|
|
51
59
|
[symbioteHostProps]="hostProps()"
|
|
52
60
|
(change)="handleChange($event, nativeSwitch)"
|
|
@@ -55,12 +63,15 @@ export type { ISwitchProps, ISwitchTrackColor } from './shared';
|
|
|
55
63
|
})
|
|
56
64
|
export class Switch extends SwitchBase implements DoCheck {
|
|
57
65
|
// This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
|
|
58
|
-
// onto (see anchorHostStyle's doc comment) — NOT the <symbiote-switch> leaf one level down.
|
|
66
|
+
// onto (see anchorHostStyle's doc comment) — NOT the <symbiote-switch-managed> leaf one level down.
|
|
59
67
|
private readonly elementRef = inject(ElementRef);
|
|
60
68
|
|
|
61
69
|
protected readonly platform = {
|
|
62
70
|
snapBackCommand: 'setValue',
|
|
63
|
-
trackColorProps: (
|
|
71
|
+
trackColorProps: (
|
|
72
|
+
_value: boolean,
|
|
73
|
+
trackColor?: { false?: string; true?: string },
|
|
74
|
+
) => ({
|
|
64
75
|
onTintColor: trackColor?.true,
|
|
65
76
|
tintColor: trackColor?.false,
|
|
66
77
|
}),
|
|
@@ -9,7 +9,10 @@ import {
|
|
|
9
9
|
type OnChanges,
|
|
10
10
|
} from '@angular/core';
|
|
11
11
|
import type { ControlValueAccessor } from '@angular/forms';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
renderSwitch,
|
|
14
|
+
resolveAccessibilityProps,
|
|
15
|
+
} from '@symbiote-native/components';
|
|
13
16
|
import type {
|
|
14
17
|
ISwitchPlatform,
|
|
15
18
|
ISwitchProps,
|
|
@@ -33,7 +36,10 @@ import {
|
|
|
33
36
|
type IViewStyle,
|
|
34
37
|
} from '@symbiote-native/engine';
|
|
35
38
|
|
|
36
|
-
export type {
|
|
39
|
+
export type {
|
|
40
|
+
ISwitchProps,
|
|
41
|
+
ISwitchTrackColor,
|
|
42
|
+
} from '@symbiote-native/components';
|
|
37
43
|
|
|
38
44
|
export type ISwitchInputs = Pick<
|
|
39
45
|
ISwitchProps,
|
|
@@ -88,7 +94,9 @@ function isSwitchEvent(event: unknown): event is ISymbioteEvent {
|
|
|
88
94
|
// concrete subclasses are real @Components — ngc's AOT build (NG2007) requires it the moment the
|
|
89
95
|
// base itself carries decorated members (@Output() here), mirroring ScrollViewBase.
|
|
90
96
|
@Directive()
|
|
91
|
-
export abstract class SwitchBase
|
|
97
|
+
export abstract class SwitchBase
|
|
98
|
+
implements ISwitchInputs, ControlValueAccessor, OnChanges
|
|
99
|
+
{
|
|
92
100
|
// The value/change lifecycle as real Angular events: `(valueChange)="onToggle($event)"`, not
|
|
93
101
|
// `[onValueChange]="onToggle"` — mirrors Pressable's press/hover @Output() conversion. Unlike
|
|
94
102
|
// Pressable's createPressHandlers, handleChange() below calls `.emit()` unconditionally: it needs
|
|
@@ -191,7 +199,10 @@ export abstract class SwitchBase implements ISwitchInputs, ControlValueAccessor,
|
|
|
191
199
|
if (next === undefined) return;
|
|
192
200
|
|
|
193
201
|
this.valueChange.emit(next);
|
|
194
|
-
this.switchState = switchReducer(this.switchState, {
|
|
202
|
+
this.switchState = switchReducer(this.switchState, {
|
|
203
|
+
type: 'native-reported',
|
|
204
|
+
value: next,
|
|
205
|
+
});
|
|
195
206
|
|
|
196
207
|
const hostNode = readSwitchNode(node);
|
|
197
208
|
if (hostNode === null) return;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// and the controlled-write predicate live in @symbiote-native/components/state, the render (intrinsic
|
|
3
3
|
// + native-prop mapping) in @symbiote-native/components/view, both shared verbatim with the React and
|
|
4
4
|
// Vue adapters. Here Angular supplies only the lifecycle: renderTextInput picks ONE of two host
|
|
5
|
-
// intrinsics at runtime (symbiote-text-input /
|
|
5
|
+
// intrinsics at runtime (symbiote-text-input-managed / …-multiline-managed) via `@if`/`@else`,
|
|
6
6
|
// each wired through the shared `SymbioteHostPropsDirective` (`[symbioteHostProps]="hostProps"`,
|
|
7
7
|
// `../primitives/shared.ts`) so the flat resolved prop bag doesn't need enumerating as individual
|
|
8
8
|
// `[prop]` bindings; a @ViewChild reading that directive (by its `#host` template ref, across
|
|
@@ -73,6 +73,9 @@ import {
|
|
|
73
73
|
setInputBlurred,
|
|
74
74
|
setInputFocused,
|
|
75
75
|
whenCommitted,
|
|
76
|
+
type IMeasureInWindowOnSuccess,
|
|
77
|
+
type IMeasureLayoutOnSuccess,
|
|
78
|
+
type IMeasureOnSuccess,
|
|
76
79
|
type IStyleProp,
|
|
77
80
|
type ISymbioteEvent,
|
|
78
81
|
type ISymbioteNode,
|
|
@@ -80,18 +83,30 @@ import {
|
|
|
80
83
|
} from '@symbiote-native/engine';
|
|
81
84
|
import {
|
|
82
85
|
anchorHostStyle,
|
|
83
|
-
|
|
86
|
+
ManagedMultilineTextInputHost,
|
|
84
87
|
SymbioteHostPropsDirective,
|
|
85
88
|
SymbioteStyleInputDirective,
|
|
86
|
-
|
|
89
|
+
ManagedTextInputHost,
|
|
87
90
|
} from '../primitives';
|
|
88
|
-
|
|
89
|
-
|
|
91
|
+
import {
|
|
92
|
+
gateWanted,
|
|
93
|
+
injectGateDemand,
|
|
94
|
+
type IGatedAccessibilityEvent,
|
|
95
|
+
} from '../gate-demand';
|
|
96
|
+
|
|
97
|
+
export type {
|
|
98
|
+
ITextInputHandle,
|
|
99
|
+
ITextInputSelection,
|
|
100
|
+
IInputMode,
|
|
101
|
+
IEnterKeyHint,
|
|
102
|
+
ISubmitBehavior,
|
|
103
|
+
};
|
|
90
104
|
|
|
91
105
|
// Mirrors React's ITextInputProps minus nothing (TextInput has no children) — declared
|
|
92
106
|
// per-adapter over the shared accessibility base because Angular's input surface aliases the
|
|
93
107
|
// aria-* keys to camelCase @Inputs, unlike the plain agnostic fields shared across adapters.
|
|
94
|
-
export interface IAngularTextInputProps
|
|
108
|
+
export interface IAngularTextInputProps
|
|
109
|
+
extends IAccessibilityProps, IAriaProps {
|
|
95
110
|
value?: string;
|
|
96
111
|
defaultValue?: string;
|
|
97
112
|
placeholder?: string;
|
|
@@ -158,16 +173,26 @@ export type IAngularTextInputInputs = Omit<
|
|
|
158
173
|
@Component({
|
|
159
174
|
selector: 'TextInput',
|
|
160
175
|
standalone: true,
|
|
161
|
-
hostDirectives: [
|
|
176
|
+
hostDirectives: [
|
|
177
|
+
{ directive: SymbioteStyleInputDirective, inputs: ['style'] },
|
|
178
|
+
],
|
|
162
179
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
163
|
-
imports: [
|
|
180
|
+
imports: [
|
|
181
|
+
SymbioteHostPropsDirective,
|
|
182
|
+
ManagedTextInputHost,
|
|
183
|
+
ManagedMultilineTextInputHost,
|
|
184
|
+
],
|
|
164
185
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
165
186
|
providers: [
|
|
166
|
-
{
|
|
187
|
+
{
|
|
188
|
+
provide: NG_VALUE_ACCESSOR,
|
|
189
|
+
useExisting: forwardRef(() => TextInput),
|
|
190
|
+
multi: true,
|
|
191
|
+
},
|
|
167
192
|
],
|
|
168
193
|
template: `
|
|
169
194
|
@if (isMultiline) {
|
|
170
|
-
<symbiote-text-input-multiline
|
|
195
|
+
<symbiote-text-input-multiline-managed
|
|
171
196
|
#host
|
|
172
197
|
[symbioteHostProps]="hostProps"
|
|
173
198
|
(change)="handleChange($event)"
|
|
@@ -178,13 +203,9 @@ export type IAngularTextInputInputs = Omit<
|
|
|
178
203
|
(keyPress)="emit(keyPress, $event)"
|
|
179
204
|
(endEditing)="emit(endEditing, $event)"
|
|
180
205
|
(contentSizeChange)="emit(contentSizeChange, $event)"
|
|
181
|
-
|
|
182
|
-
(accessibilityTap)="emit(accessibilityTap, $event)"
|
|
183
|
-
(magicTap)="emit(magicTap, $event)"
|
|
184
|
-
(accessibilityEscape)="emit(accessibilityEscape, $event)"
|
|
185
|
-
></symbiote-text-input-multiline>
|
|
206
|
+
></symbiote-text-input-multiline-managed>
|
|
186
207
|
} @else {
|
|
187
|
-
<symbiote-text-input
|
|
208
|
+
<symbiote-text-input-managed
|
|
188
209
|
#host
|
|
189
210
|
[symbioteHostProps]="hostProps"
|
|
190
211
|
(change)="handleChange($event)"
|
|
@@ -195,11 +216,7 @@ export type IAngularTextInputInputs = Omit<
|
|
|
195
216
|
(keyPress)="emit(keyPress, $event)"
|
|
196
217
|
(endEditing)="emit(endEditing, $event)"
|
|
197
218
|
(contentSizeChange)="emit(contentSizeChange, $event)"
|
|
198
|
-
|
|
199
|
-
(accessibilityTap)="emit(accessibilityTap, $event)"
|
|
200
|
-
(magicTap)="emit(magicTap, $event)"
|
|
201
|
-
(accessibilityEscape)="emit(accessibilityEscape, $event)"
|
|
202
|
-
></symbiote-text-input>
|
|
219
|
+
></symbiote-text-input-managed>
|
|
203
220
|
}
|
|
204
221
|
`,
|
|
205
222
|
})
|
|
@@ -269,6 +286,9 @@ export class TextInput
|
|
|
269
286
|
@Output() readonly magicTap = new EventEmitter<ISymbioteEvent>();
|
|
270
287
|
@Output() readonly accessibilityEscape = new EventEmitter<ISymbioteEvent>();
|
|
271
288
|
|
|
289
|
+
// Null unless a wrapper renders this TextInput in its own template. See `../gate-demand.ts`.
|
|
290
|
+
private readonly gateDemand = injectGateDemand();
|
|
291
|
+
|
|
272
292
|
@Input() accessible?: boolean;
|
|
273
293
|
@Input() accessibilityLabel?: string;
|
|
274
294
|
@Input() accessibilityHint?: string;
|
|
@@ -277,8 +297,10 @@ export class TextInput
|
|
|
277
297
|
@Input() accessibilityValue?: IAccessibilityProps['accessibilityValue'];
|
|
278
298
|
@Input() accessibilityActions?: IAccessibilityProps['accessibilityActions'];
|
|
279
299
|
@Input() accessibilityLabelledBy?: string | string[];
|
|
280
|
-
@Input()
|
|
281
|
-
|
|
300
|
+
@Input()
|
|
301
|
+
importantForAccessibility?: IAccessibilityProps['importantForAccessibility'];
|
|
302
|
+
@Input()
|
|
303
|
+
accessibilityLiveRegion?: IAccessibilityProps['accessibilityLiveRegion'];
|
|
282
304
|
@Input() screenReaderFocusable?: boolean;
|
|
283
305
|
@Input() accessibilityViewIsModal?: boolean;
|
|
284
306
|
@Input() accessibilityElementsHidden?: boolean;
|
|
@@ -303,7 +325,7 @@ export class TextInput
|
|
|
303
325
|
|
|
304
326
|
// This component's OWN host — the non-painting anchor `class="..."` at the use site resolves
|
|
305
327
|
// onto (see anchorHostStyle's doc comment) — NOT `hostRef` above, which targets the real inner
|
|
306
|
-
// symbiote-text-input(-multiline) one level down.
|
|
328
|
+
// symbiote-text-input-managed(-multiline-managed) one level down.
|
|
307
329
|
private readonly elementRef = inject(ElementRef);
|
|
308
330
|
// Only setDisabledState() needs this: it mutates `editable` from OUTSIDE Angular's own binding
|
|
309
331
|
// path (@angular/forms calling in directly), which doesn't itself schedule a tick under zoneless CD.
|
|
@@ -390,7 +412,9 @@ export class TextInput
|
|
|
390
412
|
const node = this.hostNode;
|
|
391
413
|
if (node === undefined) return;
|
|
392
414
|
dlog('TextInput autoFocus -> focus command');
|
|
393
|
-
this.cancelAutoFocus = whenCommitted(node, () =>
|
|
415
|
+
this.cancelAutoFocus = whenCommitted(node, () =>
|
|
416
|
+
dispatchViewCommand(node, 'focus', []),
|
|
417
|
+
);
|
|
394
418
|
}
|
|
395
419
|
|
|
396
420
|
ngOnDestroy(): void {
|
|
@@ -441,6 +465,41 @@ export class TextInput
|
|
|
441
465
|
if (isSymbioteEvent(event)) emitter.emit(event);
|
|
442
466
|
}
|
|
443
467
|
|
|
468
|
+
// `undefined` means `setEventListener` never sees a function, so the gate stays dark. A demand
|
|
469
|
+
// from above overrides `.observed` for the same reason it does on Pressable: a wrapper's binding
|
|
470
|
+
// is not a subscriber (`../gate-demand.ts`).
|
|
471
|
+
private gatedAccessibilityHandler(
|
|
472
|
+
name: IGatedAccessibilityEvent,
|
|
473
|
+
): ((event: unknown) => void) | undefined {
|
|
474
|
+
const emitter = this[name];
|
|
475
|
+
return gateWanted(this.gateDemand, name, emitter)
|
|
476
|
+
? event => this.emit(emitter, event)
|
|
477
|
+
: undefined;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Forwarded from the engine node so a TextInput ref is not poorer than any other host ref — an
|
|
481
|
+
// instance exposing only the five methods below CLOSES the node off (see ITextInputHandle's own
|
|
482
|
+
// comment). No Angular-specific state to add: these four pass straight through.
|
|
483
|
+
measure(callback: IMeasureOnSuccess): void {
|
|
484
|
+
this.hostNode?.measure(callback);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
measureInWindow(callback: IMeasureInWindowOnSuccess): void {
|
|
488
|
+
this.hostNode?.measureInWindow(callback);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
measureLayout(
|
|
492
|
+
relativeToNativeNode: ISymbioteNode | number,
|
|
493
|
+
onSuccess: IMeasureLayoutOnSuccess,
|
|
494
|
+
onFail?: () => void,
|
|
495
|
+
): void {
|
|
496
|
+
this.hostNode?.measureLayout(relativeToNativeNode, onSuccess, onFail);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
setNativeProps(nativeProps: Record<string, unknown>): void {
|
|
500
|
+
this.hostNode?.setNativeProps(nativeProps);
|
|
501
|
+
}
|
|
502
|
+
|
|
444
503
|
// The imperative API RN exposes on a TextInput ref; in Angular the component instance IS the
|
|
445
504
|
// handle (a parent reads it via @ViewChild(TextInput) and calls these). focus/blur drive native
|
|
446
505
|
// view commands; clear and setSelection reuse setTextAndSelection (the same stale-safe path as a
|
|
@@ -458,7 +517,12 @@ export class TextInput
|
|
|
458
517
|
clear(): void {
|
|
459
518
|
const node = this.hostNode;
|
|
460
519
|
if (node === undefined) return;
|
|
461
|
-
dispatchViewCommand(node, 'setTextAndSelection', [
|
|
520
|
+
dispatchViewCommand(node, 'setTextAndSelection', [
|
|
521
|
+
this.mostRecentEventCount,
|
|
522
|
+
'',
|
|
523
|
+
0,
|
|
524
|
+
0,
|
|
525
|
+
]);
|
|
462
526
|
this.lastNativeText = '';
|
|
463
527
|
}
|
|
464
528
|
|
|
@@ -488,12 +552,20 @@ export class TextInput
|
|
|
488
552
|
const value = this.value;
|
|
489
553
|
if (!shouldCommandText(this.lastNativeText, value)) return;
|
|
490
554
|
const selStart = this.selection?.start ?? SELECTION_NONE;
|
|
491
|
-
const selEnd =
|
|
555
|
+
const selEnd =
|
|
556
|
+
this.selection?.end ?? this.selection?.start ?? SELECTION_NONE;
|
|
492
557
|
const count = this.mostRecentEventCount;
|
|
493
|
-
dlog(
|
|
558
|
+
dlog(
|
|
559
|
+
`TextInput setTextAndSelection count=${count} text=${JSON.stringify(value)}`,
|
|
560
|
+
);
|
|
494
561
|
this.lastNativeText = value;
|
|
495
562
|
whenCommitted(node, () =>
|
|
496
|
-
dispatchViewCommand(node, 'setTextAndSelection', [
|
|
563
|
+
dispatchViewCommand(node, 'setTextAndSelection', [
|
|
564
|
+
count,
|
|
565
|
+
value,
|
|
566
|
+
selStart,
|
|
567
|
+
selEnd,
|
|
568
|
+
]),
|
|
497
569
|
);
|
|
498
570
|
}
|
|
499
571
|
|
|
@@ -501,6 +573,20 @@ export class TextInput
|
|
|
501
573
|
return {
|
|
502
574
|
...this.foldedAccessibility,
|
|
503
575
|
accessible: this.accessible,
|
|
576
|
+
// NOT template bindings, unlike every other event on this component's two host tags. These
|
|
577
|
+
// four are `on*`-GATED Fabric events (`.claude/rules/fabric-boolean-event-gates.md`): native
|
|
578
|
+
// fires them only when the committed payload carries a FUNCTION at that key, and a template
|
|
579
|
+
// `(accessibilityAction)="..."` binding is present unconditionally — so it lit all four gates
|
|
580
|
+
// on every TextInput in every app whether or not anything listened. Routed through the flat
|
|
581
|
+
// bag instead, the same shape Pressable uses.
|
|
582
|
+
onAccessibilityAction: this.gatedAccessibilityHandler(
|
|
583
|
+
'accessibilityAction',
|
|
584
|
+
),
|
|
585
|
+
onAccessibilityTap: this.gatedAccessibilityHandler('accessibilityTap'),
|
|
586
|
+
onMagicTap: this.gatedAccessibilityHandler('magicTap'),
|
|
587
|
+
onAccessibilityEscape: this.gatedAccessibilityHandler(
|
|
588
|
+
'accessibilityEscape',
|
|
589
|
+
),
|
|
504
590
|
testID: this.testID,
|
|
505
591
|
nativeID: this.nativeID,
|
|
506
592
|
placeholder: this.placeholder,
|
|
@@ -558,8 +644,10 @@ export class TextInput
|
|
|
558
644
|
accessibilityElementsHidden: this.accessibilityElementsHidden,
|
|
559
645
|
accessibilityIgnoresInvertColors: this.accessibilityIgnoresInvertColors,
|
|
560
646
|
accessibilityLanguage: this.accessibilityLanguage,
|
|
561
|
-
accessibilityRespondsToUserInteraction:
|
|
562
|
-
|
|
647
|
+
accessibilityRespondsToUserInteraction:
|
|
648
|
+
this.accessibilityRespondsToUserInteraction,
|
|
649
|
+
accessibilityShowsLargeContentViewer:
|
|
650
|
+
this.accessibilityShowsLargeContentViewer,
|
|
563
651
|
accessibilityLargeContentTitle: this.accessibilityLargeContentTitle,
|
|
564
652
|
role: this.role,
|
|
565
653
|
'aria-label': this.ariaLabel,
|