@ng-native/components 0.2.0 → 0.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.
Files changed (48) hide show
  1. package/dist/content-container.d.ts +25 -0
  2. package/dist/content-container.js +35 -0
  3. package/dist/content-container.js.map +1 -0
  4. package/dist/gestures-web.d.ts +12 -0
  5. package/dist/gestures-web.js +32 -0
  6. package/dist/gestures-web.js.map +1 -0
  7. package/dist/index.d.ts +1 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/keyboard-avoiding-view.d.ts +6 -1
  10. package/dist/keyboard-avoiding-view.js +23 -6
  11. package/dist/keyboard-avoiding-view.js.map +1 -1
  12. package/dist/pressable.d.ts +33 -4
  13. package/dist/pressable.js +55 -3
  14. package/dist/pressable.js.map +1 -1
  15. package/dist/reanimated-web.d.ts +26 -0
  16. package/dist/reanimated-web.js +59 -0
  17. package/dist/reanimated-web.js.map +1 -0
  18. package/dist/refresh-control.d.ts +4 -1
  19. package/dist/refresh-control.js +4 -1
  20. package/dist/refresh-control.js.map +1 -1
  21. package/dist/scroll-view.d.ts +17 -1
  22. package/dist/scroll-view.js +59 -6
  23. package/dist/scroll-view.js.map +1 -1
  24. package/dist/section-list.d.ts +14 -2
  25. package/dist/section-list.js +20 -4
  26. package/dist/section-list.js.map +1 -1
  27. package/dist/sticky-headers.d.ts +6 -0
  28. package/dist/sticky-headers.js +7 -2
  29. package/dist/sticky-headers.js.map +1 -1
  30. package/dist/switch.d.ts +11 -1
  31. package/dist/switch.js +16 -3
  32. package/dist/switch.js.map +1 -1
  33. package/dist/text.d.ts +10 -1
  34. package/dist/text.js +15 -1
  35. package/dist/text.js.map +1 -1
  36. package/dist/touchable-opacity.d.ts +2 -1
  37. package/dist/touchable-opacity.js +3 -0
  38. package/dist/touchable-opacity.js.map +1 -1
  39. package/dist/view-base.d.ts +28 -18
  40. package/dist/view-base.js +37 -22
  41. package/dist/view-base.js.map +1 -1
  42. package/dist/virtual-list.d.ts +49 -5
  43. package/dist/virtual-list.js +129 -42
  44. package/dist/virtual-list.js.map +1 -1
  45. package/dist/zero-size-warning.d.ts +30 -0
  46. package/dist/zero-size-warning.js +58 -0
  47. package/dist/zero-size-warning.js.map +1 -0
  48. package/package.json +7 -4
@@ -0,0 +1,25 @@
1
+ import { type OnChanges } from '@angular/core';
2
+ import { type HostNode } from '@ng-native/fabric';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * The view a component makes to hold its children, styled by the app through
6
+ * `contentContainerClass`: `<scroll-view>`'s content view, and the view `<keyboard-avoiding-view>`
7
+ * moves.
8
+ *
9
+ * The view is written in the component's template, so on its own it matches only that
10
+ * component's rules and the global sheet. The class is the app's, so while there is one the view
11
+ * is matched against the rules of the template the component is written in, and against its own
12
+ * again once the class is gone. Not before: a type selector in the app's styles would otherwise
13
+ * reach a view that nobody there wrote.
14
+ */
15
+ export declare class ContentContainer implements OnChanges {
16
+ /** The component the view belongs to, whose template the app wrote it in. */
17
+ readonly owner: import("@angular/core").InputSignal<HostNode>;
18
+ /** The app's classes for the view. */
19
+ readonly classes: import("@angular/core").InputSignal<string | undefined>;
20
+ private readonly node;
21
+ private readonly engine;
22
+ ngOnChanges(): void;
23
+ static ɵfac: i0.ɵɵFactoryDeclaration<ContentContainer, never>;
24
+ static ɵdir: i0.ɵɵDirectiveDeclaration<ContentContainer, "[contentContainerOf]", never, { "owner": { "alias": "contentContainerOf"; "required": true; "isSignal": true; }; "classes": { "alias": "contentContainerClass"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
25
+ }
@@ -0,0 +1,35 @@
1
+ import { Directive, ElementRef, inject, input } from '@angular/core';
2
+ import { HostEngine } from '@ng-native/fabric';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * The view a component makes to hold its children, styled by the app through
6
+ * `contentContainerClass`: `<scroll-view>`'s content view, and the view `<keyboard-avoiding-view>`
7
+ * moves.
8
+ *
9
+ * The view is written in the component's template, so on its own it matches only that
10
+ * component's rules and the global sheet. The class is the app's, so while there is one the view
11
+ * is matched against the rules of the template the component is written in, and against its own
12
+ * again once the class is gone. Not before: a type selector in the app's styles would otherwise
13
+ * reach a view that nobody there wrote.
14
+ */
15
+ export class ContentContainer {
16
+ /** The component the view belongs to, whose template the app wrote it in. */
17
+ owner = input.required({ ...(ngDevMode ? { debugName: "owner" } : /* istanbul ignore next */ {}), alias: 'contentContainerOf' });
18
+ /** The app's classes for the view. */
19
+ classes = input(undefined, { ...(ngDevMode ? { debugName: "classes" } : /* istanbul ignore next */ {}), alias: 'contentContainerClass' });
20
+ node = inject(ElementRef).nativeElement;
21
+ engine = this.node.host ?? inject(HostEngine);
22
+ ngOnChanges() {
23
+ this.engine.adoptScope(this.node, this.classes() ? this.owner() : null);
24
+ }
25
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: ContentContainer, deps: [], target: i0.ɵɵFactoryTarget.Directive });
26
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.2.0", type: ContentContainer, isStandalone: true, selector: "[contentContainerOf]", inputs: { owner: { classPropertyName: "owner", publicName: "contentContainerOf", isSignal: true, isRequired: true, transformFunction: null }, classes: { classPropertyName: "classes", publicName: "contentContainerClass", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, usesOnChanges: true, ngImport: i0 });
27
+ }
28
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: ContentContainer, decorators: [{
29
+ type: Directive,
30
+ args: [{
31
+ selector: '[contentContainerOf]',
32
+ host: { '[class]': 'classes()' },
33
+ }]
34
+ }], propDecorators: { owner: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentContainerOf", required: true }] }], classes: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentContainerClass", required: false }] }] } });
35
+ //# sourceMappingURL=content-container.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-container.js","sourceRoot":"","sources":["../src/content-container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAkB,MAAM,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EAAE,UAAU,EAAiB,MAAM,mBAAmB,CAAC;;AAE9D;;;;;;;;;;GAUG;AAKH,MAAM,OAAO,gBAAgB;IAC3B,6EAA6E;IACpE,KAAK,GAAG,KAAK,CAAC,QAAQ,4EAAa,KAAK,EAAE,oBAAoB,GAAG,CAAC;IAC3E,sCAAsC;IAC7B,OAAO,GAAG,KAAK,CAAS,SAAS,+EAAI,KAAK,EAAE,uBAAuB,GAAG,CAAC;IAE/D,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,aAAyB,CAAC;IACpD,MAAM,GAAe,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC;IAE3E,WAAW;QACT,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC1E,CAAC;uGAXU,gBAAgB;2FAAhB,gBAAgB;;2FAAhB,gBAAgB;kBAJ5B,SAAS;mBAAC;oBACT,QAAQ,EAAE,sBAAsB;oBAChC,IAAI,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE;iBACjC","sourcesContent":["import { Directive, ElementRef, type OnChanges, inject, input } from '@angular/core';\nimport { HostEngine, type HostNode } from '@ng-native/fabric';\n\n/**\n * The view a component makes to hold its children, styled by the app through\n * `contentContainerClass`: `<scroll-view>`'s content view, and the view `<keyboard-avoiding-view>`\n * moves.\n *\n * The view is written in the component's template, so on its own it matches only that\n * component's rules and the global sheet. The class is the app's, so while there is one the view\n * is matched against the rules of the template the component is written in, and against its own\n * again once the class is gone. Not before: a type selector in the app's styles would otherwise\n * reach a view that nobody there wrote.\n */\n@Directive({\n selector: '[contentContainerOf]',\n host: { '[class]': 'classes()' },\n})\nexport class ContentContainer implements OnChanges {\n /** The component the view belongs to, whose template the app wrote it in. */\n readonly owner = input.required<HostNode>({ alias: 'contentContainerOf' });\n /** The app's classes for the view. */\n readonly classes = input<string>(undefined, { alias: 'contentContainerClass' });\n\n private readonly node = inject(ElementRef).nativeElement as HostNode;\n private readonly engine: HostEngine = this.node.host ?? inject(HostEngine);\n\n ngOnChanges(): void {\n this.engine.adoptScope(this.node, this.classes() ? this.owner() : null);\n }\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import * as i0 from "@angular/core";
2
+ export { type GestureSpec, type GestureTarget } from './gesture-backend.ts';
3
+ export declare class NativeGesture {
4
+ readonly gesture: import("@angular/core").InputSignal<object>;
5
+ static ɵfac: i0.ɵɵFactoryDeclaration<NativeGesture, never>;
6
+ static ɵdir: i0.ɵɵDirectiveDeclaration<NativeGesture, "[gesture]", never, { "gesture": { "alias": "gesture"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
7
+ }
8
+ /** A box that fills its parent, as the native root does. `@ng-native/web`'s reset gives it `flex: 1`. */
9
+ export declare class GestureRoot {
10
+ static ɵfac: i0.ɵɵFactoryDeclaration<GestureRoot, never>;
11
+ static ɵcmp: i0.ɵɵComponentDeclaration<GestureRoot, "gesture-root", never, {}, {}, never, ["*"], true, never>;
12
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * `gestures.ts`, for a browser build.
3
+ *
4
+ * A web bundler resolves `@ng-native/components/gestures` here, through the `browser` condition in
5
+ * this package's `exports`; Metro, on a device, never sets that condition and gets the native file.
6
+ * A browser has no native gesture recognisers, so everything here is inert: the names are the
7
+ * same, a template that uses `<gesture-root>` and `[gesture]` still renders, and `[gesture]`
8
+ * attaches nothing.
9
+ */
10
+ import { Component, Directive, input } from '@angular/core';
11
+ import * as i0 from "@angular/core";
12
+ export {} from "./gesture-backend.js";
13
+ export class NativeGesture {
14
+ gesture = input.required(/* @ts-ignore */
15
+ ...(ngDevMode ? [{ debugName: "gesture" }] : /* istanbul ignore next */ []));
16
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: NativeGesture, deps: [], target: i0.ɵɵFactoryTarget.Directive });
17
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.2.0", type: NativeGesture, isStandalone: true, selector: "[gesture]", inputs: { gesture: { classPropertyName: "gesture", publicName: "gesture", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
18
+ }
19
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: NativeGesture, decorators: [{
20
+ type: Directive,
21
+ args: [{ selector: '[gesture]' }]
22
+ }], propDecorators: { gesture: [{ type: i0.Input, args: [{ isSignal: true, alias: "gesture", required: true }] }] } });
23
+ /** A box that fills its parent, as the native root does. `@ng-native/web`'s reset gives it `flex: 1`. */
24
+ export class GestureRoot {
25
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: GestureRoot, deps: [], target: i0.ɵɵFactoryTarget.Component });
26
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.2.0", type: GestureRoot, isStandalone: true, selector: "gesture-root", ngImport: i0, template: '<ng-content />', isInline: true });
27
+ }
28
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: GestureRoot, decorators: [{
29
+ type: Component,
30
+ args: [{ selector: 'gesture-root', template: '<ng-content />' }]
31
+ }] });
32
+ //# sourceMappingURL=gestures-web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gestures-web.js","sourceRoot":"","sources":["../src/gestures-web.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;;AAG5D,OAAO,EAAwC,MAAM,sBAAsB,CAAC;AAG5E,MAAM,OAAO,aAAa;IACf,OAAO,GAAG,KAAK,CAAC,QAAQ;gFAAe,CAAC;uGADtC,aAAa;2FAAb,aAAa;;2FAAb,aAAa;kBADzB,SAAS;mBAAC,EAAE,QAAQ,EAAE,WAAW,EAAE;;AAKpC,yGAAyG;AAEzG,MAAM,OAAO,WAAW;uGAAX,WAAW;2FAAX,WAAW,wEADyB,gBAAgB;;2FACpD,WAAW;kBADvB,SAAS;mBAAC,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,gBAAgB,EAAE","sourcesContent":["/**\n * `gestures.ts`, for a browser build.\n *\n * A web bundler resolves `@ng-native/components/gestures` here, through the `browser` condition in\n * this package's `exports`; Metro, on a device, never sets that condition and gets the native file.\n * A browser has no native gesture recognisers, so everything here is inert: the names are the\n * same, a template that uses `<gesture-root>` and `[gesture]` still renders, and `[gesture]`\n * attaches nothing.\n */\nimport { Component, Directive, input } from '@angular/core';\nimport type { GestureSpec } from './gesture-backend.ts';\n\nexport { type GestureSpec, type GestureTarget } from './gesture-backend.ts';\n\n@Directive({ selector: '[gesture]' })\nexport class NativeGesture {\n readonly gesture = input.required<GestureSpec>();\n}\n\n/** A box that fills its parent, as the native root does. `@ng-native/web`'s reset gives it `flex: 1`. */\n@Component({ selector: 'gesture-root', template: '<ng-content />' })\nexport class GestureRoot {}\n"]}
package/dist/index.d.ts CHANGED
@@ -33,6 +33,6 @@ export { TouchableOpacity } from './touchable-opacity.ts';
33
33
  export { optionalBoolean, optionalNumber } from './transforms.ts';
34
34
  export { View } from './view.ts';
35
35
  export { ViewBase, ViewBehavior, contributeAccessibility, type AccessibilityAction, type AccessibilityContribution, type AccessibilityLiveRegion, type AccessibilityRole, type AccessibilityState, type AccessibilityValue, type AndroidDrawable, type ImportantForAccessibility, type PointerEvents, } from './view-base.ts';
36
- export { VirtualList, VirtualListRow, VirtualListSeparator, type VirtualItemHeight, type VirtualListSeparatorContext, type VirtualListVisiblePosition, type VirtualRow, } from './virtual-list.ts';
36
+ export { VirtualList, VirtualListRow, VirtualListSeparator, type VirtualItemHeight, type VirtualListSeparatorContext, type VirtualListPadding, type VirtualListVisiblePosition, type VirtualRow, } from './virtual-list.ts';
37
37
  export { type GestureBackend, type GestureSpec, type GestureTarget } from './gesture-backend.ts';
38
38
  export { workletScroll, workletStyle, type SharedValue, type WorkletBackend, type WorkletScrollSpec, type WorkletStyleSpec, type WorkletTarget, } from './worklets.ts';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAmD,MAAM,gBAAgB,CAAC;AACjF,OAAO,EAwCN,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,KAAK,EAA+D,MAAM,YAAY,CAAC;AAChG,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,yBAAyB,GAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,oBAAoB,EAAiC,MAAM,6BAA6B,CAAC;AAClG,OAAO,EAAE,KAAK,EAAsD,MAAM,YAAY,CAAC;AACvF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EACL,WAAW,EACX,aAAa,EACb,SAAS,EACT,aAAa,GAGd,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAyC,MAAM,gBAAgB,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAyB,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAkC,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,WAAW,EACX,WAAW,EACX,gBAAgB,GAOjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAA4C,MAAM,WAAW,CAAC;AAC3E,OAAO,EACL,SAAS,GAIV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,uBAAuB,GAUxB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,WAAW,EACX,cAAc,EACd,oBAAoB,GAKrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAA6D,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,aAAa,EACb,YAAY,GAMb,MAAM,eAAe,CAAC","sourcesContent":["/**\n * The host primitives, and the platform-capability tokens they inject.\n *\n * Every element a template renders natively is a component here and must be imported by the\n * component whose template uses it, as any Angular component must. A template that uses one\n * without importing it compiles, renders a plain view, and is reported in dev builds.\n *\n * Importing this barrel evaluates decorators, so anything a Node test needs at runtime has to\n * be reached as a source file instead - see the note in `packages/integration-tests/compile.ts`.\n */\nexport { ActivityIndicator } from './activity-indicator.ts';\nexport { type AnimatedPropsHandle, type AnimationBackend } from './animation.ts';\nexport {\n type AccessibilityActionEvent,\n type AccessibilityActionPayload,\n type ContentSizeChangeEvent,\n type ImageErrorEvent,\n type ImageErrorPayload,\n type ImageLoadEvent,\n type ImageLoadPayload,\n type ImageProgressEvent,\n type ImageProgressPayload,\n type Insets,\n type KeyPressEvent,\n type KeyPressPayload,\n type LayoutEvent,\n type LayoutPayload,\n type OrientationChangeEvent,\n type OrientationChangePayload,\n type Point,\n type Rect,\n type ScrollEvent,\n type ScrollPayload,\n type SelectionChangeEvent,\n type SelectionChangePayload,\n type Size,\n type SwitchChangeEvent,\n type SwitchChangePayload,\n type TextInputChangeEvent,\n type TextInputChangePayload,\n type TextInputContentSizeEvent,\n type TextInputContentSizePayload,\n type TextInputEditingEvent,\n type TextInputFocusEvent,\n type TextInputFocusPayload,\n type TextInputScrollEvent,\n type TextInputScrollPayload,\n type TextLayoutEvent,\n type TextLayoutLine,\n type TextLayoutPayload,\n type TouchEvent,\n type TouchEventPayload,\n} from './events.ts';\nexport { Image, type ImageResizeMode, type ImageSource, type ImageURISource } from './image.ts';\nexport { ImageBackground } from './image-background.ts';\nexport { InputAccessoryView } from './input-accessory-view.ts';\nexport {\n KEYBOARD_CONTROLLER,\n KeyboardDock,\n KeyboardLift,\n provideKeyboardController,\n} from './keyboard-dock.ts';\nexport { KeyboardAvoidingView, type KeyboardAvoidingBehavior } from './keyboard-avoiding-view.ts';\nexport { Modal, type ModalOrientation, type ModalPresentationStyle } from './modal.ts';\nexport { NativeRef } from './native-ref.ts';\nexport {\n ControlBase,\n PressBehavior,\n Pressable,\n TouchableBase,\n type AndroidRipple,\n type PressEvent,\n} from './pressable.ts';\nexport { RefreshControl } from './refresh-control.ts';\nexport { type SafeAreaEdge, type SafeAreaEdges } from './safe-area.ts';\nexport { SafeAreaProvider } from './safe-area-provider.ts';\nexport { SafeAreaView, type SafeAreaEdgeMode } from './safe-area-view.ts';\nexport { type KeyboardShouldPersistTaps } from './keyboard-taps.ts';\nexport { ScrollView } from './scroll-view.ts';\nexport {\n SectionEdgeSeparator,\n SectionFooter,\n SectionHeader,\n SectionItem,\n SectionList,\n SectionSeparator,\n type SectionContext,\n type SectionEdgeSeparatorContext,\n type SectionItemContext,\n type SectionListSection,\n type SectionRow,\n type SectionSeparatorContext,\n} from './section-list.ts';\nexport { Switch } from './switch.ts';\nexport { Text, type DynamicTypeRamp, type EllipsizeMode } from './text.ts';\nexport {\n TextInput,\n type KeyboardType,\n type ReturnKeyType,\n type SubmitBehavior,\n} from './text-input.ts';\nexport { TouchableOpacity } from './touchable-opacity.ts';\nexport { optionalBoolean, optionalNumber } from './transforms.ts';\nexport { View } from './view.ts';\nexport {\n ViewBase,\n ViewBehavior,\n contributeAccessibility,\n type AccessibilityAction,\n type AccessibilityContribution,\n type AccessibilityLiveRegion,\n type AccessibilityRole,\n type AccessibilityState,\n type AccessibilityValue,\n type AndroidDrawable,\n type ImportantForAccessibility,\n type PointerEvents,\n} from './view-base.ts';\nexport {\n VirtualList,\n VirtualListRow,\n VirtualListSeparator,\n type VirtualItemHeight,\n type VirtualListSeparatorContext,\n type VirtualListVisiblePosition,\n type VirtualRow,\n} from './virtual-list.ts';\nexport { type GestureBackend, type GestureSpec, type GestureTarget } from './gesture-backend.ts';\nexport {\n workletScroll,\n workletStyle,\n type SharedValue,\n type WorkletBackend,\n type WorkletScrollSpec,\n type WorkletStyleSpec,\n type WorkletTarget,\n} from './worklets.ts';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAmD,MAAM,gBAAgB,CAAC;AACjF,OAAO,EAwCN,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,KAAK,EAA+D,MAAM,YAAY,CAAC;AAChG,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,yBAAyB,GAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,oBAAoB,EAAiC,MAAM,6BAA6B,CAAC;AAClG,OAAO,EAAE,KAAK,EAAsD,MAAM,YAAY,CAAC;AACvF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EACL,WAAW,EACX,aAAa,EACb,SAAS,EACT,aAAa,GAGd,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAyC,MAAM,gBAAgB,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAyB,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAkC,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,WAAW,EACX,WAAW,EACX,gBAAgB,GAOjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAA4C,MAAM,WAAW,CAAC;AAC3E,OAAO,EACL,SAAS,GAIV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,uBAAuB,GAUxB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,WAAW,EACX,cAAc,EACd,oBAAoB,GAMrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAA6D,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,aAAa,EACb,YAAY,GAMb,MAAM,eAAe,CAAC","sourcesContent":["/**\n * The host primitives, and the platform-capability tokens they inject.\n *\n * Every element a template renders natively is a component here and must be imported by the\n * component whose template uses it, as any Angular component must. A template that uses one\n * without importing it compiles, renders a plain view, and is reported in dev builds.\n *\n * Importing this barrel evaluates decorators, so anything a Node test needs at runtime has to\n * be reached as a source file instead - see the note in `packages/integration-tests/compile.ts`.\n */\nexport { ActivityIndicator } from './activity-indicator.ts';\nexport { type AnimatedPropsHandle, type AnimationBackend } from './animation.ts';\nexport {\n type AccessibilityActionEvent,\n type AccessibilityActionPayload,\n type ContentSizeChangeEvent,\n type ImageErrorEvent,\n type ImageErrorPayload,\n type ImageLoadEvent,\n type ImageLoadPayload,\n type ImageProgressEvent,\n type ImageProgressPayload,\n type Insets,\n type KeyPressEvent,\n type KeyPressPayload,\n type LayoutEvent,\n type LayoutPayload,\n type OrientationChangeEvent,\n type OrientationChangePayload,\n type Point,\n type Rect,\n type ScrollEvent,\n type ScrollPayload,\n type SelectionChangeEvent,\n type SelectionChangePayload,\n type Size,\n type SwitchChangeEvent,\n type SwitchChangePayload,\n type TextInputChangeEvent,\n type TextInputChangePayload,\n type TextInputContentSizeEvent,\n type TextInputContentSizePayload,\n type TextInputEditingEvent,\n type TextInputFocusEvent,\n type TextInputFocusPayload,\n type TextInputScrollEvent,\n type TextInputScrollPayload,\n type TextLayoutEvent,\n type TextLayoutLine,\n type TextLayoutPayload,\n type TouchEvent,\n type TouchEventPayload,\n} from './events.ts';\nexport { Image, type ImageResizeMode, type ImageSource, type ImageURISource } from './image.ts';\nexport { ImageBackground } from './image-background.ts';\nexport { InputAccessoryView } from './input-accessory-view.ts';\nexport {\n KEYBOARD_CONTROLLER,\n KeyboardDock,\n KeyboardLift,\n provideKeyboardController,\n} from './keyboard-dock.ts';\nexport { KeyboardAvoidingView, type KeyboardAvoidingBehavior } from './keyboard-avoiding-view.ts';\nexport { Modal, type ModalOrientation, type ModalPresentationStyle } from './modal.ts';\nexport { NativeRef } from './native-ref.ts';\nexport {\n ControlBase,\n PressBehavior,\n Pressable,\n TouchableBase,\n type AndroidRipple,\n type PressEvent,\n} from './pressable.ts';\nexport { RefreshControl } from './refresh-control.ts';\nexport { type SafeAreaEdge, type SafeAreaEdges } from './safe-area.ts';\nexport { SafeAreaProvider } from './safe-area-provider.ts';\nexport { SafeAreaView, type SafeAreaEdgeMode } from './safe-area-view.ts';\nexport { type KeyboardShouldPersistTaps } from './keyboard-taps.ts';\nexport { ScrollView } from './scroll-view.ts';\nexport {\n SectionEdgeSeparator,\n SectionFooter,\n SectionHeader,\n SectionItem,\n SectionList,\n SectionSeparator,\n type SectionContext,\n type SectionEdgeSeparatorContext,\n type SectionItemContext,\n type SectionListSection,\n type SectionRow,\n type SectionSeparatorContext,\n} from './section-list.ts';\nexport { Switch } from './switch.ts';\nexport { Text, type DynamicTypeRamp, type EllipsizeMode } from './text.ts';\nexport {\n TextInput,\n type KeyboardType,\n type ReturnKeyType,\n type SubmitBehavior,\n} from './text-input.ts';\nexport { TouchableOpacity } from './touchable-opacity.ts';\nexport { optionalBoolean, optionalNumber } from './transforms.ts';\nexport { View } from './view.ts';\nexport {\n ViewBase,\n ViewBehavior,\n contributeAccessibility,\n type AccessibilityAction,\n type AccessibilityContribution,\n type AccessibilityLiveRegion,\n type AccessibilityRole,\n type AccessibilityState,\n type AccessibilityValue,\n type AndroidDrawable,\n type ImportantForAccessibility,\n type PointerEvents,\n} from './view-base.ts';\nexport {\n VirtualList,\n VirtualListRow,\n VirtualListSeparator,\n type VirtualItemHeight,\n type VirtualListSeparatorContext,\n type VirtualListPadding,\n type VirtualListVisiblePosition,\n type VirtualRow,\n} from './virtual-list.ts';\nexport { type GestureBackend, type GestureSpec, type GestureTarget } from './gesture-backend.ts';\nexport {\n workletScroll,\n workletStyle,\n type SharedValue,\n type WorkletBackend,\n type WorkletScrollSpec,\n type WorkletStyleSpec,\n type WorkletTarget,\n} from './worklets.ts';\n"]}
@@ -33,6 +33,11 @@ export declare class KeyboardAvoidingView extends ViewBase {
33
33
  readonly behavior: import("@angular/core").InputSignal<KeyboardAvoidingBehavior>;
34
34
  /** Styles for the inner view that `position` moves. */
35
35
  readonly contentContainerStyle: import("@angular/core").InputSignal<Record<string, unknown> | undefined>;
36
+ /**
37
+ * Classes for the inner view that `position` moves, matched as if it were written in the
38
+ * template this view is. See `ContentContainer`.
39
+ */
40
+ readonly contentContainerClass: import("@angular/core").InputSignal<string | undefined>;
36
41
  /** Set to false to stop avoiding without removing the view. */
37
42
  readonly enabled: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
38
43
  /**
@@ -75,5 +80,5 @@ export declare class KeyboardAvoidingView extends ViewBase {
75
80
  */
76
81
  private windowTop;
77
82
  static ɵfac: i0.ɵɵFactoryDeclaration<KeyboardAvoidingView, never>;
78
- static ɵcmp: i0.ɵɵComponentDeclaration<KeyboardAvoidingView, "keyboard-avoiding-view", never, { "behavior": { "alias": "behavior"; "required": false; "isSignal": true; }; "contentContainerStyle": { "alias": "contentContainerStyle"; "required": false; "isSignal": true; }; "enabled": { "alias": "enabled"; "required": false; "isSignal": true; }; "keyboardVerticalOffset": { "alias": "keyboardVerticalOffset"; "required": false; "isSignal": true; }; }, {}, never, ["*", "*"], true, never>;
83
+ static ɵcmp: i0.ɵɵComponentDeclaration<KeyboardAvoidingView, "keyboard-avoiding-view", never, { "behavior": { "alias": "behavior"; "required": false; "isSignal": true; }; "contentContainerStyle": { "alias": "contentContainerStyle"; "required": false; "isSignal": true; }; "contentContainerClass": { "alias": "contentContainerClass"; "required": false; "isSignal": true; }; "enabled": { "alias": "enabled"; "required": false; "isSignal": true; }; "keyboardVerticalOffset": { "alias": "keyboardVerticalOffset"; "required": false; "isSignal": true; }; }, {}, never, ["*", "*"], true, never>;
79
84
  }
@@ -1,5 +1,6 @@
1
1
  import { Component, booleanAttribute, computed, effect, inject, input, numberAttribute, signal, } from '@angular/core';
2
2
  import { Keyboard, LayoutAnimation } from '@ng-native/device';
3
+ import { ContentContainer } from "./content-container.js";
3
4
  import { View } from "./view.js";
4
5
  import { ViewBase } from "./view-base.js";
5
6
  import * as i0 from "@angular/core";
@@ -51,6 +52,12 @@ export class KeyboardAvoidingView extends ViewBase {
51
52
  /** Styles for the inner view that `position` moves. */
52
53
  contentContainerStyle = input(/* @ts-ignore */
53
54
  ...(ngDevMode ? [undefined, { debugName: "contentContainerStyle" }] : /* istanbul ignore next */ []));
55
+ /**
56
+ * Classes for the inner view that `position` moves, matched as if it were written in the
57
+ * template this view is. See `ContentContainer`.
58
+ */
59
+ contentContainerClass = input(/* @ts-ignore */
60
+ ...(ngDevMode ? [undefined, { debugName: "contentContainerClass" }] : /* istanbul ignore next */ []));
54
61
  /** Set to false to stop avoiding without removing the view. */
55
62
  enabled = input(true, { ...(ngDevMode ? { debugName: "enabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
56
63
  /**
@@ -143,22 +150,32 @@ export class KeyboardAvoidingView extends ViewBase {
143
150
  return top;
144
151
  }
145
152
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: KeyboardAvoidingView, deps: [], target: i0.ɵɵFactoryTarget.Component });
146
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.2.0", type: KeyboardAvoidingView, isStandalone: true, selector: "keyboard-avoiding-view", inputs: { behavior: { classPropertyName: "behavior", publicName: "behavior", isSignal: true, isRequired: false, transformFunction: null }, contentContainerStyle: { classPropertyName: "contentContainerStyle", publicName: "contentContainerStyle", isSignal: true, isRequired: false, transformFunction: null }, enabled: { classPropertyName: "enabled", publicName: "enabled", isSignal: true, isRequired: false, transformFunction: null }, keyboardVerticalOffset: { classPropertyName: "keyboardVerticalOffset", publicName: "keyboardVerticalOffset", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "layout": "onLayout($event)" }, properties: { "styleOverride": "avoidance()" } }, usesInheritance: true, ngImport: i0, template: `
153
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.2.0", type: KeyboardAvoidingView, isStandalone: true, selector: "keyboard-avoiding-view", inputs: { behavior: { classPropertyName: "behavior", publicName: "behavior", isSignal: true, isRequired: false, transformFunction: null }, contentContainerStyle: { classPropertyName: "contentContainerStyle", publicName: "contentContainerStyle", isSignal: true, isRequired: false, transformFunction: null }, contentContainerClass: { classPropertyName: "contentContainerClass", publicName: "contentContainerClass", isSignal: true, isRequired: false, transformFunction: null }, enabled: { classPropertyName: "enabled", publicName: "enabled", isSignal: true, isRequired: false, transformFunction: null }, keyboardVerticalOffset: { classPropertyName: "keyboardVerticalOffset", publicName: "keyboardVerticalOffset", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "layout": "onLayout($event)" }, properties: { "styleOverride": "avoidance()" } }, usesInheritance: true, ngImport: i0, template: `
147
154
  @if (behavior() === 'position') {
148
- <view [style]="positioned()"><ng-content /></view>
155
+ <view
156
+ [contentContainerOf]="node"
157
+ [contentContainerClass]="contentContainerClass()"
158
+ [style]="positioned()"
159
+ ><ng-content
160
+ /></view>
149
161
  } @else {
150
162
  <ng-content />
151
163
  }
152
- `, isInline: true, dependencies: [{ kind: "directive", type: View, selector: "view" }] });
164
+ `, isInline: true, dependencies: [{ kind: "directive", type: ContentContainer, selector: "[contentContainerOf]", inputs: ["contentContainerOf", "contentContainerClass"] }, { kind: "directive", type: View, selector: "view" }] });
153
165
  }
154
166
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: KeyboardAvoidingView, decorators: [{
155
167
  type: Component,
156
168
  args: [{
157
169
  selector: 'keyboard-avoiding-view',
158
- imports: [View],
170
+ imports: [ContentContainer, View],
159
171
  template: `
160
172
  @if (behavior() === 'position') {
161
- <view [style]="positioned()"><ng-content /></view>
173
+ <view
174
+ [contentContainerOf]="node"
175
+ [contentContainerClass]="contentContainerClass()"
176
+ [style]="positioned()"
177
+ ><ng-content
178
+ /></view>
162
179
  } @else {
163
180
  <ng-content />
164
181
  }
@@ -168,5 +185,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImpor
168
185
  '(layout)': 'onLayout($event)',
169
186
  },
170
187
  }]
171
- }], ctorParameters: () => [], propDecorators: { behavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "behavior", required: false }] }], contentContainerStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentContainerStyle", required: false }] }], enabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "enabled", required: false }] }], keyboardVerticalOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "keyboardVerticalOffset", required: false }] }] } });
188
+ }], ctorParameters: () => [], propDecorators: { behavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "behavior", required: false }] }], contentContainerStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentContainerStyle", required: false }] }], contentContainerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentContainerClass", required: false }] }], enabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "enabled", required: false }] }], keyboardVerticalOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "keyboardVerticalOffset", required: false }] }] } });
172
189
  //# sourceMappingURL=keyboard-avoiding-view.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"keyboard-avoiding-view.js","sourceRoot":"","sources":["../src/keyboard-avoiding-view.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n booleanAttribute,\n computed,\n effect,\n inject,\n input,\n numberAttribute,\n signal,\n} from '@angular/core';\nimport { Keyboard, LayoutAnimation, type LayoutEasing } from '@ng-native/device';\nimport type { NativeSyntheticEvent } from '@ng-native/fabric';\nimport type { Rect } from './events.ts';\nimport { View } from './view.ts';\nimport { ViewBase } from './view-base.ts';\n\nexport type KeyboardAvoidingBehavior = 'padding' | 'height' | 'position';\n\n/**\n * The names `LayoutEasing` knows. `'keyboard'` is among them: iOS reports its keyboard's own\n * curve by that name, and RN's KeyboardAvoidingView animates on it.\n */\nconst LAYOUT_EASINGS: ReadonlySet<string> = new Set([\n 'linear',\n 'easeInEaseOut',\n 'easeIn',\n 'easeOut',\n 'spring',\n 'keyboard',\n]);\n\n/** A keyboard event's `easing`, narrowed to what `LayoutAnimation` accepts, or left to its default. */\nfunction layoutEasingOf(easing: string | undefined): LayoutEasing | undefined {\n return easing !== undefined && LAYOUT_EASINGS.has(easing) ? (easing as LayoutEasing) : undefined;\n}\n\n/**\n * Moves its content clear of the keyboard.\n *\n * RN's KeyboardAvoidingView is a JS composite: there is no native component, only a view whose\n * padding, height or position tracks the keyboard. Off a device the `Keyboard` service reports\n * nothing, so this renders as a plain view and does nothing, which is also the right behaviour on\n * a platform with no soft keyboard.\n *\n * The overlap is the view's own frame against the keyboard's top edge, so a view that does not\n * reach the bottom of the screen moves only as far as it must. Unlike RN, the frame's top is\n * measured in the window, which is what the keyboard's `screenY` is in: `(layout)` reports it in\n * the parent's coordinates, and on a screen under a navigation bar those start a bar's height\n * down. RN leaves that to `keyboardVerticalOffset`, and a view that was not told came up short by\n * exactly that much, its bottom edge still behind the keyboard. The overlap never exceeds the\n * view's own height either: padding a view by more than it has pushes its content out of it.\n * When the keyboard source reports no `screenY`, the keyboard's height stands in.\n *\n * The adjustment itself animates with the keyboard's own motion, the way RN's own\n * KeyboardAvoidingView does: a keyboard event's `duration` and `easing` configure the next\n * layout animation before the style change that moves this view, so the two run together rather\n * than the padding, height or position jumping to its resting place in one step.\n */\n@Component({\n selector: 'keyboard-avoiding-view',\n imports: [View],\n template: `\n @if (behavior() === 'position') {\n <view [style]=\"positioned()\"><ng-content /></view>\n } @else {\n <ng-content />\n }\n `,\n host: {\n '[styleOverride]': 'avoidance()',\n '(layout)': 'onLayout($event)',\n },\n})\nexport class KeyboardAvoidingView extends ViewBase {\n /**\n * How to make room: pad the bottom, shrink the height, or shift the content up. RN leaves this\n * unset and does nothing; `padding` is the default here because that is what a form wants.\n */\n readonly behavior = input<KeyboardAvoidingBehavior>('padding');\n /** Styles for the inner view that `position` moves. */\n readonly contentContainerStyle = input<Record<string, unknown>>();\n /** Set to false to stop avoiding without removing the view. */\n readonly enabled = input(true, { transform: booleanAttribute });\n /**\n * Extra room to leave above the keyboard, in points. RN's name, and in RN the place to put a\n * header's height; here the view is measured in the window, so a navigation bar needs none.\n */\n readonly keyboardVerticalOffset = input(0, { transform: numberAttribute });\n\n private readonly keyboard = inject(Keyboard).metrics;\n private readonly layoutAnimation = inject(LayoutAnimation);\n private readonly frame = signal<Rect | null>(null);\n /** The height before any adjustment, which `height` mode shrinks from. */\n private initialHeight: number | null = null;\n\n /** How far the keyboard intrudes into this view, in points. */\n protected readonly overlap = computed(() => {\n if (!this.enabled()) return 0;\n const { height, screenY } = this.keyboard();\n if (height === 0) return 0;\n const frame = this.frame();\n const offset = this.keyboardVerticalOffset();\n if (!frame) return Math.max(0, height - offset);\n // In `height` mode the frame is the one this view already shrank, so measure the height it\n // had before, as RN adds its current adjustment back; otherwise the room it made reads as no\n // overlap and the height springs back under the keyboard.\n const extent =\n this.behavior() === 'height' ? (this.initialHeight ?? frame.height) : frame.height;\n const overlap = screenY === undefined ? height - offset : frame.y + extent - (screenY - offset);\n return Math.min(extent, Math.max(0, overlap));\n });\n\n /**\n * The adjustment, or nothing to adjust. Bound as the engine's style override rather than as\n * host style, because Angular ranks a host style binding under the template's: a caller's\n * `[style]=\"{flex: 1}\"` would otherwise keep its flex in height mode and the view would not\n * shrink at all. RN composes the adjustment after the caller's style, so it wins there too.\n */\n protected readonly avoidance = computed(() => {\n const overlap = this.overlap();\n const behavior = this.behavior();\n if (overlap === 0 || behavior === 'position') return undefined;\n if (behavior === 'height') {\n const base = this.initialHeight ?? this.frame()?.height;\n return base === undefined ? undefined : { height: base - overlap, flex: 0 };\n }\n return { paddingBottom: overlap };\n });\n\n protected readonly positioned = computed(() => ({\n ...this.contentContainerStyle(),\n bottom: this.overlap(),\n }));\n\n constructor() {\n super();\n // A duration of zero is Android's own keyboard event, which animates itself; there is\n // nothing to configure alongside it. `appear`/`leave` are turned off because this is an\n // update to a view already on screen, not one appearing or leaving - RN's own bare\n // `LayoutAnimation.configureNext({duration, update})` animates nothing else either.\n effect(() => {\n const { duration, easing } = this.keyboard();\n if (!this.enabled() || !duration) return;\n void this.layoutAnimation.animate(() => {}, {\n duration,\n easing: layoutEasingOf(easing),\n appear: 'none',\n leave: 'none',\n });\n });\n }\n\n protected onLayout(event: NativeSyntheticEvent<{ layout?: Rect }>): void {\n const layout = event.nativeEvent?.layout;\n if (!layout) return;\n this.frame.set({ ...layout, y: this.windowTop(layout.y) });\n // Only a layout that the keyboard did not cause counts as the natural height.\n if (this.overlap() === 0) this.initialHeight = layout.height;\n }\n\n /**\n * Where this view's top edge is in the window, or `fallback` where the platform cannot say.\n * Synchronous on the new architecture, so it answers for the layout being reported.\n */\n private windowTop(fallback: number): number {\n let top = fallback;\n this.engine.measure(this.node, (frame) => (top = frame.y));\n return top;\n }\n}\n"]}
1
+ {"version":3,"file":"keyboard-avoiding-view.js","sourceRoot":"","sources":["../src/keyboard-avoiding-view.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n booleanAttribute,\n computed,\n effect,\n inject,\n input,\n numberAttribute,\n signal,\n} from '@angular/core';\nimport { Keyboard, LayoutAnimation, type LayoutEasing } from '@ng-native/device';\nimport type { NativeSyntheticEvent } from '@ng-native/fabric';\nimport type { Rect } from './events.ts';\nimport { ContentContainer } from './content-container.ts';\nimport { View } from './view.ts';\nimport { ViewBase } from './view-base.ts';\n\nexport type KeyboardAvoidingBehavior = 'padding' | 'height' | 'position';\n\n/**\n * The names `LayoutEasing` knows. `'keyboard'` is among them: iOS reports its keyboard's own\n * curve by that name, and RN's KeyboardAvoidingView animates on it.\n */\nconst LAYOUT_EASINGS: ReadonlySet<string> = new Set([\n 'linear',\n 'easeInEaseOut',\n 'easeIn',\n 'easeOut',\n 'spring',\n 'keyboard',\n]);\n\n/** A keyboard event's `easing`, narrowed to what `LayoutAnimation` accepts, or left to its default. */\nfunction layoutEasingOf(easing: string | undefined): LayoutEasing | undefined {\n return easing !== undefined && LAYOUT_EASINGS.has(easing) ? (easing as LayoutEasing) : undefined;\n}\n\n/**\n * Moves its content clear of the keyboard.\n *\n * RN's KeyboardAvoidingView is a JS composite: there is no native component, only a view whose\n * padding, height or position tracks the keyboard. Off a device the `Keyboard` service reports\n * nothing, so this renders as a plain view and does nothing, which is also the right behaviour on\n * a platform with no soft keyboard.\n *\n * The overlap is the view's own frame against the keyboard's top edge, so a view that does not\n * reach the bottom of the screen moves only as far as it must. Unlike RN, the frame's top is\n * measured in the window, which is what the keyboard's `screenY` is in: `(layout)` reports it in\n * the parent's coordinates, and on a screen under a navigation bar those start a bar's height\n * down. RN leaves that to `keyboardVerticalOffset`, and a view that was not told came up short by\n * exactly that much, its bottom edge still behind the keyboard. The overlap never exceeds the\n * view's own height either: padding a view by more than it has pushes its content out of it.\n * When the keyboard source reports no `screenY`, the keyboard's height stands in.\n *\n * The adjustment itself animates with the keyboard's own motion, the way RN's own\n * KeyboardAvoidingView does: a keyboard event's `duration` and `easing` configure the next\n * layout animation before the style change that moves this view, so the two run together rather\n * than the padding, height or position jumping to its resting place in one step.\n */\n@Component({\n selector: 'keyboard-avoiding-view',\n imports: [ContentContainer, View],\n template: `\n @if (behavior() === 'position') {\n <view\n [contentContainerOf]=\"node\"\n [contentContainerClass]=\"contentContainerClass()\"\n [style]=\"positioned()\"\n ><ng-content\n /></view>\n } @else {\n <ng-content />\n }\n `,\n host: {\n '[styleOverride]': 'avoidance()',\n '(layout)': 'onLayout($event)',\n },\n})\nexport class KeyboardAvoidingView extends ViewBase {\n /**\n * How to make room: pad the bottom, shrink the height, or shift the content up. RN leaves this\n * unset and does nothing; `padding` is the default here because that is what a form wants.\n */\n readonly behavior = input<KeyboardAvoidingBehavior>('padding');\n /** Styles for the inner view that `position` moves. */\n readonly contentContainerStyle = input<Record<string, unknown>>();\n /**\n * Classes for the inner view that `position` moves, matched as if it were written in the\n * template this view is. See `ContentContainer`.\n */\n readonly contentContainerClass = input<string>();\n /** Set to false to stop avoiding without removing the view. */\n readonly enabled = input(true, { transform: booleanAttribute });\n /**\n * Extra room to leave above the keyboard, in points. RN's name, and in RN the place to put a\n * header's height; here the view is measured in the window, so a navigation bar needs none.\n */\n readonly keyboardVerticalOffset = input(0, { transform: numberAttribute });\n\n private readonly keyboard = inject(Keyboard).metrics;\n private readonly layoutAnimation = inject(LayoutAnimation);\n private readonly frame = signal<Rect | null>(null);\n /** The height before any adjustment, which `height` mode shrinks from. */\n private initialHeight: number | null = null;\n\n /** How far the keyboard intrudes into this view, in points. */\n protected readonly overlap = computed(() => {\n if (!this.enabled()) return 0;\n const { height, screenY } = this.keyboard();\n if (height === 0) return 0;\n const frame = this.frame();\n const offset = this.keyboardVerticalOffset();\n if (!frame) return Math.max(0, height - offset);\n // In `height` mode the frame is the one this view already shrank, so measure the height it\n // had before, as RN adds its current adjustment back; otherwise the room it made reads as no\n // overlap and the height springs back under the keyboard.\n const extent =\n this.behavior() === 'height' ? (this.initialHeight ?? frame.height) : frame.height;\n const overlap = screenY === undefined ? height - offset : frame.y + extent - (screenY - offset);\n return Math.min(extent, Math.max(0, overlap));\n });\n\n /**\n * The adjustment, or nothing to adjust. Bound as the engine's style override rather than as\n * host style, because Angular ranks a host style binding under the template's: a caller's\n * `[style]=\"{flex: 1}\"` would otherwise keep its flex in height mode and the view would not\n * shrink at all. RN composes the adjustment after the caller's style, so it wins there too.\n */\n protected readonly avoidance = computed(() => {\n const overlap = this.overlap();\n const behavior = this.behavior();\n if (overlap === 0 || behavior === 'position') return undefined;\n if (behavior === 'height') {\n const base = this.initialHeight ?? this.frame()?.height;\n return base === undefined ? undefined : { height: base - overlap, flex: 0 };\n }\n return { paddingBottom: overlap };\n });\n\n protected readonly positioned = computed(() => ({\n ...this.contentContainerStyle(),\n bottom: this.overlap(),\n }));\n\n constructor() {\n super();\n // A duration of zero is Android's own keyboard event, which animates itself; there is\n // nothing to configure alongside it. `appear`/`leave` are turned off because this is an\n // update to a view already on screen, not one appearing or leaving - RN's own bare\n // `LayoutAnimation.configureNext({duration, update})` animates nothing else either.\n effect(() => {\n const { duration, easing } = this.keyboard();\n if (!this.enabled() || !duration) return;\n void this.layoutAnimation.animate(() => {}, {\n duration,\n easing: layoutEasingOf(easing),\n appear: 'none',\n leave: 'none',\n });\n });\n }\n\n protected onLayout(event: NativeSyntheticEvent<{ layout?: Rect }>): void {\n const layout = event.nativeEvent?.layout;\n if (!layout) return;\n this.frame.set({ ...layout, y: this.windowTop(layout.y) });\n // Only a layout that the keyboard did not cause counts as the natural height.\n if (this.overlap() === 0) this.initialHeight = layout.height;\n }\n\n /**\n * Where this view's top edge is in the window, or `fallback` where the platform cannot say.\n * Synchronous on the new architecture, so it answers for the layout being reported.\n */\n private windowTop(fallback: number): number {\n let top = fallback;\n this.engine.measure(this.node, (frame) => (top = frame.y));\n return top;\n }\n}\n"]}
@@ -26,8 +26,11 @@ interface RippleDrawable {
26
26
  * every element that carries it, on every pass. The controls bind theirs through `ControlBase`.
27
27
  */
28
28
  export declare abstract class TouchableBase extends ViewBase {
29
- /** Ignore touches entirely. */
30
- readonly disabled: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
29
+ /**
30
+ * Ignore touches entirely. Undefined until set, because React Native tells "not passed" from
31
+ * "passed false": only a passed `disabled` wins over `aria-disabled` in what is announced.
32
+ */
33
+ readonly disabled: import("@angular/core").InputSignalWithTransform<boolean | undefined, unknown>;
31
34
  /**
32
35
  * How far outside the hit area a touch may wander before the press is cancelled. Native's
33
36
  * `hitSlop` grows the area a touch can start in; this grows the area it may move within.
@@ -98,6 +101,17 @@ export declare abstract class TouchableBase extends ViewBase {
98
101
  protected pressedChanged(_pressed: boolean): void;
99
102
  /** Whether a touch starting on this node should be claimed. `Text` narrows it. */
100
103
  protected claims(): boolean;
104
+ /**
105
+ * Whether presses are refused. `Pressable.js` gives Pressability `disabled` alone, so here
106
+ * `aria-disabled` and `accessibilityState.disabled` change what is announced and nothing else.
107
+ * `TouchableOpacity` and `Text` widen it.
108
+ */
109
+ protected pressDisabled(): boolean;
110
+ /**
111
+ * `TouchableOpacity.js` and `Text.js`: `disabled ?? aria-disabled ?? accessibilityState.disabled`,
112
+ * which is the merged announced state whenever `disabled` is unset.
113
+ */
114
+ protected disabledByAnyState(): boolean;
101
115
  /**
102
116
  * Whether the control's size should be tracked. Native only measures a view that asks, so
103
117
  * this must not be true for every `<text>`: a pressable text opts in, a label never does.
@@ -126,8 +140,23 @@ export declare abstract class TouchableBase extends ViewBase {
126
140
  private stopResponding;
127
141
  private stopLayout;
128
142
  private stopHover;
143
+ private stopClick;
129
144
  ngOnInit(): void;
130
145
  ngOnChanges(): void;
146
+ /**
147
+ * A press with no touch: Android's `performClick()`, which is what Enter, the D-pad centre and
148
+ * TalkBack's double-tap do to a focused view, and which reaches us as `topClick` alone.
149
+ *
150
+ * `Pressability.js` answers it in `onClick`: `onPress` and nothing around it, not while disabled,
151
+ * and not for a click carrying a `pointerType`, which is the pointer event a touch already
152
+ * pressed through. It presses only the view that was clicked: a touchable the click only bubbled
153
+ * through stops it there, so neither it nor anything above it acts on a click meant for a
154
+ * focusable view inside it.
155
+ *
156
+ * Android only. iOS sends a click only as a pointer event, and the web host binds `topClick` to
157
+ * the DOM's own click, which a mouse press already reached through the responder.
158
+ */
159
+ private clickIfNeeded;
131
160
  /**
132
161
  * Join the responder negotiation, once this is something a touch can press.
133
162
  *
@@ -198,7 +227,7 @@ export declare abstract class ControlBase extends TouchableBase {
198
227
  export declare class PressBehavior extends ControlBase {
199
228
  protected accessibleByDefault(): boolean;
200
229
  protected focusableByDefault(): boolean;
201
- protected disabledForAccessibility(): boolean;
230
+ protected disabledForAccessibility(): boolean | undefined;
202
231
  static ɵfac: i0.ɵɵFactoryDeclaration<PressBehavior, never>;
203
232
  static ɵdir: i0.ɵɵDirectiveDeclaration<PressBehavior, never, never, {}, {}, never, never, true, never>;
204
233
  }
@@ -213,7 +242,7 @@ export declare class Pressable extends ControlBase {
213
242
  /** `Pressable.js`: a control is an accessibility element, and focusable, unless refused. */
214
243
  protected accessibleByDefault(): boolean;
215
244
  protected focusableByDefault(): boolean;
216
- protected disabledForAccessibility(): boolean;
245
+ protected disabledForAccessibility(): boolean | undefined;
217
246
  static ɵfac: i0.ɵɵFactoryDeclaration<Pressable, never>;
218
247
  static ɵdir: i0.ɵɵDirectiveDeclaration<Pressable, "pressable", ["pressable"], {}, {}, never, never, true, never>;
219
248
  }
package/dist/pressable.js CHANGED
@@ -6,6 +6,8 @@
6
6
  * responder negotiation, so a button and an enclosing scroll view agree on who owns a drag.
7
7
  */
8
8
  import { Directive, booleanAttribute, forwardRef, input, numberAttribute, output, signal, } from '@angular/core';
9
+ import { nativePlatform } from '@ng-native/fabric';
10
+ import { optionalBoolean } from "./transforms.js";
9
11
  import { ViewBase } from "./view-base.js";
10
12
  import * as i0 from "@angular/core";
11
13
  /**
@@ -53,8 +55,11 @@ const now = () => globalThis.performance?.now?.() ?? Date.now();
53
55
  * every element that carries it, on every pass. The controls bind theirs through `ControlBase`.
54
56
  */
55
57
  export class TouchableBase extends ViewBase {
56
- /** Ignore touches entirely. */
57
- disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
58
+ /**
59
+ * Ignore touches entirely. Undefined until set, because React Native tells "not passed" from
60
+ * "passed false": only a passed `disabled` wins over `aria-disabled` in what is announced.
61
+ */
62
+ disabled = input(undefined, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: optionalBoolean });
58
63
  /**
59
64
  * How far outside the hit area a touch may wander before the press is cancelled. Native's
60
65
  * `hitSlop` grows the area a touch can start in; this grows the area it may move within.
@@ -169,7 +174,22 @@ export class TouchableBase extends ViewBase {
169
174
  pressedChanged(_pressed) { }
170
175
  /** Whether a touch starting on this node should be claimed. `Text` narrows it. */
171
176
  claims() {
172
- return !this.disabled();
177
+ return !this.pressDisabled();
178
+ }
179
+ /**
180
+ * Whether presses are refused. `Pressable.js` gives Pressability `disabled` alone, so here
181
+ * `aria-disabled` and `accessibilityState.disabled` change what is announced and nothing else.
182
+ * `TouchableOpacity` and `Text` widen it.
183
+ */
184
+ pressDisabled() {
185
+ return !!this.disabled();
186
+ }
187
+ /**
188
+ * `TouchableOpacity.js` and `Text.js`: `disabled ?? aria-disabled ?? accessibilityState.disabled`,
189
+ * which is the merged announced state whenever `disabled` is unset.
190
+ */
191
+ disabledByAnyState() {
192
+ return (this.disabled() ?? this.accessibilityStateProp()?.disabled) === true;
173
193
  }
174
194
  /**
175
195
  * Whether the control's size should be tracked. Native only measures a view that asks, so
@@ -210,21 +230,53 @@ export class TouchableBase extends ViewBase {
210
230
  this.stopResponding?.();
211
231
  this.stopLayout?.();
212
232
  this.stopHover?.();
233
+ this.stopClick?.();
213
234
  }
214
235
  stopResponding = null;
215
236
  stopLayout = null;
216
237
  stopHover = null;
238
+ stopClick = null;
217
239
  ngOnInit() {
218
240
  super.ngOnInit();
219
241
  this.respondIfNeeded();
220
242
  this.measureIfNeeded();
221
243
  this.hoverIfNeeded();
244
+ this.clickIfNeeded();
222
245
  }
223
246
  ngOnChanges() {
224
247
  super.ngOnChanges();
225
248
  this.respondIfNeeded();
226
249
  this.measureIfNeeded();
227
250
  this.hoverIfNeeded();
251
+ this.clickIfNeeded();
252
+ }
253
+ /**
254
+ * A press with no touch: Android's `performClick()`, which is what Enter, the D-pad centre and
255
+ * TalkBack's double-tap do to a focused view, and which reaches us as `topClick` alone.
256
+ *
257
+ * `Pressability.js` answers it in `onClick`: `onPress` and nothing around it, not while disabled,
258
+ * and not for a click carrying a `pointerType`, which is the pointer event a touch already
259
+ * pressed through. It presses only the view that was clicked: a touchable the click only bubbled
260
+ * through stops it there, so neither it nor anything above it acts on a click meant for a
261
+ * focusable view inside it.
262
+ *
263
+ * Android only. iOS sends a click only as a pointer event, and the web host binds `topClick` to
264
+ * the DOM's own click, which a mouse press already reached through the responder.
265
+ */
266
+ clickIfNeeded() {
267
+ if (this.stopClick || !this.measures() || nativePlatform() !== 'android')
268
+ return;
269
+ this.stopClick = this.engine.setEventListener(this.node, 'topClick', (event) => {
270
+ const click = event;
271
+ if (!this.measures() || Object.hasOwn(click.nativeEvent ?? {}, 'pointerType'))
272
+ return;
273
+ if (click.target !== this.node) {
274
+ click.stopPropagation();
275
+ return;
276
+ }
277
+ if (this.claims())
278
+ this.press.emit(click);
279
+ });
228
280
  }
229
281
  /**
230
282
  * Join the responder negotiation, once this is something a touch can press.