@ng-native/components 0.5.0 → 0.7.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/html-entities.d.ts +7 -0
- package/dist/html-entities.js +59 -0
- package/dist/html-entities.js.map +1 -0
- package/dist/markdown-blocks.d.ts +79 -0
- package/dist/markdown-blocks.js +212 -0
- package/dist/markdown-blocks.js.map +1 -0
- package/dist/markdown.d.ts +63 -0
- package/dist/markdown.js +338 -0
- package/dist/markdown.js.map +1 -0
- package/dist/virtual-list.d.ts +16 -0
- package/dist/virtual-list.js +91 -36
- package/dist/virtual-list.js.map +1 -1
- package/package.json +14 -5
package/dist/virtual-list.js
CHANGED
|
@@ -25,8 +25,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImpor
|
|
|
25
25
|
type: Directive,
|
|
26
26
|
args: [{ selector: 'ng-template[virtualListSeparator]' }]
|
|
27
27
|
}] });
|
|
28
|
-
/**
|
|
29
|
-
|
|
28
|
+
/**
|
|
29
|
+
* A parked slot: out of the flow, out of sight and out of reach, with its view kept to be used
|
|
30
|
+
* again. Not `display: none`, which is an element with no view. A screen reader passes over a
|
|
31
|
+
* view with no opacity, and `VirtualListRow` says so outright where a row uses it. Moved off the
|
|
32
|
+
* list as well, since `pointer-events: none` is CSS's: something inside a row with a
|
|
33
|
+
* `pointer-events` of its own would still take a touch where the row was left.
|
|
34
|
+
*/
|
|
35
|
+
const PARKED = Object.freeze({
|
|
36
|
+
position: 'absolute',
|
|
37
|
+
opacity: 0,
|
|
38
|
+
pointerEvents: 'none',
|
|
39
|
+
transform: 'translateX(-100000px)',
|
|
40
|
+
});
|
|
30
41
|
/** How many hidden slots of each row type are kept ready for reuse. */
|
|
31
42
|
const PARK_LIMIT = 6;
|
|
32
43
|
/** The style of a row that sizes itself and needs nothing else: in flow, where it falls. */
|
|
@@ -178,6 +189,8 @@ export class VirtualList extends ScrollViewProps {
|
|
|
178
189
|
...(ngDevMode ? [{ debugName: "headerHeight" }] : /* istanbul ignore next */ []));
|
|
179
190
|
/** What native reported the content measures along the axis, once it has. */
|
|
180
191
|
contentSize = 0;
|
|
192
|
+
/** The rows' own extent when native reported that, so a report for other rows is not used. */
|
|
193
|
+
contentSizeFor = -1;
|
|
181
194
|
/** The item count `endReached` last fired for, cleared once the list is away from the end. */
|
|
182
195
|
endReachedFor = -1;
|
|
183
196
|
/** Slot styles are cached so a scroll does not hand Fabric new prop objects for stable rows. */
|
|
@@ -309,6 +322,9 @@ export class VirtualList extends ScrollViewProps {
|
|
|
309
322
|
stride() {
|
|
310
323
|
return this.itemHeight() + this.rowGap();
|
|
311
324
|
}
|
|
325
|
+
/** ScrollView.js's `contentContainerHorizontal`: the header, rows and footer side by side. */
|
|
326
|
+
content = computed(() => this.horizontal() ? { flexDirection: 'row' } : undefined, /* @ts-ignore */
|
|
327
|
+
...(ngDevMode ? [{ debugName: "content" }] : /* istanbul ignore next */ []));
|
|
312
328
|
canvas = computed(() => this.horizontal() ? { width: this.extent(), flexDirection: 'row' } : { height: this.extent() }, /* @ts-ignore */
|
|
313
329
|
...(ngDevMode ? [{ debugName: "canvas" }] : /* istanbul ignore next */ []));
|
|
314
330
|
/**
|
|
@@ -521,6 +537,7 @@ export class VirtualList extends ScrollViewProps {
|
|
|
521
537
|
this.flushScroll();
|
|
522
538
|
if (this.nativeSticky)
|
|
523
539
|
this.driveStickyRows();
|
|
540
|
+
this.recheckItems();
|
|
524
541
|
});
|
|
525
542
|
const stop = dismissKeyboardOnTap(this.engine, this.node, () => this.keyboardShouldPersistTaps());
|
|
526
543
|
inject(DestroyRef).onDestroy(() => {
|
|
@@ -533,6 +550,21 @@ export class VirtualList extends ScrollViewProps {
|
|
|
533
550
|
if (this.zeroSize)
|
|
534
551
|
this.checkZeroSize(this.zeroSize);
|
|
535
552
|
}
|
|
553
|
+
/** The items the end and viewability were last checked against after a render. */
|
|
554
|
+
checkedItems = null;
|
|
555
|
+
/**
|
|
556
|
+
* New items can bring the end within reach or change what is on screen with no scroll: a list
|
|
557
|
+
* shorter than its viewport, a page appended while at the end, a filter. Checked once the rows
|
|
558
|
+
* they make are rendered, and only when they changed, so any other render costs a comparison.
|
|
559
|
+
*/
|
|
560
|
+
recheckItems() {
|
|
561
|
+
const items = this.items();
|
|
562
|
+
if (items === this.checkedItems)
|
|
563
|
+
return;
|
|
564
|
+
this.checkedItems = items;
|
|
565
|
+
this.checkEnd(this.headerHeight() + this.lastOffset);
|
|
566
|
+
this.announceViewable(this.lastOffset);
|
|
567
|
+
}
|
|
536
568
|
/** Whether the viewport has been laid out yet, so a zero in it is a measurement. */
|
|
537
569
|
viewportMeasured = false;
|
|
538
570
|
/**
|
|
@@ -973,6 +1005,8 @@ export class VirtualList extends ScrollViewProps {
|
|
|
973
1005
|
}
|
|
974
1006
|
/** The last set announced, so the output fires on a change rather than on every frame. */
|
|
975
1007
|
announced = [];
|
|
1008
|
+
/** The items the last set was announced from: new items are a change even at the same indices. */
|
|
1009
|
+
announcedFrom = null;
|
|
976
1010
|
/**
|
|
977
1011
|
* Announce a change in what is on screen.
|
|
978
1012
|
*
|
|
@@ -985,10 +1019,12 @@ export class VirtualList extends ScrollViewProps {
|
|
|
985
1019
|
const viewable = this.viewableAt(offset);
|
|
986
1020
|
const entered = viewable.filter((index) => !this.announced.includes(index));
|
|
987
1021
|
const left = this.announced.filter((index) => !viewable.includes(index));
|
|
988
|
-
|
|
1022
|
+
const items = this.items();
|
|
1023
|
+
const same = items === this.announcedFrom || viewable.length === 0;
|
|
1024
|
+
if (entered.length === 0 && left.length === 0 && same)
|
|
989
1025
|
return;
|
|
990
1026
|
this.announced = viewable;
|
|
991
|
-
|
|
1027
|
+
this.announcedFrom = items;
|
|
992
1028
|
this.viewableItemsChanged.emit({
|
|
993
1029
|
viewable: viewable.map((index) => {
|
|
994
1030
|
const key = this.keyAt(index);
|
|
@@ -1091,6 +1127,7 @@ export class VirtualList extends ScrollViewProps {
|
|
|
1091
1127
|
this.viewport.set((this.horizontal() ? layout?.width : layout?.height) ?? 0);
|
|
1092
1128
|
this.viewportMeasured = true;
|
|
1093
1129
|
this.zeroSize?.laidOut(this.viewport(), this.items().length > 0);
|
|
1130
|
+
this.checkEnd(this.headerHeight() + this.lastOffset);
|
|
1094
1131
|
this.announceViewable(this.lastOffset);
|
|
1095
1132
|
}
|
|
1096
1133
|
/** The header's extent along the axis, which every row sits after. */
|
|
@@ -1118,13 +1155,18 @@ export class VirtualList extends ScrollViewProps {
|
|
|
1118
1155
|
onContentSize(event) {
|
|
1119
1156
|
const size = event.nativeEvent;
|
|
1120
1157
|
this.contentSize = (this.horizontal() ? size?.width : size?.height) ?? 0;
|
|
1158
|
+
this.contentSizeFor = this.extent();
|
|
1159
|
+
this.checkEnd(this.headerHeight() + this.lastOffset);
|
|
1121
1160
|
}
|
|
1122
1161
|
checkEnd(y) {
|
|
1123
1162
|
const count = this.items().length;
|
|
1124
1163
|
const viewport = this.viewport();
|
|
1125
1164
|
if (!count || !viewport)
|
|
1126
1165
|
return;
|
|
1127
|
-
|
|
1166
|
+
// Native's size is for the rows it last laid out; until it reports for these, their own extent.
|
|
1167
|
+
const extent = this.extent();
|
|
1168
|
+
const reported = this.contentSizeFor === extent ? this.contentSize : 0;
|
|
1169
|
+
const total = reported || this.headerHeight() + extent;
|
|
1128
1170
|
const distanceFromEnd = total - (y + viewport);
|
|
1129
1171
|
// Away from the end again re-arms it, as React Native does, so a load that failed is retried
|
|
1130
1172
|
// the next time the user comes back down.
|
|
@@ -1140,23 +1182,27 @@ export class VirtualList extends ScrollViewProps {
|
|
|
1140
1182
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: VirtualList, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1141
1183
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.2.0", type: VirtualList, isStandalone: true, selector: "virtual-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, itemHeight: { classPropertyName: "itemHeight", publicName: "itemHeight", isSignal: true, isRequired: false, transformFunction: null }, estimatedItemHeight: { classPropertyName: "estimatedItemHeight", publicName: "estimatedItemHeight", isSignal: true, isRequired: false, transformFunction: null }, contentPadding: { classPropertyName: "contentPadding", publicName: "contentPadding", isSignal: true, isRequired: false, transformFunction: null }, rowGap: { classPropertyName: "rowGap", publicName: "rowGap", isSignal: true, isRequired: false, transformFunction: null }, keyExtractor: { classPropertyName: "keyExtractor", publicName: "keyExtractor", isSignal: true, isRequired: false, transformFunction: null }, itemType: { classPropertyName: "itemType", publicName: "itemType", isSignal: true, isRequired: false, transformFunction: null }, maintainVisibleContentPosition: { classPropertyName: "maintainVisibleContentPosition", publicName: "maintainVisibleContentPosition", 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 }, horizontal: { classPropertyName: "horizontal", publicName: "horizontal", isSignal: true, isRequired: false, transformFunction: null }, inverted: { classPropertyName: "inverted", publicName: "inverted", isSignal: true, isRequired: false, transformFunction: null }, stickyIndices: { classPropertyName: "stickyIndices", publicName: "stickyIndices", isSignal: true, isRequired: false, transformFunction: null }, stickyHeader: { classPropertyName: "stickyHeader", publicName: "stickyHeader", isSignal: true, isRequired: false, transformFunction: null }, keyboardShouldPersistTaps: { classPropertyName: "keyboardShouldPersistTaps", publicName: "keyboardShouldPersistTaps", isSignal: true, isRequired: false, transformFunction: null }, itemVisiblePercentThreshold: { classPropertyName: "itemVisiblePercentThreshold", publicName: "itemVisiblePercentThreshold", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { endReached: "endReached", viewableItemsChanged: "viewableItemsChanged" }, host: { listeners: { "scroll": "onScroll($event)", "layout": "onLayout($event)", "contentSizeChange": "onContentSize($event)" }, properties: { "flexDirection": "horizontal() ? 'row' : 'column'", "horizontal": "horizontal()", "nestedScrollEnabled": "nestedScroll()", "transform": "flip()", "scrollEventThrottle": "scrollEventThrottle()" } }, queries: [{ propertyName: "separator", first: true, predicate: VirtualListSeparator, descendants: true, isSignal: true }, { propertyName: "refreshControl", first: true, predicate: RefreshControl, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "canvasView", first: true, predicate: ["rows"], descendants: true, read: ElementRef, isSignal: true }], exportAs: ["virtualList"], usesInheritance: true, ngImport: i0, template: `
|
|
1142
1184
|
<ng-content select="refresh-control" />
|
|
1143
|
-
<view [style]="
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
@
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1185
|
+
<view [style]="content()" collapsable="false">
|
|
1186
|
+
<view [style]="headerStyle()" (layout)="onHeaderLayout($event)"
|
|
1187
|
+
><ng-content select="[listHeader]"
|
|
1188
|
+
/></view>
|
|
1189
|
+
<view #rows [style]="canvas()" collapsable="false">
|
|
1190
|
+
@if (measuring()) {
|
|
1191
|
+
<view [style]="spacer()"></view>
|
|
1192
|
+
}
|
|
1193
|
+
<ng-content />
|
|
1194
|
+
@if (separator(); as separator) {
|
|
1195
|
+
@for (gap of gaps(); track gap.index) {
|
|
1196
|
+
<view [style]="gap.style"
|
|
1197
|
+
><ng-container
|
|
1198
|
+
[templateSlot]="separator.template"
|
|
1199
|
+
[templateSlotContext]="gap.context"
|
|
1200
|
+
/></view>
|
|
1201
|
+
}
|
|
1156
1202
|
}
|
|
1157
|
-
|
|
1203
|
+
</view>
|
|
1204
|
+
<view [style]="footerStyle()"><ng-content select="[listFooter]" /></view>
|
|
1158
1205
|
</view>
|
|
1159
|
-
<view [style]="footerStyle()"><ng-content select="[listFooter]" /></view>
|
|
1160
1206
|
`, isInline: true, dependencies: [{ kind: "directive", type: TemplateSlot, selector: "[templateSlot]", inputs: ["templateSlot", "templateSlotContext"] }, { kind: "directive", type: View, selector: "view" }] });
|
|
1161
1207
|
}
|
|
1162
1208
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: VirtualList, decorators: [{
|
|
@@ -1165,29 +1211,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImpor
|
|
|
1165
1211
|
selector: 'virtual-list',
|
|
1166
1212
|
exportAs: 'virtualList',
|
|
1167
1213
|
imports: [TemplateSlot, View],
|
|
1214
|
+
// One content view holds the header, the rows and the footer, as ScrollView.js's content
|
|
1215
|
+
// container does: Android's ScrollView takes one child and throws on a second. It is never
|
|
1216
|
+
// collapsed, or Fabric would flatten it away and hand the scroll view all three again.
|
|
1168
1217
|
// See ScrollView: the canvas carries only a height, so Fabric would flatten it away and drags
|
|
1169
1218
|
// over the gaps between rows would not scroll. Separators come after the rows so they draw over
|
|
1170
1219
|
// the slot they share. The spacer is there only when rows are in flow.
|
|
1171
1220
|
// A refresh control comes first, as the scroll view's own child; see ScrollView.
|
|
1172
1221
|
template: `
|
|
1173
1222
|
<ng-content select="refresh-control" />
|
|
1174
|
-
<view [style]="
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
@
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1223
|
+
<view [style]="content()" collapsable="false">
|
|
1224
|
+
<view [style]="headerStyle()" (layout)="onHeaderLayout($event)"
|
|
1225
|
+
><ng-content select="[listHeader]"
|
|
1226
|
+
/></view>
|
|
1227
|
+
<view #rows [style]="canvas()" collapsable="false">
|
|
1228
|
+
@if (measuring()) {
|
|
1229
|
+
<view [style]="spacer()"></view>
|
|
1230
|
+
}
|
|
1231
|
+
<ng-content />
|
|
1232
|
+
@if (separator(); as separator) {
|
|
1233
|
+
@for (gap of gaps(); track gap.index) {
|
|
1234
|
+
<view [style]="gap.style"
|
|
1235
|
+
><ng-container
|
|
1236
|
+
[templateSlot]="separator.template"
|
|
1237
|
+
[templateSlotContext]="gap.context"
|
|
1238
|
+
/></view>
|
|
1239
|
+
}
|
|
1187
1240
|
}
|
|
1188
|
-
|
|
1241
|
+
</view>
|
|
1242
|
+
<view [style]="footerStyle()"><ng-content select="[listFooter]" /></view>
|
|
1189
1243
|
</view>
|
|
1190
|
-
<view [style]="footerStyle()"><ng-content select="[listFooter]" /></view>
|
|
1191
1244
|
`,
|
|
1192
1245
|
host: {
|
|
1193
1246
|
// ScrollView.js's `baseHorizontal`: a column would stack the header, canvas and footer, and
|
|
@@ -1223,7 +1276,7 @@ export class VirtualListRow {
|
|
|
1223
1276
|
this.list.measureRow(this.row(), event.nativeEvent?.layout);
|
|
1224
1277
|
}
|
|
1225
1278
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: VirtualListRow, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1226
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.2.0", type: VirtualListRow, isStandalone: true, selector: "[virtualListRow]", inputs: { row: { classPropertyName: "row", publicName: "virtualListRow", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "layout": "onLayout($event)" }, properties: { "style": "row().style" } }, ngImport: i0 });
|
|
1279
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.2.0", type: VirtualListRow, isStandalone: true, selector: "[virtualListRow]", inputs: { row: { classPropertyName: "row", publicName: "virtualListRow", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "layout": "onLayout($event)" }, properties: { "style": "row().style", "attr.aria-hidden": "row().parked ? true : null" } }, ngImport: i0 });
|
|
1227
1280
|
}
|
|
1228
1281
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: VirtualListRow, decorators: [{
|
|
1229
1282
|
type: Directive,
|
|
@@ -1231,6 +1284,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImpor
|
|
|
1231
1284
|
selector: '[virtualListRow]',
|
|
1232
1285
|
host: {
|
|
1233
1286
|
'[style]': 'row().style',
|
|
1287
|
+
// A parked row is not read out: see `PARKED`.
|
|
1288
|
+
'[attr.aria-hidden]': 'row().parked ? true : null',
|
|
1234
1289
|
'(layout)': 'onLayout($event)',
|
|
1235
1290
|
},
|
|
1236
1291
|
}]
|