@ng-native/components 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/section-list.d.ts +45 -8
- package/dist/section-list.js +67 -11
- package/dist/section-list.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -47,10 +47,10 @@ renders as a plain, unstyled view and logs a console warning in development.
|
|
|
47
47
|
- `.` - `View`, `Text`, `ScrollView`, `TextInput`, `Pressable`, `Image`, `Switch`,
|
|
48
48
|
`ActivityIndicator`, `Modal`, `VirtualList`, `SafeAreaProvider`, `SafeAreaView`, and the event
|
|
49
49
|
payload types (`LayoutEvent`, `TouchEvent`, `ScrollEvent`, and more).
|
|
50
|
-
- `./gestures
|
|
51
|
-
- `./animations
|
|
50
|
+
- `./gestures` - React Native Gesture Handler bindings.
|
|
51
|
+
- `./animations` - `AnimatedStyle`, `Animated` and `Easing`: React Native's graph on a device,
|
|
52
52
|
a React-free one with the same API in a browser build.
|
|
53
|
-
- `./reanimated
|
|
53
|
+
- `./reanimated` - Reanimated worklet bindings.
|
|
54
54
|
|
|
55
55
|
These three are separate entry points because each reaches into React Native's own uncompiled
|
|
56
56
|
source, which Node cannot parse; importing them from the main entry point would break loading this
|
package/dist/index.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export { SafeAreaProvider } from './safe-area-provider.ts';
|
|
|
25
25
|
export { SafeAreaView, type SafeAreaEdgeMode } from './safe-area-view.ts';
|
|
26
26
|
export { type KeyboardShouldPersistTaps } from './keyboard-taps.ts';
|
|
27
27
|
export { ScrollView } from './scroll-view.ts';
|
|
28
|
-
export { SectionFooter, SectionHeader, SectionItem, SectionList, SectionSeparator, type SectionContext, type SectionItemContext, type SectionListSection, type SectionRow, type SectionSeparatorContext, } from './section-list.ts';
|
|
28
|
+
export { SectionEdgeSeparator, SectionFooter, SectionHeader, SectionItem, SectionList, SectionSeparator, type SectionContext, type SectionEdgeSeparatorContext, type SectionItemContext, type SectionListSection, type SectionRow, type SectionSeparatorContext, } from './section-list.ts';
|
|
29
29
|
export { Switch } from './switch.ts';
|
|
30
30
|
export { Text, type DynamicTypeRamp, type EllipsizeMode } from './text.ts';
|
|
31
31
|
export { TextInput, type KeyboardType, type ReturnKeyType, type SubmitBehavior, } from './text-input.ts';
|
package/dist/index.js
CHANGED
|
@@ -25,7 +25,7 @@ export { SafeAreaProvider } from "./safe-area-provider.js";
|
|
|
25
25
|
export { SafeAreaView } from "./safe-area-view.js";
|
|
26
26
|
export {} from "./keyboard-taps.js";
|
|
27
27
|
export { ScrollView } from "./scroll-view.js";
|
|
28
|
-
export { SectionFooter, SectionHeader, SectionItem, SectionList, SectionSeparator, } from "./section-list.js";
|
|
28
|
+
export { SectionEdgeSeparator, SectionFooter, SectionHeader, SectionItem, SectionList, SectionSeparator, } from "./section-list.js";
|
|
29
29
|
export { Switch } from "./switch.js";
|
|
30
30
|
export { Text } from "./text.js";
|
|
31
31
|
export { TextInput, } from "./text-input.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAmD,MAAM,gBAAgB,CAAC;AACjF,OAAO,EAwCN,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,KAAK,EAA+D,MAAM,YAAY,CAAC;AAChG,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,yBAAyB,GAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,oBAAoB,EAAiC,MAAM,6BAA6B,CAAC;AAClG,OAAO,EAAE,KAAK,EAAsD,MAAM,YAAY,CAAC;AACvF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EACL,WAAW,EACX,aAAa,EACb,SAAS,EACT,aAAa,GAGd,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAyC,MAAM,gBAAgB,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAyB,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAkC,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EACL,aAAa,EACb,aAAa,EACb,WAAW,EACX,WAAW,EACX,gBAAgB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAmD,MAAM,gBAAgB,CAAC;AACjF,OAAO,EAwCN,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,KAAK,EAA+D,MAAM,YAAY,CAAC;AAChG,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,yBAAyB,GAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,oBAAoB,EAAiC,MAAM,6BAA6B,CAAC;AAClG,OAAO,EAAE,KAAK,EAAsD,MAAM,YAAY,CAAC;AACvF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EACL,WAAW,EACX,aAAa,EACb,SAAS,EACT,aAAa,GAGd,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAyC,MAAM,gBAAgB,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAyB,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAkC,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,WAAW,EACX,WAAW,EACX,gBAAgB,GAOjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAA4C,MAAM,WAAW,CAAC;AAC3E,OAAO,EACL,SAAS,GAIV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,uBAAuB,GAUxB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,WAAW,EACX,cAAc,EACd,oBAAoB,GAKrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAA6D,MAAM,sBAAsB,CAAC;AACjG,OAAO,EACL,aAAa,EACb,YAAY,GAMb,MAAM,eAAe,CAAC","sourcesContent":["/**\n * The host primitives, and the platform-capability tokens they inject.\n *\n * Every element a template renders natively is a component here and must be imported by the\n * component whose template uses it, as any Angular component must. A template that uses one\n * without importing it compiles, renders a plain view, and is reported in dev builds.\n *\n * Importing this barrel evaluates decorators, so anything a Node test needs at runtime has to\n * be reached as a source file instead - see the note in `packages/integration-tests/compile.ts`.\n */\nexport { ActivityIndicator } from './activity-indicator.ts';\nexport { type AnimatedPropsHandle, type AnimationBackend } from './animation.ts';\nexport {\n type AccessibilityActionEvent,\n type AccessibilityActionPayload,\n type ContentSizeChangeEvent,\n type ImageErrorEvent,\n type ImageErrorPayload,\n type ImageLoadEvent,\n type ImageLoadPayload,\n type ImageProgressEvent,\n type ImageProgressPayload,\n type Insets,\n type KeyPressEvent,\n type KeyPressPayload,\n type LayoutEvent,\n type LayoutPayload,\n type OrientationChangeEvent,\n type OrientationChangePayload,\n type Point,\n type Rect,\n type ScrollEvent,\n type ScrollPayload,\n type SelectionChangeEvent,\n type SelectionChangePayload,\n type Size,\n type SwitchChangeEvent,\n type SwitchChangePayload,\n type TextInputChangeEvent,\n type TextInputChangePayload,\n type TextInputContentSizeEvent,\n type TextInputContentSizePayload,\n type TextInputEditingEvent,\n type TextInputFocusEvent,\n type TextInputFocusPayload,\n type TextInputScrollEvent,\n type TextInputScrollPayload,\n type TextLayoutEvent,\n type TextLayoutLine,\n type TextLayoutPayload,\n type TouchEvent,\n type TouchEventPayload,\n} from './events.ts';\nexport { Image, type ImageResizeMode, type ImageSource, type ImageURISource } from './image.ts';\nexport { ImageBackground } from './image-background.ts';\nexport { InputAccessoryView } from './input-accessory-view.ts';\nexport {\n KEYBOARD_CONTROLLER,\n KeyboardDock,\n KeyboardLift,\n provideKeyboardController,\n} from './keyboard-dock.ts';\nexport { KeyboardAvoidingView, type KeyboardAvoidingBehavior } from './keyboard-avoiding-view.ts';\nexport { Modal, type ModalOrientation, type ModalPresentationStyle } from './modal.ts';\nexport { NativeRef } from './native-ref.ts';\nexport {\n ControlBase,\n PressBehavior,\n Pressable,\n TouchableBase,\n type AndroidRipple,\n type PressEvent,\n} from './pressable.ts';\nexport { RefreshControl } from './refresh-control.ts';\nexport { type SafeAreaEdge, type SafeAreaEdges } from './safe-area.ts';\nexport { SafeAreaProvider } from './safe-area-provider.ts';\nexport { SafeAreaView, type SafeAreaEdgeMode } from './safe-area-view.ts';\nexport { type KeyboardShouldPersistTaps } from './keyboard-taps.ts';\nexport { ScrollView } from './scroll-view.ts';\nexport {\n SectionEdgeSeparator,\n SectionFooter,\n SectionHeader,\n SectionItem,\n SectionList,\n SectionSeparator,\n type SectionContext,\n type SectionEdgeSeparatorContext,\n type SectionItemContext,\n type SectionListSection,\n type SectionRow,\n type SectionSeparatorContext,\n} from './section-list.ts';\nexport { Switch } from './switch.ts';\nexport { Text, type DynamicTypeRamp, type EllipsizeMode } from './text.ts';\nexport {\n TextInput,\n type KeyboardType,\n type ReturnKeyType,\n type SubmitBehavior,\n} from './text-input.ts';\nexport { TouchableOpacity } from './touchable-opacity.ts';\nexport { optionalBoolean, optionalNumber } from './transforms.ts';\nexport { View } from './view.ts';\nexport {\n ViewBase,\n ViewBehavior,\n contributeAccessibility,\n type AccessibilityAction,\n type AccessibilityContribution,\n type AccessibilityLiveRegion,\n type AccessibilityRole,\n type AccessibilityState,\n type AccessibilityValue,\n type AndroidDrawable,\n type ImportantForAccessibility,\n type PointerEvents,\n} from './view-base.ts';\nexport {\n VirtualList,\n VirtualListRow,\n VirtualListSeparator,\n type VirtualItemHeight,\n type VirtualListSeparatorContext,\n type VirtualListVisiblePosition,\n type VirtualRow,\n} from './virtual-list.ts';\nexport { type GestureBackend, type GestureSpec, type GestureTarget } from './gesture-backend.ts';\nexport {\n workletScroll,\n workletStyle,\n type SharedValue,\n type WorkletBackend,\n type WorkletScrollSpec,\n type WorkletStyleSpec,\n type WorkletTarget,\n} from './worklets.ts';\n"]}
|
package/dist/section-list.d.ts
CHANGED
|
@@ -27,6 +27,18 @@ export interface SectionSeparatorContext<T, S> {
|
|
|
27
27
|
readonly trailingItem: T;
|
|
28
28
|
readonly section: S;
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* What a section separator template is given: the section, and what is either side of the edge
|
|
32
|
+
* it sits at. At a section's start `leadingItem` is undefined, and at its end `trailingItem` is.
|
|
33
|
+
*/
|
|
34
|
+
export interface SectionEdgeSeparatorContext<T, S> {
|
|
35
|
+
readonly $implicit: S;
|
|
36
|
+
readonly section: S;
|
|
37
|
+
readonly leadingItem: T | undefined;
|
|
38
|
+
readonly leadingSection: S | undefined;
|
|
39
|
+
readonly trailingItem: T | undefined;
|
|
40
|
+
readonly trailingSection: S | undefined;
|
|
41
|
+
}
|
|
30
42
|
/** `<ng-template sectionHeader let-section>`: RN's `renderSectionHeader`. */
|
|
31
43
|
export declare class SectionHeader<S = unknown> {
|
|
32
44
|
readonly template: TemplateRef<SectionContext<S>>;
|
|
@@ -55,21 +67,42 @@ export declare class SectionSeparator<T = unknown, S = unknown> {
|
|
|
55
67
|
static ɵfac: i0.ɵɵFactoryDeclaration<SectionSeparator<any, any>, never>;
|
|
56
68
|
static ɵdir: i0.ɵɵDirectiveDeclaration<SectionSeparator<any, any>, "ng-template[sectionSeparator]", never, {}, {}, never, never, true, never>;
|
|
57
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* `<ng-template sectionEdgeSeparator let-section>`: RN's `SectionSeparatorComponent`, drawn at
|
|
72
|
+
* both edges of a section that has items, between its header and first item and between its
|
|
73
|
+
* last item and footer.
|
|
74
|
+
*/
|
|
75
|
+
export declare class SectionEdgeSeparator<T = unknown, S = unknown> {
|
|
76
|
+
readonly template: TemplateRef<SectionEdgeSeparatorContext<T, S>>;
|
|
77
|
+
static ngTemplateContextGuard<T, S>(_directive: SectionEdgeSeparator<T, S>, context: unknown): context is SectionEdgeSeparatorContext<T, S>;
|
|
78
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SectionEdgeSeparator<any, any>, never>;
|
|
79
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<SectionEdgeSeparator<any, any>, "ng-template[sectionEdgeSeparator]", never, {}, {}, never, never, true, never>;
|
|
80
|
+
}
|
|
58
81
|
/** One row of the flattened list. */
|
|
59
82
|
export type SectionRow<T, S> = {
|
|
60
83
|
readonly kind: 'header' | 'footer';
|
|
61
84
|
readonly context: SectionContext<S>;
|
|
62
85
|
readonly separator: null;
|
|
86
|
+
readonly leading: null;
|
|
87
|
+
readonly trailing: null;
|
|
63
88
|
} | {
|
|
64
89
|
readonly kind: 'item';
|
|
65
90
|
readonly context: SectionItemContext<T, S>;
|
|
66
|
-
/** Null for a section's last item,
|
|
91
|
+
/** Null for a section's last item, where the section separator takes its place, as in RN. */
|
|
67
92
|
readonly separator: SectionSeparatorContext<T, S> | null;
|
|
93
|
+
/** The section separator before a section's first item, and null on every other. */
|
|
94
|
+
readonly leading: SectionEdgeSeparatorContext<T, S> | null;
|
|
95
|
+
/** The section separator after a section's last item, and null on every other. */
|
|
96
|
+
readonly trailing: SectionEdgeSeparatorContext<T, S> | null;
|
|
68
97
|
};
|
|
69
98
|
/**
|
|
70
99
|
* Flatten sections into the rows RN's `VirtualizedSectionList` gives its list: for each section a
|
|
71
100
|
* header, its items, then a footer. The header and footer rows are there whether or not anything
|
|
72
101
|
* is drawn in them, as in RN, which is what keeps `scrollToLocation`'s arithmetic the same.
|
|
102
|
+
*
|
|
103
|
+
* The section separators ride on the first and last item, as RN's do: `SectionSeparatorComponent`
|
|
104
|
+
* is the first item's leading separator and the last item's trailing one, so an empty section has
|
|
105
|
+
* none, and a last item has it in place of the item separator.
|
|
73
106
|
*/
|
|
74
107
|
export declare function flattenSections<T, S extends SectionListSection<T>>(sections: readonly S[]): SectionRow<T, S>[];
|
|
75
108
|
type Height<A extends unknown[]> = number | ((...args: A) => number);
|
|
@@ -85,23 +118,26 @@ type Height<A extends unknown[]> = number | ((...args: A) => number);
|
|
|
85
118
|
* <ng-template sectionHeader let-section><text>{{ section.title }}</text></ng-template>
|
|
86
119
|
* <ng-template sectionItem let-item><text>{{ item }}</text></ng-template>
|
|
87
120
|
* <ng-template sectionSeparator><view [style]="line"></view></ng-template>
|
|
121
|
+
* <ng-template sectionEdgeSeparator><view [style]="rule"></view></ng-template>
|
|
88
122
|
* </section-list>
|
|
89
123
|
* ```
|
|
90
124
|
*
|
|
91
125
|
* Rows are fixed height, as `getItemLayout` makes them in RN: `itemHeight`, `sectionHeaderHeight`
|
|
92
|
-
* and `sectionFooterHeight` are numbers or functions. An item's height includes its
|
|
93
|
-
* which
|
|
126
|
+
* and `sectionFooterHeight` are numbers or functions. An item's height includes its separators,
|
|
127
|
+
* which are drawn in the item's slot: the item separator at its bottom, only between items of the
|
|
128
|
+
* same section, and the section separator at the top of a section's first item and the bottom of
|
|
129
|
+
* its last, as RN's `SectionSeparatorComponent` is.
|
|
94
130
|
*
|
|
95
131
|
* `stickySectionHeadersEnabled` pins the current section's header until the next pushes it off.
|
|
96
132
|
* It defaults to on for iOS and off for Android, as RN's does. `listHeader` and `listFooter`
|
|
97
133
|
* content and a `<refresh-control>` pass through to the list.
|
|
98
134
|
*
|
|
99
|
-
* ponytail: no `
|
|
100
|
-
*
|
|
135
|
+
* ponytail: no `horizontal` or `inverted`, no viewability events, and no `highlighted` on a
|
|
136
|
+
* separator. The host is a plain view with the list filling it, where RN's host is the scroll view.
|
|
101
137
|
*/
|
|
102
138
|
export declare class SectionList<T, S extends SectionListSection<T> = SectionListSection<T>> {
|
|
103
139
|
readonly sections: import("@angular/core").InputSignal<readonly S[]>;
|
|
104
|
-
/** Each item's height, separator
|
|
140
|
+
/** Each item's height, including every separator drawn in its slot. */
|
|
105
141
|
readonly itemHeight: import("@angular/core").InputSignal<Height<[item: T, index: number, section: S]>>;
|
|
106
142
|
readonly sectionHeaderHeight: import("@angular/core").InputSignal<Height<[section: S]>>;
|
|
107
143
|
readonly sectionFooterHeight: import("@angular/core").InputSignal<Height<[section: S]>>;
|
|
@@ -117,11 +153,12 @@ export declare class SectionList<T, S extends SectionListSection<T> = SectionLis
|
|
|
117
153
|
protected readonly footer: import("@angular/core").Signal<SectionFooter<S> | undefined>;
|
|
118
154
|
protected readonly item: import("@angular/core").Signal<SectionItem<T, S> | undefined>;
|
|
119
155
|
protected readonly separator: import("@angular/core").Signal<SectionSeparator<T, S> | undefined>;
|
|
156
|
+
protected readonly edge: import("@angular/core").Signal<SectionEdgeSeparator<T, S> | undefined>;
|
|
120
157
|
private readonly list;
|
|
121
158
|
protected readonly fill: {
|
|
122
159
|
flex: number;
|
|
123
160
|
};
|
|
124
|
-
/** The item fills its slot
|
|
161
|
+
/** The item fills its slot between its separators, as RN's cell draws them around it. */
|
|
125
162
|
protected readonly cell: {
|
|
126
163
|
flex: number;
|
|
127
164
|
};
|
|
@@ -141,6 +178,6 @@ export declare class SectionList<T, S extends SectionListSection<T> = SectionLis
|
|
|
141
178
|
animated?: boolean;
|
|
142
179
|
}): void;
|
|
143
180
|
static ɵfac: i0.ɵɵFactoryDeclaration<SectionList<any, any>, never>;
|
|
144
|
-
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"], ["refresh-control", "[listHeader]", "*", "[listFooter]"], true, 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>;
|
|
145
182
|
}
|
|
146
183
|
export {};
|
package/dist/section-list.js
CHANGED
|
@@ -57,28 +57,59 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImpor
|
|
|
57
57
|
type: Directive,
|
|
58
58
|
args: [{ selector: 'ng-template[sectionSeparator]' }]
|
|
59
59
|
}] });
|
|
60
|
+
/**
|
|
61
|
+
* `<ng-template sectionEdgeSeparator let-section>`: RN's `SectionSeparatorComponent`, drawn at
|
|
62
|
+
* both edges of a section that has items, between its header and first item and between its
|
|
63
|
+
* last item and footer.
|
|
64
|
+
*/
|
|
65
|
+
export class SectionEdgeSeparator {
|
|
66
|
+
template = inject(TemplateRef);
|
|
67
|
+
static ngTemplateContextGuard(_directive, context) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: SectionEdgeSeparator, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
71
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.2.0", type: SectionEdgeSeparator, isStandalone: true, selector: "ng-template[sectionEdgeSeparator]", ngImport: i0 });
|
|
72
|
+
}
|
|
73
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: SectionEdgeSeparator, decorators: [{
|
|
74
|
+
type: Directive,
|
|
75
|
+
args: [{ selector: 'ng-template[sectionEdgeSeparator]' }]
|
|
76
|
+
}] });
|
|
60
77
|
/**
|
|
61
78
|
* Flatten sections into the rows RN's `VirtualizedSectionList` gives its list: for each section a
|
|
62
79
|
* header, its items, then a footer. The header and footer rows are there whether or not anything
|
|
63
80
|
* is drawn in them, as in RN, which is what keeps `scrollToLocation`'s arithmetic the same.
|
|
81
|
+
*
|
|
82
|
+
* The section separators ride on the first and last item, as RN's do: `SectionSeparatorComponent`
|
|
83
|
+
* is the first item's leading separator and the last item's trailing one, so an empty section has
|
|
84
|
+
* none, and a last item has it in place of the item separator.
|
|
64
85
|
*/
|
|
65
86
|
export function flattenSections(sections) {
|
|
66
87
|
const rows = [];
|
|
88
|
+
const edges = { leading: null, trailing: null };
|
|
67
89
|
sections.forEach((section, sectionIndex) => {
|
|
68
90
|
const context = { $implicit: section, section, sectionIndex };
|
|
69
|
-
rows.push({ kind: 'header', context, separator: null });
|
|
91
|
+
rows.push({ kind: 'header', context, separator: null, ...edges });
|
|
70
92
|
const data = section.data;
|
|
93
|
+
const last = data.length - 1;
|
|
94
|
+
const around = {
|
|
95
|
+
$implicit: section,
|
|
96
|
+
section,
|
|
97
|
+
leadingSection: sections[sectionIndex - 1],
|
|
98
|
+
trailingSection: sections[sectionIndex + 1],
|
|
99
|
+
};
|
|
71
100
|
data.forEach((item, index) => {
|
|
72
101
|
const trailingItem = data[index + 1];
|
|
73
102
|
rows.push({
|
|
74
103
|
kind: 'item',
|
|
75
104
|
context: { $implicit: item, item, index, section, sectionIndex },
|
|
76
|
-
separator: index <
|
|
105
|
+
separator: index < last
|
|
77
106
|
? { $implicit: item, leadingItem: item, trailingItem: trailingItem, section }
|
|
78
107
|
: null,
|
|
108
|
+
leading: index === 0 ? { ...around, leadingItem: undefined, trailingItem: item } : null,
|
|
109
|
+
trailing: index === last ? { ...around, leadingItem: item, trailingItem: undefined } : null,
|
|
79
110
|
});
|
|
80
111
|
});
|
|
81
|
-
rows.push({ kind: 'footer', context, separator: null });
|
|
112
|
+
rows.push({ kind: 'footer', context, separator: null, ...edges });
|
|
82
113
|
});
|
|
83
114
|
return rows;
|
|
84
115
|
}
|
|
@@ -95,24 +126,27 @@ const measure = (height, ...args) => typeof height === 'number' ? height : heigh
|
|
|
95
126
|
* <ng-template sectionHeader let-section><text>{{ section.title }}</text></ng-template>
|
|
96
127
|
* <ng-template sectionItem let-item><text>{{ item }}</text></ng-template>
|
|
97
128
|
* <ng-template sectionSeparator><view [style]="line"></view></ng-template>
|
|
129
|
+
* <ng-template sectionEdgeSeparator><view [style]="rule"></view></ng-template>
|
|
98
130
|
* </section-list>
|
|
99
131
|
* ```
|
|
100
132
|
*
|
|
101
133
|
* Rows are fixed height, as `getItemLayout` makes them in RN: `itemHeight`, `sectionHeaderHeight`
|
|
102
|
-
* and `sectionFooterHeight` are numbers or functions. An item's height includes its
|
|
103
|
-
* which
|
|
134
|
+
* and `sectionFooterHeight` are numbers or functions. An item's height includes its separators,
|
|
135
|
+
* which are drawn in the item's slot: the item separator at its bottom, only between items of the
|
|
136
|
+
* same section, and the section separator at the top of a section's first item and the bottom of
|
|
137
|
+
* its last, as RN's `SectionSeparatorComponent` is.
|
|
104
138
|
*
|
|
105
139
|
* `stickySectionHeadersEnabled` pins the current section's header until the next pushes it off.
|
|
106
140
|
* It defaults to on for iOS and off for Android, as RN's does. `listHeader` and `listFooter`
|
|
107
141
|
* content and a `<refresh-control>` pass through to the list.
|
|
108
142
|
*
|
|
109
|
-
* ponytail: no `
|
|
110
|
-
*
|
|
143
|
+
* ponytail: no `horizontal` or `inverted`, no viewability events, and no `highlighted` on a
|
|
144
|
+
* separator. The host is a plain view with the list filling it, where RN's host is the scroll view.
|
|
111
145
|
*/
|
|
112
146
|
export class SectionList {
|
|
113
147
|
sections = input.required(/* @ts-ignore */
|
|
114
148
|
...(ngDevMode ? [{ debugName: "sections" }] : /* istanbul ignore next */ []));
|
|
115
|
-
/** Each item's height, separator
|
|
149
|
+
/** Each item's height, including every separator drawn in its slot. */
|
|
116
150
|
itemHeight = input.required(/* @ts-ignore */
|
|
117
151
|
...(ngDevMode ? [{ debugName: "itemHeight" }] : /* istanbul ignore next */ []));
|
|
118
152
|
sectionHeaderHeight = input(0, /* @ts-ignore */
|
|
@@ -133,10 +167,12 @@ export class SectionList {
|
|
|
133
167
|
...(ngDevMode ? [{ debugName: "item" }] : /* istanbul ignore next */ []));
|
|
134
168
|
separator = contentChild(SectionSeparator, /* @ts-ignore */
|
|
135
169
|
...(ngDevMode ? [{ debugName: "separator" }] : /* istanbul ignore next */ []));
|
|
170
|
+
edge = contentChild(SectionEdgeSeparator, /* @ts-ignore */
|
|
171
|
+
...(ngDevMode ? [{ debugName: "edge" }] : /* istanbul ignore next */ []));
|
|
136
172
|
list = viewChild.required('list', /* @ts-ignore */
|
|
137
173
|
...(ngDevMode ? [{ debugName: "list" }] : /* istanbul ignore next */ []));
|
|
138
174
|
fill = { flex: 1 };
|
|
139
|
-
/** The item fills its slot
|
|
175
|
+
/** The item fills its slot between its separators, as RN's cell draws them around it. */
|
|
140
176
|
cell = { flex: 1 };
|
|
141
177
|
rows = computed(() => flattenSections(this.sections()), /* @ts-ignore */
|
|
142
178
|
...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
|
|
@@ -180,7 +216,7 @@ export class SectionList {
|
|
|
180
216
|
this.list().scrollToIndex({ index, viewOffset, animated: options.animated });
|
|
181
217
|
}
|
|
182
218
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: SectionList, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
183
|
-
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 }], viewQueries: [{ propertyName: "list", first: true, predicate: ["list"], descendants: true, isSignal: true }], exportAs: ["sectionList"], ngImport: i0, template: `
|
|
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: `
|
|
184
220
|
<virtual-list
|
|
185
221
|
#list
|
|
186
222
|
[items]="rows()"
|
|
@@ -214,6 +250,11 @@ export class SectionList {
|
|
|
214
250
|
}
|
|
215
251
|
}
|
|
216
252
|
@case ('item') {
|
|
253
|
+
@if (row.item.leading; as start) {
|
|
254
|
+
@if (edge(); as edge) {
|
|
255
|
+
<ng-container [templateSlot]="edge.template" [templateSlotContext]="start" />
|
|
256
|
+
}
|
|
257
|
+
}
|
|
217
258
|
<view [style]="cell">
|
|
218
259
|
@if (item(); as item) {
|
|
219
260
|
<ng-container
|
|
@@ -227,6 +268,11 @@ export class SectionList {
|
|
|
227
268
|
<ng-container [templateSlot]="separator.template" [templateSlotContext]="gap" />
|
|
228
269
|
}
|
|
229
270
|
}
|
|
271
|
+
@if (row.item.trailing; as end) {
|
|
272
|
+
@if (edge(); as edge) {
|
|
273
|
+
<ng-container [templateSlot]="edge.template" [templateSlotContext]="end" />
|
|
274
|
+
}
|
|
275
|
+
}
|
|
230
276
|
}
|
|
231
277
|
}
|
|
232
278
|
</view>
|
|
@@ -275,6 +321,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImpor
|
|
|
275
321
|
}
|
|
276
322
|
}
|
|
277
323
|
@case ('item') {
|
|
324
|
+
@if (row.item.leading; as start) {
|
|
325
|
+
@if (edge(); as edge) {
|
|
326
|
+
<ng-container [templateSlot]="edge.template" [templateSlotContext]="start" />
|
|
327
|
+
}
|
|
328
|
+
}
|
|
278
329
|
<view [style]="cell">
|
|
279
330
|
@if (item(); as item) {
|
|
280
331
|
<ng-container
|
|
@@ -288,6 +339,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImpor
|
|
|
288
339
|
<ng-container [templateSlot]="separator.template" [templateSlotContext]="gap" />
|
|
289
340
|
}
|
|
290
341
|
}
|
|
342
|
+
@if (row.item.trailing; as end) {
|
|
343
|
+
@if (edge(); as edge) {
|
|
344
|
+
<ng-container [templateSlot]="edge.template" [templateSlotContext]="end" />
|
|
345
|
+
}
|
|
346
|
+
}
|
|
291
347
|
}
|
|
292
348
|
}
|
|
293
349
|
</view>
|
|
@@ -296,5 +352,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImpor
|
|
|
296
352
|
</virtual-list>
|
|
297
353
|
`,
|
|
298
354
|
}]
|
|
299
|
-
}], 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 }] }], list: [{ type: i0.ViewChild, args: ['list', { isSignal: true }] }] } });
|
|
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 }] }] } });
|
|
300
356
|
//# 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/** `<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/** 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 }\n | {\n readonly kind: 'item';\n readonly context: SectionItemContext<T, S>;\n /** Null for a section's last item, which RN draws no separator after. */\n readonly separator: SectionSeparatorContext<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 */\nexport function flattenSections<T, S extends SectionListSection<T>>(\n sections: readonly S[],\n): SectionRow<T, S>[] {\n const rows: SectionRow<T, S>[] = [];\n sections.forEach((section, sectionIndex) => {\n const context = { $implicit: section, section, sectionIndex };\n rows.push({ kind: 'header', context, separator: null });\n const data = section.data;\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 < data.length - 1\n ? { $implicit: item, leadingItem: item, trailingItem: trailingItem!, section }\n : null,\n });\n });\n rows.push({ kind: 'footer', context, separator: null });\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 * </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 separator,\n * which is drawn at the bottom of the item's slot and only between items of the same section.\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 `SectionSeparatorComponent`, no `horizontal` or `inverted`, and no viewability\n * events. 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 <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 }\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, separator included. */\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 private readonly list = viewChild.required<VirtualList<SectionRow<T, S>>>('list');\n\n protected readonly fill = { flex: 1 };\n /** The item fills its slot above the separator, as RN's cell puts the separator after 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 { 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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ng-native/components",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Angular Native's core components: view, text, image, pressable, scroll-view, virtual-list, text-input and the rest of React Native's set.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"angular",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@ng-native/
|
|
43
|
-
"@ng-native/
|
|
42
|
+
"@ng-native/fabric": "0.1.2",
|
|
43
|
+
"@ng-native/device": "0.1.2"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"@angular/core": "^22.0.0",
|