@symbiote-native/angular 3.2.0 → 3.3.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/babel-register-composed.cjs +1 -0
- package/build/angular/components/checkbox-props.d.ts +2 -0
- package/build/angular/components/checkbox-props.js +2 -0
- package/build/angular/components/checkbox-props.js.map +1 -0
- package/build/angular/components.d.ts +1 -0
- package/build/angular/components.js.map +1 -1
- package/build/angular/descriptor-to-angular/descriptor-host.d.ts +8 -0
- package/build/angular/descriptor-to-angular/descriptor-host.js +38 -0
- package/build/angular/descriptor-to-angular/descriptor-host.js.map +1 -0
- package/build/angular/descriptor-to-angular/index.d.ts +1 -0
- package/build/angular/descriptor-to-angular/index.js +4 -0
- package/build/angular/descriptor-to-angular/index.js.map +1 -1
- package/build/angular/element-base.d.ts +153 -0
- package/build/angular/element-base.js +272 -0
- package/build/angular/element-base.js.map +1 -0
- package/build/angular/elements-controls.d.ts +165 -0
- package/build/angular/elements-controls.js +382 -0
- package/build/angular/elements-controls.js.map +1 -0
- package/build/angular/elements-layout.d.ts +122 -0
- package/build/angular/elements-layout.js +242 -0
- package/build/angular/elements-layout.js.map +1 -0
- package/build/angular/elements-press.d.ts +96 -0
- package/build/angular/elements-press.js +227 -0
- package/build/angular/elements-press.js.map +1 -0
- package/build/angular/elements.d.ts +6 -516
- package/build/angular/elements.js +8 -1091
- package/build/angular/elements.js.map +1 -1
- package/build/angular/host-instance/index.d.ts +2 -0
- package/build/angular/host-instance/index.js +4 -4
- package/build/angular/host-instance/index.js.map +1 -1
- package/build/angular/index.d.ts +5 -4
- package/build/angular/index.js +4 -3
- package/build/angular/index.js.map +1 -1
- package/build/angular/native-view-base.d.ts +10 -2
- package/build/angular/native-view-base.js +23 -2
- package/build/angular/native-view-base.js.map +1 -1
- package/build/angular/services/index.d.ts +1 -0
- package/build/angular/services/index.js +1 -0
- package/build/angular/services/index.js.map +1 -1
- package/build/angular/services/inject-event.d.ts +6 -0
- package/build/angular/services/inject-event.js +24 -0
- package/build/angular/services/inject-event.js.map +1 -0
- package/package.json +6 -6
- package/src/components/checkbox-props.ts +12 -0
- package/src/components.ts +1 -0
- package/src/descriptor-to-angular/descriptor-host.ts +27 -0
- package/src/descriptor-to-angular/index.ts +5 -0
- package/src/element-base.ts +272 -0
- package/src/elements-controls.ts +282 -0
- package/src/elements-layout.ts +141 -0
- package/src/elements-press.ts +145 -0
- package/src/elements.ts +73 -788
- package/src/host-instance/index.ts +4 -4
- package/src/index.ts +6 -1
- package/src/native-view-base.ts +37 -2
- package/src/services/index.ts +1 -0
- package/src/services/inject-event.ts +52 -0
|
@@ -21,14 +21,14 @@ import {
|
|
|
21
21
|
|
|
22
22
|
export type { IHostInstance } from '@symbiote-native/engine';
|
|
23
23
|
|
|
24
|
-
function
|
|
24
|
+
export function hostNodeOf(candidate: unknown): ISymbioteNode | null {
|
|
25
25
|
if (candidate === null || candidate === undefined) return null;
|
|
26
26
|
if (isSymbioteNode(candidate)) return candidate;
|
|
27
27
|
if (candidate instanceof ElementRef)
|
|
28
|
-
return
|
|
28
|
+
return hostNodeOf(candidate.nativeElement);
|
|
29
29
|
const maybeHost = candidate as { nativeElement?: unknown };
|
|
30
30
|
if (typeof maybeHost.nativeElement !== 'undefined') {
|
|
31
|
-
return
|
|
31
|
+
return hostNodeOf(maybeHost.nativeElement);
|
|
32
32
|
}
|
|
33
33
|
return null;
|
|
34
34
|
}
|
|
@@ -37,6 +37,6 @@ export function findNodeHandle(componentOrHandle: unknown): number | null {
|
|
|
37
37
|
if (componentOrHandle === null || componentOrHandle === undefined)
|
|
38
38
|
return null;
|
|
39
39
|
if (typeof componentOrHandle === 'number') return componentOrHandle;
|
|
40
|
-
const node =
|
|
40
|
+
const node = hostNodeOf(componentOrHandle);
|
|
41
41
|
return node ? (getNativeTag(node) ?? null) : null;
|
|
42
42
|
}
|
package/src/index.ts
CHANGED
|
@@ -89,6 +89,7 @@ export type {
|
|
|
89
89
|
IAngularTouchableOpacityProps,
|
|
90
90
|
IAngularTouchableWithoutFeedbackProps,
|
|
91
91
|
IButtonProps,
|
|
92
|
+
ICheckboxProps,
|
|
92
93
|
ICellLayout,
|
|
93
94
|
IFlatListHandle,
|
|
94
95
|
IFlatListProps,
|
|
@@ -144,6 +145,7 @@ export {
|
|
|
144
145
|
ActivityIndicatorElement,
|
|
145
146
|
ActivityIndicatorSpinnerElement,
|
|
146
147
|
ButtonElement,
|
|
148
|
+
CheckboxElement,
|
|
147
149
|
HorizontalScrollContentElement,
|
|
148
150
|
HorizontalScrollViewElement,
|
|
149
151
|
ImageBackgroundElement,
|
|
@@ -187,6 +189,7 @@ export { mount, unmount } from './render';
|
|
|
187
189
|
// @symbiote-native/slider) can render a shared @symbiote-native/components/@symbiote-native/slider Descriptor tree
|
|
188
190
|
// without hand-writing its own Renderer2 walker.
|
|
189
191
|
export { DescriptorOutlet } from './descriptor-to-angular';
|
|
192
|
+
export { DescriptorHost } from './descriptor-to-angular/descriptor-host';
|
|
190
193
|
// createPortal (same-surface only — see the file header) and createTunnel (cross-surface,
|
|
191
194
|
// see its file header) are the Angular twins of the React/Vue portal/tunnel primitives.
|
|
192
195
|
// Angular can't synthesize components at runtime (no JIT under Metro/Hermes), so both are
|
|
@@ -206,7 +209,7 @@ export { SymbioteRenderer, SymbioteRendererFactory } from './renderer';
|
|
|
206
209
|
// import straight from that subpath so app-screen registration never routes through this cyclic
|
|
207
210
|
// barrel.
|
|
208
211
|
export { registerComposedComponent } from './anchor-host-registry';
|
|
209
|
-
export { findNodeHandle } from './host-instance';
|
|
212
|
+
export { findNodeHandle, hostNodeOf } from './host-instance';
|
|
210
213
|
export type { IHostInstance } from './host-instance';
|
|
211
214
|
export { StatusBar } from './modules/status-bar';
|
|
212
215
|
export type { IStatusBarProps, IStatusBarStyle } from './modules/status-bar';
|
|
@@ -230,6 +233,8 @@ export {
|
|
|
230
233
|
WindowDimensionsService,
|
|
231
234
|
createResourceHook,
|
|
232
235
|
createEventValueHook,
|
|
236
|
+
injectEvent,
|
|
237
|
+
injectEventListener,
|
|
233
238
|
connectWatchedSignal,
|
|
234
239
|
PermissionsServiceBase,
|
|
235
240
|
} from './services';
|
package/src/native-view-base.ts
CHANGED
|
@@ -1,18 +1,32 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
ChangeDetectorRef,
|
|
3
|
+
Directive,
|
|
4
|
+
ElementRef,
|
|
5
|
+
inject,
|
|
6
|
+
Input,
|
|
7
|
+
ViewChild,
|
|
8
|
+
} from '@angular/core';
|
|
9
|
+
import type { OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
|
|
2
10
|
import { resolveAccessibilityProps } from '@symbiote-native/components';
|
|
3
11
|
import type { IDescriptor } from '@symbiote-native/components';
|
|
4
12
|
import type {
|
|
5
13
|
IStyleProp,
|
|
6
14
|
ISymbioteEvent,
|
|
15
|
+
ISymbioteNode,
|
|
7
16
|
IViewStyle,
|
|
8
17
|
} from '@symbiote-native/engine';
|
|
9
18
|
import { AccessibilityInputsBase } from './accessibility-inputs';
|
|
19
|
+
import { DescriptorOutlet } from './descriptor-to-angular';
|
|
20
|
+
import { hostNodeOf } from './host-instance';
|
|
10
21
|
import { anchorStyleProp } from './primitives/shared';
|
|
11
22
|
|
|
12
23
|
// Shared shell of a component that paints one Expo native view: the common inputs, the anchor
|
|
13
24
|
// host `class="..."` resolves onto, and a descriptor that recomputes on every OnPush check
|
|
14
25
|
@Directive()
|
|
15
|
-
export abstract class NativeViewBase
|
|
26
|
+
export abstract class NativeViewBase
|
|
27
|
+
extends AccessibilityInputsBase
|
|
28
|
+
implements OnChanges, OnDestroy
|
|
29
|
+
{
|
|
16
30
|
@Input() style?: IStyleProp<IViewStyle>;
|
|
17
31
|
@Input() testID?: string;
|
|
18
32
|
@Input() nativeID?: string;
|
|
@@ -23,6 +37,27 @@ export abstract class NativeViewBase extends AccessibilityInputsBase {
|
|
|
23
37
|
|
|
24
38
|
// This component's own `ElementRef`, the anchor a `class="..."` at the use site lands on
|
|
25
39
|
private readonly elementRef = inject(ElementRef);
|
|
40
|
+
protected readonly changeDetector = inject(ChangeDetectorRef);
|
|
41
|
+
|
|
42
|
+
@ViewChild(DescriptorOutlet) private readonly nativeOutlet?: DescriptorOutlet;
|
|
43
|
+
|
|
44
|
+
// The committed host node of the native view, for a component that calls its view functions
|
|
45
|
+
protected hostNode(): ISymbioteNode | null {
|
|
46
|
+
return hostNodeOf(this.nativeOutlet?.rootNode);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Hook for a component that holds more than its native node, runs once when it is destroyed
|
|
50
|
+
protected disposeView(): void {}
|
|
51
|
+
|
|
52
|
+
// A `[style]` binding reaches the `style` input without dirtying an OnPush view, a plain
|
|
53
|
+
// `[prop]` does. A subclass with its own `ngOnChanges` calls this one first
|
|
54
|
+
ngOnChanges(changes: SimpleChanges): void {
|
|
55
|
+
if ('style' in changes) this.changeDetector.markForCheck();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
ngOnDestroy(): void {
|
|
59
|
+
this.disposeView();
|
|
60
|
+
}
|
|
26
61
|
|
|
27
62
|
// Names of the component's own inputs that go to the native view, read off `this`
|
|
28
63
|
protected abstract readonly propNames: readonly string[];
|
package/src/services/index.ts
CHANGED
|
@@ -2,5 +2,6 @@ export { ColorSchemeService } from './color-scheme.service';
|
|
|
2
2
|
export { WindowDimensionsService } from './window-dimensions.service';
|
|
3
3
|
export { createResourceHook } from './create-resource-hook';
|
|
4
4
|
export { createEventValueHook } from './create-event-value-hook';
|
|
5
|
+
export { injectEvent, injectEventListener } from './inject-event';
|
|
5
6
|
export { connectWatchedSignal } from './connect-watched-signal';
|
|
6
7
|
export { PermissionsServiceBase } from './permissions-service-base';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Angular twins of `useEvent` and `useEventListener` of the `expo` package, for any emitter
|
|
2
|
+
|
|
3
|
+
import { effect, signal, untracked } from '@angular/core';
|
|
4
|
+
import type { Signal } from '@angular/core';
|
|
5
|
+
import { bindEventListener } from '@symbiote-native/engine';
|
|
6
|
+
import type {
|
|
7
|
+
IEventEmitterOf,
|
|
8
|
+
IEventName,
|
|
9
|
+
IEventPayload,
|
|
10
|
+
IEventsMap,
|
|
11
|
+
} from '@symbiote-native/engine';
|
|
12
|
+
|
|
13
|
+
/** Calls the listener for each event, the latest one, and stops with the injection context */
|
|
14
|
+
export function injectEventListener<
|
|
15
|
+
TEventsMap extends IEventsMap,
|
|
16
|
+
TName extends IEventName<TEventsMap>,
|
|
17
|
+
>(
|
|
18
|
+
emitter: () => IEventEmitterOf<TEventsMap>,
|
|
19
|
+
eventName: () => TName,
|
|
20
|
+
listener: () => TEventsMap[TName],
|
|
21
|
+
): void {
|
|
22
|
+
effect(onCleanup => {
|
|
23
|
+
const source = emitter();
|
|
24
|
+
const name = eventName();
|
|
25
|
+
// The listener is read at each event, a new one is not a new subscription
|
|
26
|
+
onCleanup(bindEventListener(source, name, () => untracked(listener)));
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** The payload of the last event, `initialValue` (or `null`) until the first one */
|
|
31
|
+
export function injectEvent<
|
|
32
|
+
TEventsMap extends IEventsMap,
|
|
33
|
+
TName extends IEventName<TEventsMap>,
|
|
34
|
+
>(
|
|
35
|
+
emitter: () => IEventEmitterOf<TEventsMap>,
|
|
36
|
+
eventName: () => TName,
|
|
37
|
+
initialValue: IEventPayload<TEventsMap, TName> | null = null,
|
|
38
|
+
): Signal<IEventPayload<TEventsMap, TName> | null> {
|
|
39
|
+
const event = signal<IEventPayload<TEventsMap, TName> | null>(initialValue);
|
|
40
|
+
effect(onCleanup => {
|
|
41
|
+
const source = emitter();
|
|
42
|
+
const name = eventName();
|
|
43
|
+
onCleanup(
|
|
44
|
+
bindEventListener(
|
|
45
|
+
source,
|
|
46
|
+
name,
|
|
47
|
+
() => (next: IEventPayload<TEventsMap, TName>) => event.set(next),
|
|
48
|
+
),
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
return event.asReadonly();
|
|
52
|
+
}
|