@ng-native/components 0.2.0 → 0.4.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/dist/content-container.d.ts +25 -0
- package/dist/content-container.js +35 -0
- package/dist/content-container.js.map +1 -0
- package/dist/gestures-web.d.ts +12 -0
- package/dist/gestures-web.js +32 -0
- package/dist/gestures-web.js.map +1 -0
- package/dist/gestures.d.ts +0 -1
- package/dist/gestures.js +5 -4
- package/dist/gestures.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js.map +1 -1
- package/dist/keyboard-avoiding-view.d.ts +6 -1
- package/dist/keyboard-avoiding-view.js +23 -6
- package/dist/keyboard-avoiding-view.js.map +1 -1
- package/dist/pressable.d.ts +56 -4
- package/dist/pressable.js +80 -7
- package/dist/pressable.js.map +1 -1
- package/dist/reanimated-web.d.ts +18 -0
- package/dist/reanimated-web.js +59 -0
- package/dist/reanimated-web.js.map +1 -0
- package/dist/reanimated.d.ts +4 -4
- package/dist/reanimated.js +3 -3
- package/dist/reanimated.js.map +1 -1
- package/dist/refresh-control.d.ts +4 -1
- package/dist/refresh-control.js +4 -1
- package/dist/refresh-control.js.map +1 -1
- package/dist/scroll-view.d.ts +17 -1
- package/dist/scroll-view.js +59 -6
- package/dist/scroll-view.js.map +1 -1
- package/dist/section-list.d.ts +14 -2
- package/dist/section-list.js +20 -4
- package/dist/section-list.js.map +1 -1
- package/dist/stand-ins/gesture-handler.d.ts +40 -0
- package/dist/stand-ins/gesture-handler.js +43 -0
- package/dist/stand-ins/gesture-handler.js.map +1 -0
- package/dist/stand-ins/reanimated.d.ts +62 -0
- package/dist/stand-ins/reanimated.js +95 -0
- package/dist/stand-ins/reanimated.js.map +1 -0
- package/dist/stand-ins/worklets.d.ts +11 -0
- package/dist/stand-ins/worklets.js +24 -0
- package/dist/stand-ins/worklets.js.map +1 -0
- package/dist/sticky-headers.d.ts +6 -0
- package/dist/sticky-headers.js +7 -2
- package/dist/sticky-headers.js.map +1 -1
- package/dist/switch.d.ts +11 -1
- package/dist/switch.js +16 -3
- package/dist/switch.js.map +1 -1
- package/dist/text.d.ts +11 -2
- package/dist/text.js +15 -1
- package/dist/text.js.map +1 -1
- package/dist/touchable-opacity.d.ts +2 -1
- package/dist/touchable-opacity.js +3 -0
- package/dist/touchable-opacity.js.map +1 -1
- package/dist/view-base.d.ts +36 -21
- package/dist/view-base.js +91 -23
- package/dist/view-base.js.map +1 -1
- package/dist/virtual-list.d.ts +52 -7
- package/dist/virtual-list.js +132 -44
- package/dist/virtual-list.js.map +1 -1
- package/dist/worklets.d.ts +11 -0
- package/dist/worklets.js.map +1 -1
- package/dist/written-props.js +1 -0
- package/dist/written-props.js.map +1 -1
- package/dist/zero-size-warning.d.ts +30 -0
- package/dist/zero-size-warning.js +58 -0
- package/dist/zero-size-warning.js.map +1 -0
- package/package.json +19 -4
package/dist/scroll-view.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Component, DestroyRef, ElementRef, afterEveryRender, computed, contentChild, inject, input, output, viewChild, } from '@angular/core';
|
|
2
2
|
import { nativePlatform } from '@ng-native/fabric';
|
|
3
3
|
import { dismissKeyboardOnTap } from "./keyboard-taps.js";
|
|
4
|
+
import { ContentContainer } from "./content-container.js";
|
|
4
5
|
import { RefreshControl } from "./refresh-control.js";
|
|
5
6
|
import { StickyHeaders } from "./sticky-headers.js";
|
|
6
7
|
import { optionalBoolean } from "./transforms.js";
|
|
7
8
|
import { ScrollViewProps } from "./scroll-view-props.js";
|
|
8
9
|
import { View } from "./view.js";
|
|
10
|
+
import { ZeroSizeWarning, checksZeroSize, written } from "./zero-size-warning.js";
|
|
9
11
|
import * as i0 from "@angular/core";
|
|
10
12
|
/**
|
|
11
13
|
* A scrolling container. Commits as `RCTScrollView`, with the children inside a content view.
|
|
@@ -38,6 +40,13 @@ export class ScrollView extends ScrollViewProps {
|
|
|
38
40
|
/** Styles for the view that holds the children, e.g. padding and gap. */
|
|
39
41
|
contentContainerStyle = input(/* @ts-ignore */
|
|
40
42
|
...(ngDevMode ? [undefined, { debugName: "contentContainerStyle" }] : /* istanbul ignore next */ []));
|
|
43
|
+
/**
|
|
44
|
+
* Classes for the view that holds the children, matched as if the view were written in the
|
|
45
|
+
* template the scroll view is. See `ContentContainer`. `contentContainerStyle` wins over it, as
|
|
46
|
+
* an inline style does over a class.
|
|
47
|
+
*/
|
|
48
|
+
contentContainerClass = input(/* @ts-ignore */
|
|
49
|
+
...(ngDevMode ? [undefined, { debugName: "contentContainerClass" }] : /* istanbul ignore next */ []));
|
|
41
50
|
/**
|
|
42
51
|
* The content view's style, with the row direction a horizontal scroll view needs.
|
|
43
52
|
*
|
|
@@ -86,6 +95,30 @@ export class ScrollView extends ScrollViewProps {
|
|
|
86
95
|
const stop = dismissKeyboardOnTap(this.engine, this.node, () => this.keyboardShouldPersistTaps());
|
|
87
96
|
inject(DestroyRef).onDestroy(stop);
|
|
88
97
|
this.trackStickyHeaders();
|
|
98
|
+
if (checksZeroSize())
|
|
99
|
+
this.checkZeroSize();
|
|
100
|
+
}
|
|
101
|
+
/** The content's extent along the axis, and the scroll view's own, for `checkZeroSize`. */
|
|
102
|
+
contentExtent = 0;
|
|
103
|
+
ownExtent;
|
|
104
|
+
zeroSize = null;
|
|
105
|
+
/**
|
|
106
|
+
* In development only, the scroll view's own layout, to say when it stays at zero size with
|
|
107
|
+
* content in it. A release build listens for nothing, so it commits no `onLayout`.
|
|
108
|
+
*/
|
|
109
|
+
checkZeroSize() {
|
|
110
|
+
const warning = (this.zeroSize = new ZeroSizeWarning(() => written(this.node), () => !!this.horizontal()));
|
|
111
|
+
const stop = this.engine.setEventListener(this.node, 'topLayout', (event) => {
|
|
112
|
+
this.ownExtent = this.extent(event.nativeEvent?.layout);
|
|
113
|
+
warning.laidOut(this.ownExtent, this.contentExtent > 0);
|
|
114
|
+
});
|
|
115
|
+
inject(DestroyRef).onDestroy(() => {
|
|
116
|
+
stop();
|
|
117
|
+
warning.stop();
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
extent(size) {
|
|
121
|
+
return (this.horizontal() ? size?.width : size?.height) ?? 0;
|
|
89
122
|
}
|
|
90
123
|
/**
|
|
91
124
|
* Sticky children are found again after each pass, because a pass can add or move them, and the
|
|
@@ -135,21 +168,34 @@ export class ScrollView extends ScrollViewProps {
|
|
|
135
168
|
const layout = event.nativeEvent?.layout;
|
|
136
169
|
if (layout)
|
|
137
170
|
this.contentSizeChange.emit({ width: layout.width, height: layout.height });
|
|
171
|
+
if (this.zeroSize) {
|
|
172
|
+
this.contentExtent = this.extent(layout);
|
|
173
|
+
if (this.ownExtent !== undefined) {
|
|
174
|
+
this.zeroSize.laidOut(this.ownExtent, this.contentExtent > 0);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
138
177
|
}
|
|
139
178
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: ScrollView, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
140
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.2.0", type: ScrollView, isStandalone: true, selector: "scroll-view", inputs: { contentContainerStyle: { classPropertyName: "contentContainerStyle", publicName: "contentContainerStyle", isSignal: true, isRequired: false, transformFunction: null }, horizontal: { classPropertyName: "horizontal", publicName: "horizontal", isSignal: true, isRequired: false, transformFunction: null }, contentOffset: { classPropertyName: "contentOffset", publicName: "contentOffset", isSignal: true, isRequired: false, transformFunction: null }, maintainVisibleContentPosition: { classPropertyName: "maintainVisibleContentPosition", publicName: "maintainVisibleContentPosition", isSignal: true, isRequired: false, transformFunction: null }, keyboardShouldPersistTaps: { classPropertyName: "keyboardShouldPersistTaps", publicName: "keyboardShouldPersistTaps", isSignal: true, isRequired: false, transformFunction: null }, nestedScrollEnabled: { classPropertyName: "nestedScrollEnabled", publicName: "nestedScrollEnabled", isSignal: true, isRequired: false, transformFunction: null }, stickyHeaderIndices: { classPropertyName: "stickyHeaderIndices", publicName: "stickyHeaderIndices", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { contentSizeChange: "contentSizeChange" }, host: { properties: { "flexDirection": "horizontal() ? 'row' : 'column'", "horizontal": "horizontal()", "contentOffset": "contentOffset()", "maintainVisibleContentPosition": "maintainVisibleContentPosition()", "scrollEventThrottle": "resolvedThrottle()", "nestedScrollEnabled": "resolvedNestedScroll()" } }, queries: [{ propertyName: "refreshControl", first: true, predicate: RefreshControl, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, read: ElementRef, isSignal: true }], exportAs: ["scrollView"], usesInheritance: true, ngImport: i0, template: `
|
|
179
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.2.0", type: ScrollView, isStandalone: true, selector: "scroll-view", inputs: { contentContainerStyle: { classPropertyName: "contentContainerStyle", publicName: "contentContainerStyle", isSignal: true, isRequired: false, transformFunction: null }, contentContainerClass: { classPropertyName: "contentContainerClass", publicName: "contentContainerClass", isSignal: true, isRequired: false, transformFunction: null }, horizontal: { classPropertyName: "horizontal", publicName: "horizontal", isSignal: true, isRequired: false, transformFunction: null }, contentOffset: { classPropertyName: "contentOffset", publicName: "contentOffset", isSignal: true, isRequired: false, transformFunction: null }, maintainVisibleContentPosition: { classPropertyName: "maintainVisibleContentPosition", publicName: "maintainVisibleContentPosition", isSignal: true, isRequired: false, transformFunction: null }, keyboardShouldPersistTaps: { classPropertyName: "keyboardShouldPersistTaps", publicName: "keyboardShouldPersistTaps", isSignal: true, isRequired: false, transformFunction: null }, nestedScrollEnabled: { classPropertyName: "nestedScrollEnabled", publicName: "nestedScrollEnabled", isSignal: true, isRequired: false, transformFunction: null }, stickyHeaderIndices: { classPropertyName: "stickyHeaderIndices", publicName: "stickyHeaderIndices", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { contentSizeChange: "contentSizeChange" }, host: { properties: { "flexDirection": "horizontal() ? 'row' : 'column'", "horizontal": "horizontal()", "contentOffset": "contentOffset()", "maintainVisibleContentPosition": "maintainVisibleContentPosition()", "scrollEventThrottle": "resolvedThrottle()", "nestedScrollEnabled": "resolvedNestedScroll()" } }, queries: [{ propertyName: "refreshControl", first: true, predicate: RefreshControl, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, read: ElementRef, isSignal: true }], exportAs: ["scrollView"], usesInheritance: true, ngImport: i0, template: `
|
|
141
180
|
<ng-content select="refresh-control" />
|
|
142
|
-
<view
|
|
181
|
+
<view
|
|
182
|
+
#content
|
|
183
|
+
[contentContainerOf]="node"
|
|
184
|
+
[contentContainerClass]="contentContainerClass()"
|
|
185
|
+
[style]="contentStyle()"
|
|
186
|
+
collapsable="false"
|
|
187
|
+
(layout)="onContentLayout($event)"
|
|
188
|
+
>
|
|
143
189
|
<ng-content />
|
|
144
190
|
</view>
|
|
145
|
-
`, isInline: true, dependencies: [{ kind: "directive", type: View, selector: "view" }] });
|
|
191
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: ContentContainer, selector: "[contentContainerOf]", inputs: ["contentContainerOf", "contentContainerClass"] }, { kind: "directive", type: View, selector: "view" }] });
|
|
146
192
|
}
|
|
147
193
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: ScrollView, decorators: [{
|
|
148
194
|
type: Component,
|
|
149
195
|
args: [{
|
|
150
196
|
selector: 'scroll-view',
|
|
151
197
|
exportAs: 'scrollView',
|
|
152
|
-
imports: [View],
|
|
198
|
+
imports: [ContentContainer, View],
|
|
153
199
|
// `collapsable: false` is load-bearing, not a hint. Fabric flattens views whose props are
|
|
154
200
|
// layout-only, and a content container with just padding qualifies: it gets no UIView at all.
|
|
155
201
|
// Touches in its empty areas then land on the scroll view itself, which does not scroll from a
|
|
@@ -162,7 +208,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImpor
|
|
|
162
208
|
// scroll view, and never attach.
|
|
163
209
|
template: `
|
|
164
210
|
<ng-content select="refresh-control" />
|
|
165
|
-
<view
|
|
211
|
+
<view
|
|
212
|
+
#content
|
|
213
|
+
[contentContainerOf]="node"
|
|
214
|
+
[contentContainerClass]="contentContainerClass()"
|
|
215
|
+
[style]="contentStyle()"
|
|
216
|
+
collapsable="false"
|
|
217
|
+
(layout)="onContentLayout($event)"
|
|
218
|
+
>
|
|
166
219
|
<ng-content />
|
|
167
220
|
</view>
|
|
168
221
|
`,
|
|
@@ -177,5 +230,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImpor
|
|
|
177
230
|
'[nestedScrollEnabled]': 'resolvedNestedScroll()',
|
|
178
231
|
},
|
|
179
232
|
}]
|
|
180
|
-
}], ctorParameters: () => [], propDecorators: { contentContainerStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentContainerStyle", required: false }] }], horizontal: [{ type: i0.Input, args: [{ isSignal: true, alias: "horizontal", required: false }] }], contentOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentOffset", required: false }] }], maintainVisibleContentPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "maintainVisibleContentPosition", required: false }] }], keyboardShouldPersistTaps: [{ type: i0.Input, args: [{ isSignal: true, alias: "keyboardShouldPersistTaps", required: false }] }], nestedScrollEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "nestedScrollEnabled", required: false }] }], stickyHeaderIndices: [{ type: i0.Input, args: [{ isSignal: true, alias: "stickyHeaderIndices", required: false }] }], contentSizeChange: [{ type: i0.Output, args: ["contentSizeChange"] }], refreshControl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => RefreshControl), { isSignal: true }] }], content: [{ type: i0.ViewChild, args: ['content', { ...{ read: ElementRef }, isSignal: true }] }] } });
|
|
233
|
+
}], ctorParameters: () => [], propDecorators: { contentContainerStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentContainerStyle", required: false }] }], contentContainerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentContainerClass", required: false }] }], horizontal: [{ type: i0.Input, args: [{ isSignal: true, alias: "horizontal", required: false }] }], contentOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentOffset", required: false }] }], maintainVisibleContentPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "maintainVisibleContentPosition", required: false }] }], keyboardShouldPersistTaps: [{ type: i0.Input, args: [{ isSignal: true, alias: "keyboardShouldPersistTaps", required: false }] }], nestedScrollEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "nestedScrollEnabled", required: false }] }], stickyHeaderIndices: [{ type: i0.Input, args: [{ isSignal: true, alias: "stickyHeaderIndices", required: false }] }], contentSizeChange: [{ type: i0.Output, args: ["contentSizeChange"] }], refreshControl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => RefreshControl), { isSignal: true }] }], content: [{ type: i0.ViewChild, args: ['content', { ...{ read: ElementRef }, isSignal: true }] }] } });
|
|
181
234
|
//# sourceMappingURL=scroll-view.js.map
|
package/dist/scroll-view.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scroll-view.js","sourceRoot":"","sources":["../src/scroll-view.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n DestroyRef,\n ElementRef,\n afterEveryRender,\n computed,\n contentChild,\n inject,\n input,\n output,\n viewChild,\n} from '@angular/core';\nimport { type HostNode, type NativeSyntheticEvent, nativePlatform } from '@ng-native/fabric';\nimport type { Point, Rect, Size } from './events.ts';\nimport { type KeyboardShouldPersistTaps, dismissKeyboardOnTap } from './keyboard-taps.ts';\nimport { RefreshControl } from './refresh-control.ts';\nimport { StickyHeaders } from './sticky-headers.ts';\nimport { optionalBoolean } from './transforms.ts';\nimport { ScrollViewProps } from './scroll-view-props.ts';\nimport { View } from './view.ts';\n\n/**\n * A scrolling container. Commits as `RCTScrollView`, with the children inside a content view.\n *\n * The native scroll view has no `contentContainerStyle`: RN's `ScrollView.js` wraps children in\n * a content view and applies it there, which is done here. The engine gives the host RN's base\n * style (`overflow: 'scroll'` and the flex defaults); without it the content spills out of the\n * scroll view's bounds.\n *\n * `horizontal` changes two things rather than one, and both are needed. RN swaps its whole base\n * style for `baseHorizontal` - the same defaults but `flexDirection: 'row'` - and puts\n * `contentContainerHorizontal` on the content view. With the host left as a column the content\n * view is stretched to the scroll view's width instead of growing past it, so there is nothing to\n * scroll to and a sideways drag does nothing at all. It looks like a scroll view that simply has\n * too little in it.\n *\n * Keyboard policy is the other half of what `ScrollView.js` does in JavaScript. With a text\n * input focused, a tap elsewhere in the scroll view dismisses the keyboard and goes no further\n * (`keyboardShouldPersistTaps: 'never'`, the default), reaches the child first and dismisses only\n * if nothing handled it (`'handled'`), or never dismisses (`'always'`).\n *\n * `stickyHeaderIndices` pins those children of the content to the leading edge, each until the\n * next pushes it off. It is JavaScript in RN as well; see `StickyHeaders`.\n *\n * Events are element events: `(scroll)`, `(scrollBeginDrag)`, `(scrollEndDrag)`,\n * `(momentumScrollBegin)`, `(momentumScrollEnd)`, `(scrollToTop)`. `(contentSizeChange)` is an\n * output, measured from the content view's layout as RN does.\n */\n@Component({\n selector: 'scroll-view',\n exportAs: 'scrollView',\n imports: [View],\n // `collapsable: false` is load-bearing, not a hint. Fabric flattens views whose props are\n // layout-only, and a content container with just padding qualifies: it gets no UIView at all.\n // Touches in its empty areas then land on the scroll view itself, which does not scroll from a\n // direct hit, so dragging anywhere the children do not cover silently does nothing. RN sets the\n // same flag on its content container for the same reason.\n //\n // A refresh control is the scroll view's own child, before the content view, as RN's\n // ScrollView.js commits it. On iOS it finds its scroll view once, when it is inserted, and\n // Fabric mounts bottom-up: inside the content view it would look before that view was in the\n // scroll view, and never attach.\n template: `\n <ng-content select=\"refresh-control\" />\n <view #content [style]=\"contentStyle()\" collapsable=\"false\" (layout)=\"onContentLayout($event)\">\n <ng-content />\n </view>\n `,\n host: {\n // The base style's direction, which `horizontal` decides. A top-level prop rather than a\n // host `[style]`, so the caller's own `[style]` still applies over it as it does in RN.\n '[flexDirection]': \"horizontal() ? 'row' : 'column'\",\n '[horizontal]': 'horizontal()',\n '[contentOffset]': 'contentOffset()',\n '[maintainVisibleContentPosition]': 'maintainVisibleContentPosition()',\n '[scrollEventThrottle]': 'resolvedThrottle()',\n '[nestedScrollEnabled]': 'resolvedNestedScroll()',\n },\n})\nexport class ScrollView extends ScrollViewProps {\n /** Styles for the view that holds the children, e.g. padding and gap. */\n readonly contentContainerStyle = input<Record<string, unknown>>();\n\n /**\n * The content view's style, with the row direction a horizontal scroll view needs.\n *\n * RN's `contentContainerHorizontal`, and in the same order: the caller's own style is applied\n * over it, so a horizontal scroll view whose content really should stack in a column can still\n * say so.\n */\n protected readonly contentStyle = computed(() =>\n this.horizontal()\n ? { flexDirection: 'row', ...this.contentContainerStyle() }\n : this.contentContainerStyle(),\n );\n /** Lay children out in a row and scroll sideways. */\n readonly horizontal = input(undefined, { transform: optionalBoolean });\n /** Where the content starts, before the user scrolls. */\n readonly contentOffset = input<Point>();\n /** Keep what is on screen still when content is added above it. */\n readonly maintainVisibleContentPosition = input<{\n readonly minIndexForVisible: number;\n readonly autoscrollToTopThreshold?: number;\n }>();\n /** What a tap does with the keyboard up. See the class note. Defaults to `never`. */\n readonly keyboardShouldPersistTaps = input<KeyboardShouldPersistTaps>('never');\n /** Android: cooperate with a scrolling ancestor. */\n readonly nestedScrollEnabled = input(undefined, { transform: optionalBoolean });\n\n /** Children of the content, by position, that stick to the leading edge while it scrolls. */\n readonly stickyHeaderIndices = input<readonly number[]>([]);\n\n /** The content view's size changed; the value is its new width and height. */\n readonly contentSizeChange = output<Size>();\n\n private readonly refreshControl = contentChild(RefreshControl);\n private readonly content = viewChild.required('content', { read: ElementRef });\n private readonly sticky = new StickyHeaders(this.engine, this.node, () => !!this.horizontal());\n\n /** RN asks for every scroll event while anything is sticky, which is what keeps it pinned. */\n protected readonly resolvedThrottle = computed(() =>\n this.stickyHeaderIndices().length > 0 ? 1 : this.scrollEventThrottle(),\n );\n\n /**\n * RN's `nestedScrollEnabled ?? true` for a scroll view inside Android's swipe layout: the scroll\n * view has to see a drag before the layout wrapped around it does, or every drag is a pull.\n */\n protected readonly resolvedNestedScroll = computed(\n () =>\n this.nestedScrollEnabled() ??\n (nativePlatform() === 'android' && this.refreshControl() ? true : undefined),\n );\n\n constructor() {\n super();\n const stop = dismissKeyboardOnTap(this.engine, this.node, () =>\n this.keyboardShouldPersistTaps(),\n );\n inject(DestroyRef).onDestroy(stop);\n this.trackStickyHeaders();\n }\n\n /**\n * Sticky children are found again after each pass, because a pass can add or move them, and the\n * scroll offset is listened for only while there are any.\n */\n private trackStickyHeaders(): void {\n let stopScroll: (() => void) | null = null;\n afterEveryRender(() => {\n const indices = this.stickyHeaderIndices();\n if (indices.length === 0 && !stopScroll) return;\n this.sticky.track(this.content().nativeElement as HostNode, indices);\n if (indices.length > 0 && !stopScroll) {\n stopScroll = this.engine.setEventListener(this.node, 'topScroll', (event) => {\n const offset = (event as NativeSyntheticEvent<{ contentOffset?: Point }>).nativeEvent\n ?.contentOffset;\n this.sticky.scrolled((this.horizontal() ? offset?.x : offset?.y) ?? 0);\n });\n } else if (indices.length === 0 && stopScroll) {\n stopScroll();\n stopScroll = null;\n }\n });\n inject(DestroyRef).onDestroy(() => {\n stopScroll?.();\n this.sticky.destroy();\n });\n }\n\n /** Scroll to a position. */\n scrollTo(options: { x?: number; y?: number; animated?: boolean }): void {\n const { x = 0, y = 0, animated = true } = options;\n this.engine.dispatchCommand(this.node, 'scrollTo', [x, y, animated]);\n }\n\n scrollToEnd(options: { animated?: boolean } = {}): void {\n this.engine.dispatchCommand(this.node, 'scrollToEnd', [options.animated ?? true]);\n }\n\n /** Briefly show the scroll indicators, to hint that there is more. */\n flashScrollIndicators(): void {\n this.engine.dispatchCommand(this.node, 'flashScrollIndicators');\n }\n\n /** iOS: zoom so that a rectangle of the content fills the viewport. */\n zoomToRect(rect: Rect, animated = true): void {\n this.engine.dispatchCommand(this.node, 'zoomToRect', [rect, animated]);\n }\n\n protected onContentLayout(event: NativeSyntheticEvent<{ layout?: Size }>): void {\n const layout = event.nativeEvent?.layout;\n if (layout) this.contentSizeChange.emit({ width: layout.width, height: layout.height });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"scroll-view.js","sourceRoot":"","sources":["../src/scroll-view.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n DestroyRef,\n ElementRef,\n afterEveryRender,\n computed,\n contentChild,\n inject,\n input,\n output,\n viewChild,\n} from '@angular/core';\nimport { type HostNode, type NativeSyntheticEvent, nativePlatform } from '@ng-native/fabric';\nimport type { Point, Rect, Size } from './events.ts';\nimport { type KeyboardShouldPersistTaps, dismissKeyboardOnTap } from './keyboard-taps.ts';\nimport { ContentContainer } from './content-container.ts';\nimport { RefreshControl } from './refresh-control.ts';\nimport { StickyHeaders } from './sticky-headers.ts';\nimport { optionalBoolean } from './transforms.ts';\nimport { ScrollViewProps } from './scroll-view-props.ts';\nimport { View } from './view.ts';\nimport { ZeroSizeWarning, checksZeroSize, written } from './zero-size-warning.ts';\n\n/**\n * A scrolling container. Commits as `RCTScrollView`, with the children inside a content view.\n *\n * The native scroll view has no `contentContainerStyle`: RN's `ScrollView.js` wraps children in\n * a content view and applies it there, which is done here. The engine gives the host RN's base\n * style (`overflow: 'scroll'` and the flex defaults); without it the content spills out of the\n * scroll view's bounds.\n *\n * `horizontal` changes two things rather than one, and both are needed. RN swaps its whole base\n * style for `baseHorizontal` - the same defaults but `flexDirection: 'row'` - and puts\n * `contentContainerHorizontal` on the content view. With the host left as a column the content\n * view is stretched to the scroll view's width instead of growing past it, so there is nothing to\n * scroll to and a sideways drag does nothing at all. It looks like a scroll view that simply has\n * too little in it.\n *\n * Keyboard policy is the other half of what `ScrollView.js` does in JavaScript. With a text\n * input focused, a tap elsewhere in the scroll view dismisses the keyboard and goes no further\n * (`keyboardShouldPersistTaps: 'never'`, the default), reaches the child first and dismisses only\n * if nothing handled it (`'handled'`), or never dismisses (`'always'`).\n *\n * `stickyHeaderIndices` pins those children of the content to the leading edge, each until the\n * next pushes it off. It is JavaScript in RN as well; see `StickyHeaders`.\n *\n * Events are element events: `(scroll)`, `(scrollBeginDrag)`, `(scrollEndDrag)`,\n * `(momentumScrollBegin)`, `(momentumScrollEnd)`, `(scrollToTop)`. `(contentSizeChange)` is an\n * output, measured from the content view's layout as RN does.\n */\n@Component({\n selector: 'scroll-view',\n exportAs: 'scrollView',\n imports: [ContentContainer, View],\n // `collapsable: false` is load-bearing, not a hint. Fabric flattens views whose props are\n // layout-only, and a content container with just padding qualifies: it gets no UIView at all.\n // Touches in its empty areas then land on the scroll view itself, which does not scroll from a\n // direct hit, so dragging anywhere the children do not cover silently does nothing. RN sets the\n // same flag on its content container for the same reason.\n //\n // A refresh control is the scroll view's own child, before the content view, as RN's\n // ScrollView.js commits it. On iOS it finds its scroll view once, when it is inserted, and\n // Fabric mounts bottom-up: inside the content view it would look before that view was in the\n // scroll view, and never attach.\n template: `\n <ng-content select=\"refresh-control\" />\n <view\n #content\n [contentContainerOf]=\"node\"\n [contentContainerClass]=\"contentContainerClass()\"\n [style]=\"contentStyle()\"\n collapsable=\"false\"\n (layout)=\"onContentLayout($event)\"\n >\n <ng-content />\n </view>\n `,\n host: {\n // The base style's direction, which `horizontal` decides. A top-level prop rather than a\n // host `[style]`, so the caller's own `[style]` still applies over it as it does in RN.\n '[flexDirection]': \"horizontal() ? 'row' : 'column'\",\n '[horizontal]': 'horizontal()',\n '[contentOffset]': 'contentOffset()',\n '[maintainVisibleContentPosition]': 'maintainVisibleContentPosition()',\n '[scrollEventThrottle]': 'resolvedThrottle()',\n '[nestedScrollEnabled]': 'resolvedNestedScroll()',\n },\n})\nexport class ScrollView extends ScrollViewProps {\n /** Styles for the view that holds the children, e.g. padding and gap. */\n readonly contentContainerStyle = input<Record<string, unknown>>();\n /**\n * Classes for the view that holds the children, matched as if the view were written in the\n * template the scroll view is. See `ContentContainer`. `contentContainerStyle` wins over it, as\n * an inline style does over a class.\n */\n readonly contentContainerClass = input<string>();\n\n /**\n * The content view's style, with the row direction a horizontal scroll view needs.\n *\n * RN's `contentContainerHorizontal`, and in the same order: the caller's own style is applied\n * over it, so a horizontal scroll view whose content really should stack in a column can still\n * say so.\n */\n protected readonly contentStyle = computed(() =>\n this.horizontal()\n ? { flexDirection: 'row', ...this.contentContainerStyle() }\n : this.contentContainerStyle(),\n );\n /** Lay children out in a row and scroll sideways. */\n readonly horizontal = input(undefined, { transform: optionalBoolean });\n /** Where the content starts, before the user scrolls. */\n readonly contentOffset = input<Point>();\n /** Keep what is on screen still when content is added above it. */\n readonly maintainVisibleContentPosition = input<{\n readonly minIndexForVisible: number;\n readonly autoscrollToTopThreshold?: number;\n }>();\n /** What a tap does with the keyboard up. See the class note. Defaults to `never`. */\n readonly keyboardShouldPersistTaps = input<KeyboardShouldPersistTaps>('never');\n /** Android: cooperate with a scrolling ancestor. */\n readonly nestedScrollEnabled = input(undefined, { transform: optionalBoolean });\n\n /** Children of the content, by position, that stick to the leading edge while it scrolls. */\n readonly stickyHeaderIndices = input<readonly number[]>([]);\n\n /** The content view's size changed; the value is its new width and height. */\n readonly contentSizeChange = output<Size>();\n\n private readonly refreshControl = contentChild(RefreshControl);\n private readonly content = viewChild.required('content', { read: ElementRef });\n private readonly sticky = new StickyHeaders(this.engine, this.node, () => !!this.horizontal());\n\n /** RN asks for every scroll event while anything is sticky, which is what keeps it pinned. */\n protected readonly resolvedThrottle = computed(() =>\n this.stickyHeaderIndices().length > 0 ? 1 : this.scrollEventThrottle(),\n );\n\n /**\n * RN's `nestedScrollEnabled ?? true` for a scroll view inside Android's swipe layout: the scroll\n * view has to see a drag before the layout wrapped around it does, or every drag is a pull.\n */\n protected readonly resolvedNestedScroll = computed(\n () =>\n this.nestedScrollEnabled() ??\n (nativePlatform() === 'android' && this.refreshControl() ? true : undefined),\n );\n\n constructor() {\n super();\n const stop = dismissKeyboardOnTap(this.engine, this.node, () =>\n this.keyboardShouldPersistTaps(),\n );\n inject(DestroyRef).onDestroy(stop);\n this.trackStickyHeaders();\n if (checksZeroSize()) this.checkZeroSize();\n }\n\n /** The content's extent along the axis, and the scroll view's own, for `checkZeroSize`. */\n private contentExtent = 0;\n private ownExtent: number | undefined;\n private zeroSize: ZeroSizeWarning | null = null;\n\n /**\n * In development only, the scroll view's own layout, to say when it stays at zero size with\n * content in it. A release build listens for nothing, so it commits no `onLayout`.\n */\n private checkZeroSize(): void {\n const warning = (this.zeroSize = new ZeroSizeWarning(\n () => written(this.node),\n () => !!this.horizontal(),\n ));\n const stop = this.engine.setEventListener(this.node, 'topLayout', (event) => {\n this.ownExtent = this.extent(\n (event as NativeSyntheticEvent<{ layout?: Size }>).nativeEvent?.layout,\n );\n warning.laidOut(this.ownExtent, this.contentExtent > 0);\n });\n inject(DestroyRef).onDestroy(() => {\n stop();\n warning.stop();\n });\n }\n\n private extent(size: Size | undefined): number {\n return (this.horizontal() ? size?.width : size?.height) ?? 0;\n }\n\n /**\n * Sticky children are found again after each pass, because a pass can add or move them, and the\n * scroll offset is listened for only while there are any.\n */\n private trackStickyHeaders(): void {\n let stopScroll: (() => void) | null = null;\n afterEveryRender(() => {\n const indices = this.stickyHeaderIndices();\n if (indices.length === 0 && !stopScroll) return;\n this.sticky.track(this.content().nativeElement as HostNode, indices);\n if (indices.length > 0 && !stopScroll) {\n stopScroll = this.engine.setEventListener(this.node, 'topScroll', (event) => {\n const offset = (event as NativeSyntheticEvent<{ contentOffset?: Point }>).nativeEvent\n ?.contentOffset;\n this.sticky.scrolled((this.horizontal() ? offset?.x : offset?.y) ?? 0);\n });\n } else if (indices.length === 0 && stopScroll) {\n stopScroll();\n stopScroll = null;\n }\n });\n inject(DestroyRef).onDestroy(() => {\n stopScroll?.();\n this.sticky.destroy();\n });\n }\n\n /** Scroll to a position. */\n scrollTo(options: { x?: number; y?: number; animated?: boolean }): void {\n const { x = 0, y = 0, animated = true } = options;\n this.engine.dispatchCommand(this.node, 'scrollTo', [x, y, animated]);\n }\n\n scrollToEnd(options: { animated?: boolean } = {}): void {\n this.engine.dispatchCommand(this.node, 'scrollToEnd', [options.animated ?? true]);\n }\n\n /** Briefly show the scroll indicators, to hint that there is more. */\n flashScrollIndicators(): void {\n this.engine.dispatchCommand(this.node, 'flashScrollIndicators');\n }\n\n /** iOS: zoom so that a rectangle of the content fills the viewport. */\n zoomToRect(rect: Rect, animated = true): void {\n this.engine.dispatchCommand(this.node, 'zoomToRect', [rect, animated]);\n }\n\n protected onContentLayout(event: NativeSyntheticEvent<{ layout?: Size }>): void {\n const layout = event.nativeEvent?.layout;\n if (layout) this.contentSizeChange.emit({ width: layout.width, height: layout.height });\n if (this.zeroSize) {\n this.contentExtent = this.extent(layout);\n if (this.ownExtent !== undefined) {\n this.zeroSize.laidOut(this.ownExtent, this.contentExtent > 0);\n }\n }\n }\n}\n"]}
|
package/dist/section-list.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { TemplateRef } from '@angular/core';
|
|
2
|
+
import type { KeyboardShouldPersistTaps } from './keyboard-taps.ts';
|
|
3
|
+
import { type VirtualListPadding } from './virtual-list.ts';
|
|
2
4
|
import * as i0 from "@angular/core";
|
|
3
5
|
/** A section as RN's SectionList takes it: its rows in `data`, plus whatever else it carries. */
|
|
4
6
|
export interface SectionListSection<T> {
|
|
@@ -132,8 +134,14 @@ type Height<A extends unknown[]> = number | ((...args: A) => number);
|
|
|
132
134
|
* It defaults to on for iOS and off for Android, as RN's does. `listHeader` and `listFooter`
|
|
133
135
|
* content and a `<refresh-control>` pass through to the list.
|
|
134
136
|
*
|
|
137
|
+
* `contentPadding` and `keyboardShouldPersistTaps` pass through to the list as `<virtual-list>`
|
|
138
|
+
* takes them.
|
|
139
|
+
*
|
|
135
140
|
* ponytail: no `horizontal` or `inverted`, no viewability events, and no `highlighted` on a
|
|
136
|
-
* separator.
|
|
141
|
+
* separator. No `keyExtractor` or `maintainVisibleContentPosition` either: rows are fixed height,
|
|
142
|
+
* so there is no measured height for a key to carry across an insert. The host is a plain view
|
|
143
|
+
* with the list filling it, where RN's host is the scroll view, so scroll-view props are not
|
|
144
|
+
* taken.
|
|
137
145
|
*/
|
|
138
146
|
export declare class SectionList<T, S extends SectionListSection<T> = SectionListSection<T>> {
|
|
139
147
|
readonly sections: import("@angular/core").InputSignal<readonly S[]>;
|
|
@@ -145,6 +153,10 @@ export declare class SectionList<T, S extends SectionListSection<T> = SectionLis
|
|
|
145
153
|
readonly stickySectionHeadersEnabled: import("@angular/core").InputSignalWithTransform<boolean | undefined, unknown>;
|
|
146
154
|
readonly overscan: import("@angular/core").InputSignalWithTransform<number, unknown>;
|
|
147
155
|
readonly endReachedThreshold: import("@angular/core").InputSignalWithTransform<number, unknown>;
|
|
156
|
+
/** Space around the rows, inside the scrolling content. See `<virtual-list>`. */
|
|
157
|
+
readonly contentPadding: import("@angular/core").InputSignal<VirtualListPadding>;
|
|
158
|
+
/** What a tap in the list does while a text input has the keyboard up. See `ScrollView`. */
|
|
159
|
+
readonly keyboardShouldPersistTaps: import("@angular/core").InputSignal<KeyboardShouldPersistTaps>;
|
|
148
160
|
/** The end of the last section is within `endReachedThreshold`. See `<virtual-list>`. */
|
|
149
161
|
readonly endReached: import("@angular/core").OutputEmitterRef<{
|
|
150
162
|
distanceFromEnd: number;
|
|
@@ -178,6 +190,6 @@ export declare class SectionList<T, S extends SectionListSection<T> = SectionLis
|
|
|
178
190
|
animated?: boolean;
|
|
179
191
|
}): void;
|
|
180
192
|
static ɵfac: i0.ɵɵFactoryDeclaration<SectionList<any, any>, never>;
|
|
181
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<SectionList<any, any>, "section-list", ["sectionList"], { "sections": { "alias": "sections"; "required": true; "isSignal": true; }; "itemHeight": { "alias": "itemHeight"; "required": true; "isSignal": true; }; "sectionHeaderHeight": { "alias": "sectionHeaderHeight"; "required": false; "isSignal": true; }; "sectionFooterHeight": { "alias": "sectionFooterHeight"; "required": false; "isSignal": true; }; "stickySectionHeadersEnabled": { "alias": "stickySectionHeadersEnabled"; "required": false; "isSignal": true; }; "overscan": { "alias": "overscan"; "required": false; "isSignal": true; }; "endReachedThreshold": { "alias": "endReachedThreshold"; "required": false; "isSignal": true; }; }, { "endReached": "endReached"; }, ["header", "footer", "item", "separator", "edge"], ["refresh-control", "[listHeader]", "*", "[listFooter]"], true, never>;
|
|
193
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<SectionList<any, any>, "section-list", ["sectionList"], { "sections": { "alias": "sections"; "required": true; "isSignal": true; }; "itemHeight": { "alias": "itemHeight"; "required": true; "isSignal": true; }; "sectionHeaderHeight": { "alias": "sectionHeaderHeight"; "required": false; "isSignal": true; }; "sectionFooterHeight": { "alias": "sectionFooterHeight"; "required": false; "isSignal": true; }; "stickySectionHeadersEnabled": { "alias": "stickySectionHeadersEnabled"; "required": false; "isSignal": true; }; "overscan": { "alias": "overscan"; "required": false; "isSignal": true; }; "endReachedThreshold": { "alias": "endReachedThreshold"; "required": false; "isSignal": true; }; "contentPadding": { "alias": "contentPadding"; "required": false; "isSignal": true; }; "keyboardShouldPersistTaps": { "alias": "keyboardShouldPersistTaps"; "required": false; "isSignal": true; }; }, { "endReached": "endReached"; }, ["header", "footer", "item", "separator", "edge"], ["refresh-control", "[listHeader]", "*", "[listFooter]"], true, never>;
|
|
182
194
|
}
|
|
183
195
|
export {};
|
package/dist/section-list.js
CHANGED
|
@@ -140,8 +140,14 @@ const measure = (height, ...args) => typeof height === 'number' ? height : heigh
|
|
|
140
140
|
* It defaults to on for iOS and off for Android, as RN's does. `listHeader` and `listFooter`
|
|
141
141
|
* content and a `<refresh-control>` pass through to the list.
|
|
142
142
|
*
|
|
143
|
+
* `contentPadding` and `keyboardShouldPersistTaps` pass through to the list as `<virtual-list>`
|
|
144
|
+
* takes them.
|
|
145
|
+
*
|
|
143
146
|
* ponytail: no `horizontal` or `inverted`, no viewability events, and no `highlighted` on a
|
|
144
|
-
* separator.
|
|
147
|
+
* separator. No `keyExtractor` or `maintainVisibleContentPosition` either: rows are fixed height,
|
|
148
|
+
* so there is no measured height for a key to carry across an insert. The host is a plain view
|
|
149
|
+
* with the list filling it, where RN's host is the scroll view, so scroll-view props are not
|
|
150
|
+
* taken.
|
|
145
151
|
*/
|
|
146
152
|
export class SectionList {
|
|
147
153
|
sections = input.required(/* @ts-ignore */
|
|
@@ -157,6 +163,12 @@ export class SectionList {
|
|
|
157
163
|
stickySectionHeadersEnabled = input(undefined, { ...(ngDevMode ? { debugName: "stickySectionHeadersEnabled" } : /* istanbul ignore next */ {}), transform: optionalBoolean });
|
|
158
164
|
overscan = input(4, { ...(ngDevMode ? { debugName: "overscan" } : /* istanbul ignore next */ {}), transform: numberAttribute });
|
|
159
165
|
endReachedThreshold = input(2, { ...(ngDevMode ? { debugName: "endReachedThreshold" } : /* istanbul ignore next */ {}), transform: numberAttribute });
|
|
166
|
+
/** Space around the rows, inside the scrolling content. See `<virtual-list>`. */
|
|
167
|
+
contentPadding = input(0, /* @ts-ignore */
|
|
168
|
+
...(ngDevMode ? [{ debugName: "contentPadding" }] : /* istanbul ignore next */ []));
|
|
169
|
+
/** What a tap in the list does while a text input has the keyboard up. See `ScrollView`. */
|
|
170
|
+
keyboardShouldPersistTaps = input('never', /* @ts-ignore */
|
|
171
|
+
...(ngDevMode ? [{ debugName: "keyboardShouldPersistTaps" }] : /* istanbul ignore next */ []));
|
|
160
172
|
/** The end of the last section is within `endReachedThreshold`. See `<virtual-list>`. */
|
|
161
173
|
endReached = output();
|
|
162
174
|
header = contentChild(SectionHeader, /* @ts-ignore */
|
|
@@ -216,7 +228,7 @@ export class SectionList {
|
|
|
216
228
|
this.list().scrollToIndex({ index, viewOffset, animated: options.animated });
|
|
217
229
|
}
|
|
218
230
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: SectionList, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
219
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.2.0", type: SectionList, isStandalone: true, selector: "section-list", inputs: { sections: { classPropertyName: "sections", publicName: "sections", isSignal: true, isRequired: true, transformFunction: null }, itemHeight: { classPropertyName: "itemHeight", publicName: "itemHeight", isSignal: true, isRequired: true, transformFunction: null }, sectionHeaderHeight: { classPropertyName: "sectionHeaderHeight", publicName: "sectionHeaderHeight", isSignal: true, isRequired: false, transformFunction: null }, sectionFooterHeight: { classPropertyName: "sectionFooterHeight", publicName: "sectionFooterHeight", isSignal: true, isRequired: false, transformFunction: null }, stickySectionHeadersEnabled: { classPropertyName: "stickySectionHeadersEnabled", publicName: "stickySectionHeadersEnabled", isSignal: true, isRequired: false, transformFunction: null }, overscan: { classPropertyName: "overscan", publicName: "overscan", isSignal: true, isRequired: false, transformFunction: null }, endReachedThreshold: { classPropertyName: "endReachedThreshold", publicName: "endReachedThreshold", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { endReached: "endReached" }, queries: [{ propertyName: "header", first: true, predicate: SectionHeader, descendants: true, isSignal: true }, { propertyName: "footer", first: true, predicate: SectionFooter, descendants: true, isSignal: true }, { propertyName: "item", first: true, predicate: SectionItem, descendants: true, isSignal: true }, { propertyName: "separator", first: true, predicate: SectionSeparator, descendants: true, isSignal: true }, { propertyName: "edge", first: true, predicate: SectionEdgeSeparator, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "list", first: true, predicate: ["list"], descendants: true, isSignal: true }], exportAs: ["sectionList"], ngImport: i0, template: `
|
|
231
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.2.0", type: SectionList, isStandalone: true, selector: "section-list", inputs: { sections: { classPropertyName: "sections", publicName: "sections", isSignal: true, isRequired: true, transformFunction: null }, itemHeight: { classPropertyName: "itemHeight", publicName: "itemHeight", isSignal: true, isRequired: true, transformFunction: null }, sectionHeaderHeight: { classPropertyName: "sectionHeaderHeight", publicName: "sectionHeaderHeight", isSignal: true, isRequired: false, transformFunction: null }, sectionFooterHeight: { classPropertyName: "sectionFooterHeight", publicName: "sectionFooterHeight", isSignal: true, isRequired: false, transformFunction: null }, stickySectionHeadersEnabled: { classPropertyName: "stickySectionHeadersEnabled", publicName: "stickySectionHeadersEnabled", isSignal: true, isRequired: false, transformFunction: null }, overscan: { classPropertyName: "overscan", publicName: "overscan", isSignal: true, isRequired: false, transformFunction: null }, endReachedThreshold: { classPropertyName: "endReachedThreshold", publicName: "endReachedThreshold", isSignal: true, isRequired: false, transformFunction: null }, contentPadding: { classPropertyName: "contentPadding", publicName: "contentPadding", isSignal: true, isRequired: false, transformFunction: null }, keyboardShouldPersistTaps: { classPropertyName: "keyboardShouldPersistTaps", publicName: "keyboardShouldPersistTaps", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { endReached: "endReached" }, queries: [{ propertyName: "header", first: true, predicate: SectionHeader, descendants: true, isSignal: true }, { propertyName: "footer", first: true, predicate: SectionFooter, descendants: true, isSignal: true }, { propertyName: "item", first: true, predicate: SectionItem, descendants: true, isSignal: true }, { propertyName: "separator", first: true, predicate: SectionSeparator, descendants: true, isSignal: true }, { propertyName: "edge", first: true, predicate: SectionEdgeSeparator, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "list", first: true, predicate: ["list"], descendants: true, isSignal: true }], exportAs: ["sectionList"], ngImport: i0, template: `
|
|
220
232
|
<virtual-list
|
|
221
233
|
#list
|
|
222
234
|
[items]="rows()"
|
|
@@ -224,6 +236,8 @@ export class SectionList {
|
|
|
224
236
|
[stickyIndices]="stickyRows()"
|
|
225
237
|
[overscan]="overscan()"
|
|
226
238
|
[endReachedThreshold]="endReachedThreshold()"
|
|
239
|
+
[contentPadding]="contentPadding()"
|
|
240
|
+
[keyboardShouldPersistTaps]="keyboardShouldPersistTaps()"
|
|
227
241
|
[style]="fill"
|
|
228
242
|
(endReached)="endReached.emit($event)"
|
|
229
243
|
>
|
|
@@ -279,7 +293,7 @@ export class SectionList {
|
|
|
279
293
|
}
|
|
280
294
|
<view listFooter><ng-content select="[listFooter]" /></view>
|
|
281
295
|
</virtual-list>
|
|
282
|
-
`, isInline: true, dependencies: [{ kind: "directive", type: TemplateSlot, selector: "[templateSlot]", inputs: ["templateSlot", "templateSlotContext"] }, { kind: "directive", type: View, selector: "view" }, { kind: "component", type: VirtualList, selector: "virtual-list", inputs: ["items", "itemHeight", "estimatedItemHeight", "keyExtractor", "itemType", "maintainVisibleContentPosition", "overscan", "endReachedThreshold", "horizontal", "inverted", "stickyIndices", "stickyHeader", "keyboardShouldPersistTaps", "itemVisiblePercentThreshold"], outputs: ["endReached", "viewableItemsChanged"], exportAs: ["virtualList"] }] });
|
|
296
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: TemplateSlot, selector: "[templateSlot]", inputs: ["templateSlot", "templateSlotContext"] }, { kind: "directive", type: View, selector: "view" }, { kind: "component", type: VirtualList, selector: "virtual-list", inputs: ["items", "itemHeight", "estimatedItemHeight", "contentPadding", "rowGap", "keyExtractor", "itemType", "maintainVisibleContentPosition", "overscan", "endReachedThreshold", "horizontal", "inverted", "stickyIndices", "stickyHeader", "keyboardShouldPersistTaps", "itemVisiblePercentThreshold"], outputs: ["endReached", "viewableItemsChanged"], exportAs: ["virtualList"] }] });
|
|
283
297
|
}
|
|
284
298
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: SectionList, decorators: [{
|
|
285
299
|
type: Component,
|
|
@@ -295,6 +309,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImpor
|
|
|
295
309
|
[stickyIndices]="stickyRows()"
|
|
296
310
|
[overscan]="overscan()"
|
|
297
311
|
[endReachedThreshold]="endReachedThreshold()"
|
|
312
|
+
[contentPadding]="contentPadding()"
|
|
313
|
+
[keyboardShouldPersistTaps]="keyboardShouldPersistTaps()"
|
|
298
314
|
[style]="fill"
|
|
299
315
|
(endReached)="endReached.emit($event)"
|
|
300
316
|
>
|
|
@@ -352,5 +368,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImpor
|
|
|
352
368
|
</virtual-list>
|
|
353
369
|
`,
|
|
354
370
|
}]
|
|
355
|
-
}], propDecorators: { sections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sections", required: true }] }], itemHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemHeight", required: true }] }], sectionHeaderHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "sectionHeaderHeight", required: false }] }], sectionFooterHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "sectionFooterHeight", required: false }] }], stickySectionHeadersEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "stickySectionHeadersEnabled", required: false }] }], overscan: [{ type: i0.Input, args: [{ isSignal: true, alias: "overscan", required: false }] }], endReachedThreshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "endReachedThreshold", required: false }] }], endReached: [{ type: i0.Output, args: ["endReached"] }], header: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SectionHeader), { isSignal: true }] }], footer: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SectionFooter), { isSignal: true }] }], item: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SectionItem), { isSignal: true }] }], separator: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SectionSeparator), { isSignal: true }] }], edge: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SectionEdgeSeparator), { isSignal: true }] }], list: [{ type: i0.ViewChild, args: ['list', { isSignal: true }] }] } });
|
|
371
|
+
}], propDecorators: { sections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sections", required: true }] }], itemHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemHeight", required: true }] }], sectionHeaderHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "sectionHeaderHeight", required: false }] }], sectionFooterHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "sectionFooterHeight", required: false }] }], stickySectionHeadersEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "stickySectionHeadersEnabled", required: false }] }], overscan: [{ type: i0.Input, args: [{ isSignal: true, alias: "overscan", required: false }] }], endReachedThreshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "endReachedThreshold", required: false }] }], contentPadding: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentPadding", required: false }] }], keyboardShouldPersistTaps: [{ type: i0.Input, args: [{ isSignal: true, alias: "keyboardShouldPersistTaps", required: false }] }], endReached: [{ type: i0.Output, args: ["endReached"] }], header: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SectionHeader), { isSignal: true }] }], footer: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SectionFooter), { isSignal: true }] }], item: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SectionItem), { isSignal: true }] }], separator: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SectionSeparator), { isSignal: true }] }], edge: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SectionEdgeSeparator), { isSignal: true }] }], list: [{ type: i0.ViewChild, args: ['list', { isSignal: true }] }] } });
|
|
356
372
|
//# sourceMappingURL=section-list.js.map
|
package/dist/section-list.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"section-list.js","sourceRoot":"","sources":["../src/section-list.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Directive,\n TemplateRef,\n computed,\n contentChild,\n inject,\n input,\n numberAttribute,\n output,\n viewChild,\n} from '@angular/core';\nimport { nativePlatform } from '@ng-native/fabric';\nimport { TemplateSlot } from './template-slot.ts';\nimport { optionalBoolean } from './transforms.ts';\nimport { View } from './view.ts';\nimport { VirtualList } from './virtual-list.ts';\n\n/** A section as RN's SectionList takes it: its rows in `data`, plus whatever else it carries. */\nexport interface SectionListSection<T> {\n readonly key?: string;\n readonly title?: string;\n readonly data: readonly T[];\n}\n\n/** What a section header or footer template is given. */\nexport interface SectionContext<S> {\n readonly $implicit: S;\n readonly section: S;\n readonly sectionIndex: number;\n}\n\n/** What an item template is given. `index` counts within the section, as `renderItem` does. */\nexport interface SectionItemContext<T, S> {\n readonly $implicit: T;\n readonly item: T;\n readonly index: number;\n readonly section: S;\n readonly sectionIndex: number;\n}\n\n/** What a separator template is given: the items either side of it, in the same section. */\nexport interface SectionSeparatorContext<T, S> {\n readonly $implicit: T;\n readonly leadingItem: T;\n readonly trailingItem: T;\n readonly section: S;\n}\n\n/**\n * What a section separator template is given: the section, and what is either side of the edge\n * it sits at. At a section's start `leadingItem` is undefined, and at its end `trailingItem` is.\n */\nexport interface SectionEdgeSeparatorContext<T, S> {\n readonly $implicit: S;\n readonly section: S;\n readonly leadingItem: T | undefined;\n readonly leadingSection: S | undefined;\n readonly trailingItem: T | undefined;\n readonly trailingSection: S | undefined;\n}\n\n/** `<ng-template sectionHeader let-section>`: RN's `renderSectionHeader`. */\n@Directive({ selector: 'ng-template[sectionHeader]' })\nexport class SectionHeader<S = unknown> {\n readonly template = inject<TemplateRef<SectionContext<S>>>(TemplateRef);\n\n static ngTemplateContextGuard<S>(\n _directive: SectionHeader<S>,\n context: unknown,\n ): context is SectionContext<S> {\n return true;\n }\n}\n\n/** `<ng-template sectionFooter let-section>`: RN's `renderSectionFooter`. */\n@Directive({ selector: 'ng-template[sectionFooter]' })\nexport class SectionFooter<S = unknown> {\n readonly template = inject<TemplateRef<SectionContext<S>>>(TemplateRef);\n\n static ngTemplateContextGuard<S>(\n _directive: SectionFooter<S>,\n context: unknown,\n ): context is SectionContext<S> {\n return true;\n }\n}\n\n/** `<ng-template sectionItem let-item let-index=\"index\">`: RN's `renderItem`. */\n@Directive({ selector: 'ng-template[sectionItem]' })\nexport class SectionItem<T = unknown, S = unknown> {\n readonly template = inject<TemplateRef<SectionItemContext<T, S>>>(TemplateRef);\n\n static ngTemplateContextGuard<T, S>(\n _directive: SectionItem<T, S>,\n context: unknown,\n ): context is SectionItemContext<T, S> {\n return true;\n }\n}\n\n/** `<ng-template sectionSeparator let-leading>`: RN's `ItemSeparatorComponent`. */\n@Directive({ selector: 'ng-template[sectionSeparator]' })\nexport class SectionSeparator<T = unknown, S = unknown> {\n readonly template = inject<TemplateRef<SectionSeparatorContext<T, S>>>(TemplateRef);\n\n static ngTemplateContextGuard<T, S>(\n _directive: SectionSeparator<T, S>,\n context: unknown,\n ): context is SectionSeparatorContext<T, S> {\n return true;\n }\n}\n\n/**\n * `<ng-template sectionEdgeSeparator let-section>`: RN's `SectionSeparatorComponent`, drawn at\n * both edges of a section that has items, between its header and first item and between its\n * last item and footer.\n */\n@Directive({ selector: 'ng-template[sectionEdgeSeparator]' })\nexport class SectionEdgeSeparator<T = unknown, S = unknown> {\n readonly template = inject<TemplateRef<SectionEdgeSeparatorContext<T, S>>>(TemplateRef);\n\n static ngTemplateContextGuard<T, S>(\n _directive: SectionEdgeSeparator<T, S>,\n context: unknown,\n ): context is SectionEdgeSeparatorContext<T, S> {\n return true;\n }\n}\n\n/** One row of the flattened list. */\nexport type SectionRow<T, S> =\n | {\n readonly kind: 'header' | 'footer';\n readonly context: SectionContext<S>;\n readonly separator: null;\n readonly leading: null;\n readonly trailing: null;\n }\n | {\n readonly kind: 'item';\n readonly context: SectionItemContext<T, S>;\n /** Null for a section's last item, where the section separator takes its place, as in RN. */\n readonly separator: SectionSeparatorContext<T, S> | null;\n /** The section separator before a section's first item, and null on every other. */\n readonly leading: SectionEdgeSeparatorContext<T, S> | null;\n /** The section separator after a section's last item, and null on every other. */\n readonly trailing: SectionEdgeSeparatorContext<T, S> | null;\n };\n\n/**\n * Flatten sections into the rows RN's `VirtualizedSectionList` gives its list: for each section a\n * header, its items, then a footer. The header and footer rows are there whether or not anything\n * is drawn in them, as in RN, which is what keeps `scrollToLocation`'s arithmetic the same.\n *\n * The section separators ride on the first and last item, as RN's do: `SectionSeparatorComponent`\n * is the first item's leading separator and the last item's trailing one, so an empty section has\n * none, and a last item has it in place of the item separator.\n */\nexport function flattenSections<T, S extends SectionListSection<T>>(\n sections: readonly S[],\n): SectionRow<T, S>[] {\n const rows: SectionRow<T, S>[] = [];\n const edges = { leading: null, trailing: null };\n sections.forEach((section, sectionIndex) => {\n const context = { $implicit: section, section, sectionIndex };\n rows.push({ kind: 'header', context, separator: null, ...edges });\n const data = section.data;\n const last = data.length - 1;\n const around = {\n $implicit: section,\n section,\n leadingSection: sections[sectionIndex - 1],\n trailingSection: sections[sectionIndex + 1],\n };\n data.forEach((item, index) => {\n const trailingItem = data[index + 1];\n rows.push({\n kind: 'item',\n context: { $implicit: item, item, index, section, sectionIndex },\n separator:\n index < last\n ? { $implicit: item, leadingItem: item, trailingItem: trailingItem!, section }\n : null,\n leading: index === 0 ? { ...around, leadingItem: undefined, trailingItem: item } : null,\n trailing: index === last ? { ...around, leadingItem: item, trailingItem: undefined } : null,\n });\n });\n rows.push({ kind: 'footer', context, separator: null, ...edges });\n });\n return rows;\n}\n\ntype Height<A extends unknown[]> = number | ((...args: A) => number);\n\nconst measure = <A extends unknown[]>(height: Height<A>, ...args: A): number =>\n typeof height === 'number' ? height : height(...args);\n\n/**\n * RN's SectionList: sections of items, each with a header and footer, over `<virtual-list>`.\n *\n * RN's own is a VirtualizedList over flattened rows, and so is this. Sections become one list of\n * header, item and footer rows, the rows are placed by `<virtual-list>`'s variable-height windowing,\n * and this component draws each from the caller's templates:\n *\n * ```html\n * <section-list [sections]=\"sections\" [itemHeight]=\"44\" [sectionHeaderHeight]=\"28\">\n * <ng-template sectionHeader let-section><text>{{ section.title }}</text></ng-template>\n * <ng-template sectionItem let-item><text>{{ item }}</text></ng-template>\n * <ng-template sectionSeparator><view [style]=\"line\"></view></ng-template>\n * <ng-template sectionEdgeSeparator><view [style]=\"rule\"></view></ng-template>\n * </section-list>\n * ```\n *\n * Rows are fixed height, as `getItemLayout` makes them in RN: `itemHeight`, `sectionHeaderHeight`\n * and `sectionFooterHeight` are numbers or functions. An item's height includes its separators,\n * which are drawn in the item's slot: the item separator at its bottom, only between items of the\n * same section, and the section separator at the top of a section's first item and the bottom of\n * its last, as RN's `SectionSeparatorComponent` is.\n *\n * `stickySectionHeadersEnabled` pins the current section's header until the next pushes it off.\n * It defaults to on for iOS and off for Android, as RN's does. `listHeader` and `listFooter`\n * content and a `<refresh-control>` pass through to the list.\n *\n * ponytail: no `horizontal` or `inverted`, no viewability events, and no `highlighted` on a\n * separator. The host is a plain view with the list filling it, where RN's host is the scroll view.\n */\n@Component({\n selector: 'section-list',\n exportAs: 'sectionList',\n imports: [TemplateSlot, View, VirtualList],\n template: `\n <virtual-list\n #list\n [items]=\"rows()\"\n [itemHeight]=\"rowHeight\"\n [stickyIndices]=\"stickyRows()\"\n [overscan]=\"overscan()\"\n [endReachedThreshold]=\"endReachedThreshold()\"\n [style]=\"fill\"\n (endReached)=\"endReached.emit($event)\"\n >\n <ng-content select=\"refresh-control\" ngProjectAs=\"refresh-control\" />\n <view listHeader><ng-content select=\"[listHeader]\" /></view>\n <ng-content />\n @for (row of list.window(); track row.index) {\n <view [style]=\"row.style\">\n @switch (row.item.kind) {\n @case ('header') {\n @if (header(); as header) {\n <ng-container\n [templateSlot]=\"header.template\"\n [templateSlotContext]=\"row.item.context\"\n />\n }\n }\n @case ('footer') {\n @if (footer(); as footer) {\n <ng-container\n [templateSlot]=\"footer.template\"\n [templateSlotContext]=\"row.item.context\"\n />\n }\n }\n @case ('item') {\n @if (row.item.leading; as start) {\n @if (edge(); as edge) {\n <ng-container [templateSlot]=\"edge.template\" [templateSlotContext]=\"start\" />\n }\n }\n <view [style]=\"cell\">\n @if (item(); as item) {\n <ng-container\n [templateSlot]=\"item.template\"\n [templateSlotContext]=\"row.item.context\"\n />\n }\n </view>\n @if (separator(); as separator) {\n @if (row.item.separator; as gap) {\n <ng-container [templateSlot]=\"separator.template\" [templateSlotContext]=\"gap\" />\n }\n }\n @if (row.item.trailing; as end) {\n @if (edge(); as edge) {\n <ng-container [templateSlot]=\"edge.template\" [templateSlotContext]=\"end\" />\n }\n }\n }\n }\n </view>\n }\n <view listFooter><ng-content select=\"[listFooter]\" /></view>\n </virtual-list>\n `,\n})\nexport class SectionList<T, S extends SectionListSection<T> = SectionListSection<T>> {\n readonly sections = input.required<readonly S[]>();\n /** Each item's height, including every separator drawn in its slot. */\n readonly itemHeight = input.required<Height<[item: T, index: number, section: S]>>();\n readonly sectionHeaderHeight = input<Height<[section: S]>>(0);\n readonly sectionFooterHeight = input<Height<[section: S]>>(0);\n /** Pin the current section's header. Defaults to true on iOS and false on Android, as RN. */\n readonly stickySectionHeadersEnabled = input(undefined, { transform: optionalBoolean });\n readonly overscan = input(4, { transform: numberAttribute });\n readonly endReachedThreshold = input(2, { transform: numberAttribute });\n\n /** The end of the last section is within `endReachedThreshold`. See `<virtual-list>`. */\n readonly endReached = output<{ distanceFromEnd: number }>();\n\n protected readonly header = contentChild<SectionHeader<S>>(SectionHeader);\n protected readonly footer = contentChild<SectionFooter<S>>(SectionFooter);\n protected readonly item = contentChild<SectionItem<T, S>>(SectionItem);\n protected readonly separator = contentChild<SectionSeparator<T, S>>(SectionSeparator);\n protected readonly edge = contentChild<SectionEdgeSeparator<T, S>>(SectionEdgeSeparator);\n private readonly list = viewChild.required<VirtualList<SectionRow<T, S>>>('list');\n\n protected readonly fill = { flex: 1 };\n /** The item fills its slot between its separators, as RN's cell draws them around it. */\n protected readonly cell = { flex: 1 };\n\n protected readonly rows = computed(() => flattenSections<T, S>(this.sections()));\n\n private readonly sticky = computed(\n () => this.stickySectionHeadersEnabled() ?? nativePlatform() === 'ios',\n );\n\n /** The header rows, pinned in turn, when headers stick and there is a header to draw. */\n protected readonly stickyRows = computed(() => {\n if (!this.sticky() || !this.header()) return [];\n const indices: number[] = [];\n this.rows().forEach((row, index) => {\n if (row.kind === 'header') indices.push(index);\n });\n return indices;\n });\n\n protected readonly rowHeight = (row: SectionRow<T, S>): number => {\n const { section } = row.context;\n if (row.kind === 'item') {\n return measure(this.itemHeight(), row.context.item, row.context.index, section);\n }\n return row.kind === 'header'\n ? measure(this.sectionHeaderHeight(), section)\n : measure(this.sectionFooterHeight(), section);\n };\n\n /**\n * Scroll to an item, RN's way: `itemIndex` 0 is the section's header and 1 its first item, and\n * with sticky headers the header's height is allowed for so the item is not hidden under it.\n */\n scrollToLocation(options: {\n sectionIndex: number;\n itemIndex: number;\n viewOffset?: number;\n animated?: boolean;\n }): void {\n const sections = this.sections();\n let index = options.itemIndex;\n for (let i = 0; i < options.sectionIndex; i++) index += sections[i]!.data.length + 2;\n let viewOffset = options.viewOffset ?? 0;\n const section = sections[options.sectionIndex];\n if (options.itemIndex > 0 && this.sticky() && section) {\n viewOffset += measure(this.sectionHeaderHeight(), section);\n }\n this.list().scrollToIndex({ index, viewOffset, animated: options.animated });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"section-list.js","sourceRoot":"","sources":["../src/section-list.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Directive,\n TemplateRef,\n computed,\n contentChild,\n inject,\n input,\n numberAttribute,\n output,\n viewChild,\n} from '@angular/core';\nimport { nativePlatform } from '@ng-native/fabric';\nimport { TemplateSlot } from './template-slot.ts';\nimport { optionalBoolean } from './transforms.ts';\nimport { View } from './view.ts';\nimport type { KeyboardShouldPersistTaps } from './keyboard-taps.ts';\nimport { VirtualList, type VirtualListPadding } from './virtual-list.ts';\n\n/** A section as RN's SectionList takes it: its rows in `data`, plus whatever else it carries. */\nexport interface SectionListSection<T> {\n readonly key?: string;\n readonly title?: string;\n readonly data: readonly T[];\n}\n\n/** What a section header or footer template is given. */\nexport interface SectionContext<S> {\n readonly $implicit: S;\n readonly section: S;\n readonly sectionIndex: number;\n}\n\n/** What an item template is given. `index` counts within the section, as `renderItem` does. */\nexport interface SectionItemContext<T, S> {\n readonly $implicit: T;\n readonly item: T;\n readonly index: number;\n readonly section: S;\n readonly sectionIndex: number;\n}\n\n/** What a separator template is given: the items either side of it, in the same section. */\nexport interface SectionSeparatorContext<T, S> {\n readonly $implicit: T;\n readonly leadingItem: T;\n readonly trailingItem: T;\n readonly section: S;\n}\n\n/**\n * What a section separator template is given: the section, and what is either side of the edge\n * it sits at. At a section's start `leadingItem` is undefined, and at its end `trailingItem` is.\n */\nexport interface SectionEdgeSeparatorContext<T, S> {\n readonly $implicit: S;\n readonly section: S;\n readonly leadingItem: T | undefined;\n readonly leadingSection: S | undefined;\n readonly trailingItem: T | undefined;\n readonly trailingSection: S | undefined;\n}\n\n/** `<ng-template sectionHeader let-section>`: RN's `renderSectionHeader`. */\n@Directive({ selector: 'ng-template[sectionHeader]' })\nexport class SectionHeader<S = unknown> {\n readonly template = inject<TemplateRef<SectionContext<S>>>(TemplateRef);\n\n static ngTemplateContextGuard<S>(\n _directive: SectionHeader<S>,\n context: unknown,\n ): context is SectionContext<S> {\n return true;\n }\n}\n\n/** `<ng-template sectionFooter let-section>`: RN's `renderSectionFooter`. */\n@Directive({ selector: 'ng-template[sectionFooter]' })\nexport class SectionFooter<S = unknown> {\n readonly template = inject<TemplateRef<SectionContext<S>>>(TemplateRef);\n\n static ngTemplateContextGuard<S>(\n _directive: SectionFooter<S>,\n context: unknown,\n ): context is SectionContext<S> {\n return true;\n }\n}\n\n/** `<ng-template sectionItem let-item let-index=\"index\">`: RN's `renderItem`. */\n@Directive({ selector: 'ng-template[sectionItem]' })\nexport class SectionItem<T = unknown, S = unknown> {\n readonly template = inject<TemplateRef<SectionItemContext<T, S>>>(TemplateRef);\n\n static ngTemplateContextGuard<T, S>(\n _directive: SectionItem<T, S>,\n context: unknown,\n ): context is SectionItemContext<T, S> {\n return true;\n }\n}\n\n/** `<ng-template sectionSeparator let-leading>`: RN's `ItemSeparatorComponent`. */\n@Directive({ selector: 'ng-template[sectionSeparator]' })\nexport class SectionSeparator<T = unknown, S = unknown> {\n readonly template = inject<TemplateRef<SectionSeparatorContext<T, S>>>(TemplateRef);\n\n static ngTemplateContextGuard<T, S>(\n _directive: SectionSeparator<T, S>,\n context: unknown,\n ): context is SectionSeparatorContext<T, S> {\n return true;\n }\n}\n\n/**\n * `<ng-template sectionEdgeSeparator let-section>`: RN's `SectionSeparatorComponent`, drawn at\n * both edges of a section that has items, between its header and first item and between its\n * last item and footer.\n */\n@Directive({ selector: 'ng-template[sectionEdgeSeparator]' })\nexport class SectionEdgeSeparator<T = unknown, S = unknown> {\n readonly template = inject<TemplateRef<SectionEdgeSeparatorContext<T, S>>>(TemplateRef);\n\n static ngTemplateContextGuard<T, S>(\n _directive: SectionEdgeSeparator<T, S>,\n context: unknown,\n ): context is SectionEdgeSeparatorContext<T, S> {\n return true;\n }\n}\n\n/** One row of the flattened list. */\nexport type SectionRow<T, S> =\n | {\n readonly kind: 'header' | 'footer';\n readonly context: SectionContext<S>;\n readonly separator: null;\n readonly leading: null;\n readonly trailing: null;\n }\n | {\n readonly kind: 'item';\n readonly context: SectionItemContext<T, S>;\n /** Null for a section's last item, where the section separator takes its place, as in RN. */\n readonly separator: SectionSeparatorContext<T, S> | null;\n /** The section separator before a section's first item, and null on every other. */\n readonly leading: SectionEdgeSeparatorContext<T, S> | null;\n /** The section separator after a section's last item, and null on every other. */\n readonly trailing: SectionEdgeSeparatorContext<T, S> | null;\n };\n\n/**\n * Flatten sections into the rows RN's `VirtualizedSectionList` gives its list: for each section a\n * header, its items, then a footer. The header and footer rows are there whether or not anything\n * is drawn in them, as in RN, which is what keeps `scrollToLocation`'s arithmetic the same.\n *\n * The section separators ride on the first and last item, as RN's do: `SectionSeparatorComponent`\n * is the first item's leading separator and the last item's trailing one, so an empty section has\n * none, and a last item has it in place of the item separator.\n */\nexport function flattenSections<T, S extends SectionListSection<T>>(\n sections: readonly S[],\n): SectionRow<T, S>[] {\n const rows: SectionRow<T, S>[] = [];\n const edges = { leading: null, trailing: null };\n sections.forEach((section, sectionIndex) => {\n const context = { $implicit: section, section, sectionIndex };\n rows.push({ kind: 'header', context, separator: null, ...edges });\n const data = section.data;\n const last = data.length - 1;\n const around = {\n $implicit: section,\n section,\n leadingSection: sections[sectionIndex - 1],\n trailingSection: sections[sectionIndex + 1],\n };\n data.forEach((item, index) => {\n const trailingItem = data[index + 1];\n rows.push({\n kind: 'item',\n context: { $implicit: item, item, index, section, sectionIndex },\n separator:\n index < last\n ? { $implicit: item, leadingItem: item, trailingItem: trailingItem!, section }\n : null,\n leading: index === 0 ? { ...around, leadingItem: undefined, trailingItem: item } : null,\n trailing: index === last ? { ...around, leadingItem: item, trailingItem: undefined } : null,\n });\n });\n rows.push({ kind: 'footer', context, separator: null, ...edges });\n });\n return rows;\n}\n\ntype Height<A extends unknown[]> = number | ((...args: A) => number);\n\nconst measure = <A extends unknown[]>(height: Height<A>, ...args: A): number =>\n typeof height === 'number' ? height : height(...args);\n\n/**\n * RN's SectionList: sections of items, each with a header and footer, over `<virtual-list>`.\n *\n * RN's own is a VirtualizedList over flattened rows, and so is this. Sections become one list of\n * header, item and footer rows, the rows are placed by `<virtual-list>`'s variable-height windowing,\n * and this component draws each from the caller's templates:\n *\n * ```html\n * <section-list [sections]=\"sections\" [itemHeight]=\"44\" [sectionHeaderHeight]=\"28\">\n * <ng-template sectionHeader let-section><text>{{ section.title }}</text></ng-template>\n * <ng-template sectionItem let-item><text>{{ item }}</text></ng-template>\n * <ng-template sectionSeparator><view [style]=\"line\"></view></ng-template>\n * <ng-template sectionEdgeSeparator><view [style]=\"rule\"></view></ng-template>\n * </section-list>\n * ```\n *\n * Rows are fixed height, as `getItemLayout` makes them in RN: `itemHeight`, `sectionHeaderHeight`\n * and `sectionFooterHeight` are numbers or functions. An item's height includes its separators,\n * which are drawn in the item's slot: the item separator at its bottom, only between items of the\n * same section, and the section separator at the top of a section's first item and the bottom of\n * its last, as RN's `SectionSeparatorComponent` is.\n *\n * `stickySectionHeadersEnabled` pins the current section's header until the next pushes it off.\n * It defaults to on for iOS and off for Android, as RN's does. `listHeader` and `listFooter`\n * content and a `<refresh-control>` pass through to the list.\n *\n * `contentPadding` and `keyboardShouldPersistTaps` pass through to the list as `<virtual-list>`\n * takes them.\n *\n * ponytail: no `horizontal` or `inverted`, no viewability events, and no `highlighted` on a\n * separator. No `keyExtractor` or `maintainVisibleContentPosition` either: rows are fixed height,\n * so there is no measured height for a key to carry across an insert. The host is a plain view\n * with the list filling it, where RN's host is the scroll view, so scroll-view props are not\n * taken.\n */\n@Component({\n selector: 'section-list',\n exportAs: 'sectionList',\n imports: [TemplateSlot, View, VirtualList],\n template: `\n <virtual-list\n #list\n [items]=\"rows()\"\n [itemHeight]=\"rowHeight\"\n [stickyIndices]=\"stickyRows()\"\n [overscan]=\"overscan()\"\n [endReachedThreshold]=\"endReachedThreshold()\"\n [contentPadding]=\"contentPadding()\"\n [keyboardShouldPersistTaps]=\"keyboardShouldPersistTaps()\"\n [style]=\"fill\"\n (endReached)=\"endReached.emit($event)\"\n >\n <ng-content select=\"refresh-control\" ngProjectAs=\"refresh-control\" />\n <view listHeader><ng-content select=\"[listHeader]\" /></view>\n <ng-content />\n @for (row of list.window(); track row.index) {\n <view [style]=\"row.style\">\n @switch (row.item.kind) {\n @case ('header') {\n @if (header(); as header) {\n <ng-container\n [templateSlot]=\"header.template\"\n [templateSlotContext]=\"row.item.context\"\n />\n }\n }\n @case ('footer') {\n @if (footer(); as footer) {\n <ng-container\n [templateSlot]=\"footer.template\"\n [templateSlotContext]=\"row.item.context\"\n />\n }\n }\n @case ('item') {\n @if (row.item.leading; as start) {\n @if (edge(); as edge) {\n <ng-container [templateSlot]=\"edge.template\" [templateSlotContext]=\"start\" />\n }\n }\n <view [style]=\"cell\">\n @if (item(); as item) {\n <ng-container\n [templateSlot]=\"item.template\"\n [templateSlotContext]=\"row.item.context\"\n />\n }\n </view>\n @if (separator(); as separator) {\n @if (row.item.separator; as gap) {\n <ng-container [templateSlot]=\"separator.template\" [templateSlotContext]=\"gap\" />\n }\n }\n @if (row.item.trailing; as end) {\n @if (edge(); as edge) {\n <ng-container [templateSlot]=\"edge.template\" [templateSlotContext]=\"end\" />\n }\n }\n }\n }\n </view>\n }\n <view listFooter><ng-content select=\"[listFooter]\" /></view>\n </virtual-list>\n `,\n})\nexport class SectionList<T, S extends SectionListSection<T> = SectionListSection<T>> {\n readonly sections = input.required<readonly S[]>();\n /** Each item's height, including every separator drawn in its slot. */\n readonly itemHeight = input.required<Height<[item: T, index: number, section: S]>>();\n readonly sectionHeaderHeight = input<Height<[section: S]>>(0);\n readonly sectionFooterHeight = input<Height<[section: S]>>(0);\n /** Pin the current section's header. Defaults to true on iOS and false on Android, as RN. */\n readonly stickySectionHeadersEnabled = input(undefined, { transform: optionalBoolean });\n readonly overscan = input(4, { transform: numberAttribute });\n readonly endReachedThreshold = input(2, { transform: numberAttribute });\n /** Space around the rows, inside the scrolling content. See `<virtual-list>`. */\n readonly contentPadding = input<VirtualListPadding>(0);\n /** What a tap in the list does while a text input has the keyboard up. See `ScrollView`. */\n readonly keyboardShouldPersistTaps = input<KeyboardShouldPersistTaps>('never');\n\n /** The end of the last section is within `endReachedThreshold`. See `<virtual-list>`. */\n readonly endReached = output<{ distanceFromEnd: number }>();\n\n protected readonly header = contentChild<SectionHeader<S>>(SectionHeader);\n protected readonly footer = contentChild<SectionFooter<S>>(SectionFooter);\n protected readonly item = contentChild<SectionItem<T, S>>(SectionItem);\n protected readonly separator = contentChild<SectionSeparator<T, S>>(SectionSeparator);\n protected readonly edge = contentChild<SectionEdgeSeparator<T, S>>(SectionEdgeSeparator);\n private readonly list = viewChild.required<VirtualList<SectionRow<T, S>>>('list');\n\n protected readonly fill = { flex: 1 };\n /** The item fills its slot between its separators, as RN's cell draws them around it. */\n protected readonly cell = { flex: 1 };\n\n protected readonly rows = computed(() => flattenSections<T, S>(this.sections()));\n\n private readonly sticky = computed(\n () => this.stickySectionHeadersEnabled() ?? nativePlatform() === 'ios',\n );\n\n /** The header rows, pinned in turn, when headers stick and there is a header to draw. */\n protected readonly stickyRows = computed(() => {\n if (!this.sticky() || !this.header()) return [];\n const indices: number[] = [];\n this.rows().forEach((row, index) => {\n if (row.kind === 'header') indices.push(index);\n });\n return indices;\n });\n\n protected readonly rowHeight = (row: SectionRow<T, S>): number => {\n const { section } = row.context;\n if (row.kind === 'item') {\n return measure(this.itemHeight(), row.context.item, row.context.index, section);\n }\n return row.kind === 'header'\n ? measure(this.sectionHeaderHeight(), section)\n : measure(this.sectionFooterHeight(), section);\n };\n\n /**\n * Scroll to an item, RN's way: `itemIndex` 0 is the section's header and 1 its first item, and\n * with sticky headers the header's height is allowed for so the item is not hidden under it.\n */\n scrollToLocation(options: {\n sectionIndex: number;\n itemIndex: number;\n viewOffset?: number;\n animated?: boolean;\n }): void {\n const sections = this.sections();\n let index = options.itemIndex;\n for (let i = 0; i < options.sectionIndex; i++) index += sections[i]!.data.length + 2;\n let viewOffset = options.viewOffset ?? 0;\n const section = sections[options.sectionIndex];\n if (options.itemIndex > 0 && this.sticky() && section) {\n viewOffset += measure(this.sectionHeaderHeight(), section);\n }\n this.list().scrollToIndex({ index, viewOffset, animated: options.animated });\n }\n}\n"]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `react-native-gesture-handler` where there is no native recogniser: a browser build and a test,
|
|
3
|
+
* which resolve the library here (`ngNativeWeb()` and `@ng-native/testing`). Nothing is recognised.
|
|
4
|
+
*
|
|
5
|
+
* `Gesture.Pan()`, `Gesture.Tap()`, `Gesture.Simultaneous(...)` and every other builder returns a
|
|
6
|
+
* gesture that takes any configuration call, `.minDistance(10).onUpdate(...)`, and returns itself,
|
|
7
|
+
* so a component builds its gestures exactly as it does on a device. The callbacks it was
|
|
8
|
+
* given are kept on `callbacks`, by name, for a test that wants to call one. `State` and
|
|
9
|
+
* `Directions` are the library's own numbers.
|
|
10
|
+
*/
|
|
11
|
+
/** The configuration and callback calls gestures take, as far as a test types them. */
|
|
12
|
+
type GestureMethod = 'onBegin' | 'onStart' | 'onUpdate' | 'onChange' | 'onEnd' | 'onFinalize' | 'onTouchesDown' | 'onTouchesMove' | 'onTouchesUp' | 'onTouchesCancelled' | 'enabled' | 'runOnJS' | 'minDistance' | 'minPointers' | 'maxPointers' | 'numberOfTaps' | 'minDuration' | 'maxDuration' | 'direction' | 'activeOffsetX' | 'activeOffsetY' | 'failOffsetX' | 'failOffsetY' | 'hitSlop' | 'shouldCancelWhenOutside' | 'manualActivation' | 'simultaneousWithExternalGesture' | 'requireExternalGestureToFail' | 'blocksExternalGesture' | 'withRef' | 'withTestId';
|
|
13
|
+
/**
|
|
14
|
+
* A gesture built in a test: every configuration call returns it, and callbacks are kept. `kind`
|
|
15
|
+
* is the builder that made it, `Pan` or `Race`, and `gestures` what a composed one was made of.
|
|
16
|
+
*/
|
|
17
|
+
export type StandInGesture = {
|
|
18
|
+
readonly kind: string;
|
|
19
|
+
readonly gestures: readonly StandInGesture[];
|
|
20
|
+
readonly callbacks: Record<string, (...args: never[]) => unknown>;
|
|
21
|
+
} & {
|
|
22
|
+
readonly [M in GestureMethod]: (...args: readonly unknown[]) => StandInGesture;
|
|
23
|
+
};
|
|
24
|
+
type Builder = 'Pan' | 'Tap' | 'LongPress' | 'Pinch' | 'Rotation' | 'Fling' | 'Hover' | 'Manual' | 'Native' | 'ForceTouch' | 'Race' | 'Simultaneous' | 'Exclusive';
|
|
25
|
+
export declare const Gesture: Readonly<Record<Builder, (...gestures: readonly unknown[]) => StandInGesture>>;
|
|
26
|
+
export declare const State: {
|
|
27
|
+
readonly UNDETERMINED: 0;
|
|
28
|
+
readonly FAILED: 1;
|
|
29
|
+
readonly BEGAN: 2;
|
|
30
|
+
readonly CANCELLED: 3;
|
|
31
|
+
readonly ACTIVE: 4;
|
|
32
|
+
readonly END: 5;
|
|
33
|
+
};
|
|
34
|
+
export declare const Directions: {
|
|
35
|
+
readonly RIGHT: 1;
|
|
36
|
+
readonly LEFT: 2;
|
|
37
|
+
readonly UP: 4;
|
|
38
|
+
readonly DOWN: 8;
|
|
39
|
+
};
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `react-native-gesture-handler` where there is no native recogniser: a browser build and a test,
|
|
3
|
+
* which resolve the library here (`ngNativeWeb()` and `@ng-native/testing`). Nothing is recognised.
|
|
4
|
+
*
|
|
5
|
+
* `Gesture.Pan()`, `Gesture.Tap()`, `Gesture.Simultaneous(...)` and every other builder returns a
|
|
6
|
+
* gesture that takes any configuration call, `.minDistance(10).onUpdate(...)`, and returns itself,
|
|
7
|
+
* so a component builds its gestures exactly as it does on a device. The callbacks it was
|
|
8
|
+
* given are kept on `callbacks`, by name, for a test that wants to call one. `State` and
|
|
9
|
+
* `Directions` are the library's own numbers.
|
|
10
|
+
*/
|
|
11
|
+
function gesture(kind, gestures) {
|
|
12
|
+
const callbacks = {};
|
|
13
|
+
const fields = { kind, gestures, callbacks };
|
|
14
|
+
const self = new Proxy(fields, {
|
|
15
|
+
get(target, key) {
|
|
16
|
+
if (typeof key === 'string' && key in fields)
|
|
17
|
+
return fields[key];
|
|
18
|
+
// Not a thenable, and nothing to say to a symbol such as `Symbol.toPrimitive`.
|
|
19
|
+
if (typeof key === 'symbol' || key === 'then')
|
|
20
|
+
return undefined;
|
|
21
|
+
return (...args) => {
|
|
22
|
+
if (key.startsWith('on') && typeof args[0] === 'function') {
|
|
23
|
+
callbacks[key] = args[0];
|
|
24
|
+
}
|
|
25
|
+
return self;
|
|
26
|
+
};
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
return self;
|
|
30
|
+
}
|
|
31
|
+
export const Gesture = new Proxy({}, {
|
|
32
|
+
get: (_target, kind) => (...gestures) => gesture(String(kind), gestures),
|
|
33
|
+
});
|
|
34
|
+
export const State = {
|
|
35
|
+
UNDETERMINED: 0,
|
|
36
|
+
FAILED: 1,
|
|
37
|
+
BEGAN: 2,
|
|
38
|
+
CANCELLED: 3,
|
|
39
|
+
ACTIVE: 4,
|
|
40
|
+
END: 5,
|
|
41
|
+
};
|
|
42
|
+
export const Directions = { RIGHT: 1, LEFT: 2, UP: 4, DOWN: 8 };
|
|
43
|
+
//# sourceMappingURL=gesture-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gesture-handler.js","sourceRoot":"","sources":["../../src/stand-ins/gesture-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA6DH,SAAS,OAAO,CAAC,IAAY,EAAE,QAAmC;IAChE,MAAM,SAAS,GAAkD,EAAE,CAAC;IACpE,MAAM,MAAM,GAA4B,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtE,MAAM,IAAI,GAAG,IAAI,KAAK,CAAC,MAAwB,EAAE;QAC/C,GAAG,CAAC,MAAM,EAAE,GAAG;YACb,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,IAAI,MAAM;gBAAE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,+EAA+E;YAC/E,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,MAAM;gBAAE,OAAO,SAAS,CAAC;YAChE,OAAO,CAAC,GAAG,IAAe,EAAE,EAAE;gBAC5B,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,UAAU,EAAE,CAAC;oBAC1D,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAkC,CAAC;gBAC5D,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,KAAK,CAC9B,EAAE,EACF;IACE,GAAG,EACD,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAClB,CAAC,GAAG,QAAmB,EAAE,EAAE,CACzB,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,QAA4B,CAAC;CACxD,CACgF,CAAC;AAEpF,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,YAAY,EAAE,CAAC;IACf,MAAM,EAAE,CAAC;IACT,KAAK,EAAE,CAAC;IACR,SAAS,EAAE,CAAC;IACZ,MAAM,EAAE,CAAC;IACT,GAAG,EAAE,CAAC;CACE,CAAC;AAEX,MAAM,CAAC,MAAM,UAAU,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAW,CAAC","sourcesContent":["/**\n * `react-native-gesture-handler` where there is no native recogniser: a browser build and a test,\n * which resolve the library here (`ngNativeWeb()` and `@ng-native/testing`). Nothing is recognised.\n *\n * `Gesture.Pan()`, `Gesture.Tap()`, `Gesture.Simultaneous(...)` and every other builder returns a\n * gesture that takes any configuration call, `.minDistance(10).onUpdate(...)`, and returns itself,\n * so a component builds its gestures exactly as it does on a device. The callbacks it was\n * given are kept on `callbacks`, by name, for a test that wants to call one. `State` and\n * `Directions` are the library's own numbers.\n */\n\n/** The configuration and callback calls gestures take, as far as a test types them. */\ntype GestureMethod =\n | 'onBegin'\n | 'onStart'\n | 'onUpdate'\n | 'onChange'\n | 'onEnd'\n | 'onFinalize'\n | 'onTouchesDown'\n | 'onTouchesMove'\n | 'onTouchesUp'\n | 'onTouchesCancelled'\n | 'enabled'\n | 'runOnJS'\n | 'minDistance'\n | 'minPointers'\n | 'maxPointers'\n | 'numberOfTaps'\n | 'minDuration'\n | 'maxDuration'\n | 'direction'\n | 'activeOffsetX'\n | 'activeOffsetY'\n | 'failOffsetX'\n | 'failOffsetY'\n | 'hitSlop'\n | 'shouldCancelWhenOutside'\n | 'manualActivation'\n | 'simultaneousWithExternalGesture'\n | 'requireExternalGestureToFail'\n | 'blocksExternalGesture'\n | 'withRef'\n | 'withTestId';\n\n/**\n * A gesture built in a test: every configuration call returns it, and callbacks are kept. `kind`\n * is the builder that made it, `Pan` or `Race`, and `gestures` what a composed one was made of.\n */\nexport type StandInGesture = {\n readonly kind: string;\n readonly gestures: readonly StandInGesture[];\n readonly callbacks: Record<string, (...args: never[]) => unknown>;\n} & { readonly [M in GestureMethod]: (...args: readonly unknown[]) => StandInGesture };\n\ntype Builder =\n | 'Pan'\n | 'Tap'\n | 'LongPress'\n | 'Pinch'\n | 'Rotation'\n | 'Fling'\n | 'Hover'\n | 'Manual'\n | 'Native'\n | 'ForceTouch'\n | 'Race'\n | 'Simultaneous'\n | 'Exclusive';\n\nfunction gesture(kind: string, gestures: readonly StandInGesture[]): StandInGesture {\n const callbacks: Record<string, (...args: never[]) => unknown> = {};\n const fields: Record<string, unknown> = { kind, gestures, callbacks };\n const self = new Proxy(fields as StandInGesture, {\n get(target, key) {\n if (typeof key === 'string' && key in fields) return fields[key];\n // Not a thenable, and nothing to say to a symbol such as `Symbol.toPrimitive`.\n if (typeof key === 'symbol' || key === 'then') return undefined;\n return (...args: unknown[]) => {\n if (key.startsWith('on') && typeof args[0] === 'function') {\n callbacks[key] = args[0] as (...args: never[]) => unknown;\n }\n return self;\n };\n },\n });\n return self;\n}\n\nexport const Gesture = new Proxy(\n {},\n {\n get:\n (_target, kind) =>\n (...gestures: unknown[]) =>\n gesture(String(kind), gestures as StandInGesture[]),\n },\n) as Readonly<Record<Builder, (...gestures: readonly unknown[]) => StandInGesture>>;\n\nexport const State = {\n UNDETERMINED: 0,\n FAILED: 1,\n BEGAN: 2,\n CANCELLED: 3,\n ACTIVE: 4,\n END: 5,\n} as const;\n\nexport const Directions = { RIGHT: 1, LEFT: 2, UP: 4, DOWN: 8 } as const;\n"]}
|