mtrl-addons 0.5.3 → 0.5.4
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/components/vlist/features/filter.d.ts +116 -0
- package/dist/components/vlist/features/index.d.ts +12 -0
- package/dist/components/vlist/features/layout.d.ts +66 -0
- package/dist/components/vlist/features/scroll-restore.d.ts +120 -0
- package/dist/components/vlist/features/search.d.ts +98 -0
- package/dist/components/vlist/features/stats.d.ts +119 -0
- package/dist/components/vlist/features/velocity.d.ts +124 -0
- package/dist/components/vlist/features/viewport.d.ts +8 -0
- package/dist/components/vlist/index.d.ts +54 -0
- package/dist/components/vlist/types.d.ts +198 -0
- package/dist/components/vlist/vlist.d.ts +90 -15
- package/dist/core/viewport/features/collection.d.ts +6 -0
- package/dist/index.js +1587 -167
- package/dist/index.mjs +1587 -167
- package/dist/styles.css +147 -0
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
- package/src/styles/components/_vlist.scss +219 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filter feature for VList
|
|
3
|
+
*
|
|
4
|
+
* Provides generic, layout-agnostic filter functionality that works with
|
|
5
|
+
* any layout structure and any filter controls. The feature references
|
|
6
|
+
* layout elements by name and handles filter state, events, and integration
|
|
7
|
+
* with the collection adapter.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* const vlist = createVList({
|
|
12
|
+
* layout: [
|
|
13
|
+
* ['head', { class: 'head' },
|
|
14
|
+
* [createIconButton, 'filter-toggle', { icon: iconFilter, toggle: true }]
|
|
15
|
+
* ],
|
|
16
|
+
* ['filters', { class: 'filter-panel' },
|
|
17
|
+
* [createSelect, 'country-select', { options: countries }],
|
|
18
|
+
* [createSelect, 'decade-select', { options: decades }],
|
|
19
|
+
* [Button, 'clear-btn', { icon: iconCancel }]
|
|
20
|
+
* ],
|
|
21
|
+
* ['viewport'],
|
|
22
|
+
* ],
|
|
23
|
+
*
|
|
24
|
+
* filter: {
|
|
25
|
+
* toggleButton: 'filter-toggle',
|
|
26
|
+
* panel: 'filters',
|
|
27
|
+
* clearButton: 'clear-btn',
|
|
28
|
+
* controls: {
|
|
29
|
+
* country: 'country-select',
|
|
30
|
+
* decade: 'decade-select',
|
|
31
|
+
* },
|
|
32
|
+
* },
|
|
33
|
+
*
|
|
34
|
+
* collection: {
|
|
35
|
+
* adapter: {
|
|
36
|
+
* read: async ({ page, limit, filters }) => {
|
|
37
|
+
* let url = `/api/items?page=${page}&limit=${limit}`
|
|
38
|
+
* if (filters?.country) url += `&country=${filters.country}`
|
|
39
|
+
* if (filters?.decade) url += `&decade=${filters.decade}`
|
|
40
|
+
* return fetch(url).then(r => r.json())
|
|
41
|
+
* }
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
* })
|
|
45
|
+
*
|
|
46
|
+
* // Events
|
|
47
|
+
* vlist.on('filter:open', () => console.log('Filter panel opened'))
|
|
48
|
+
* vlist.on('filter:change', ({ name, value, filters }) => console.log('Filter changed:', name, value))
|
|
49
|
+
* vlist.on('filter:clear', () => console.log('Filters cleared'))
|
|
50
|
+
*
|
|
51
|
+
* // API
|
|
52
|
+
* vlist.setFilter('country', 'FR')
|
|
53
|
+
* vlist.setFilters({ country: 'FR', decade: '1980' })
|
|
54
|
+
* vlist.clearFilters()
|
|
55
|
+
* console.log(vlist.getFilters())
|
|
56
|
+
* console.log(vlist.getFilter('country'))
|
|
57
|
+
* console.log(vlist.isFiltered())
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
import type { VListConfig, VListItem } from "../types";
|
|
61
|
+
/**
|
|
62
|
+
* Filter configuration
|
|
63
|
+
*/
|
|
64
|
+
export interface FilterConfig {
|
|
65
|
+
/** Layout element name for toggle button */
|
|
66
|
+
toggleButton?: string;
|
|
67
|
+
/** Layout element name for filter panel container */
|
|
68
|
+
panel?: string;
|
|
69
|
+
/** Layout element name for clear all filters button */
|
|
70
|
+
clearButton?: string;
|
|
71
|
+
/** Map of filter name to layout element name */
|
|
72
|
+
controls?: Record<string, string>;
|
|
73
|
+
/** Automatically reload on filter change (default: true) */
|
|
74
|
+
autoReload?: boolean;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Adds filter functionality to VList component
|
|
78
|
+
*
|
|
79
|
+
* This feature:
|
|
80
|
+
* 1. Connects to layout elements by name (toggle button, panel, controls)
|
|
81
|
+
* 2. Manages filter state
|
|
82
|
+
* 3. Emits events for app-specific handling
|
|
83
|
+
* 4. Provides API methods for programmatic control
|
|
84
|
+
* 5. Triggers list reload on filter changes (configurable)
|
|
85
|
+
*
|
|
86
|
+
* @param config - VList configuration with filter options
|
|
87
|
+
* @returns Feature function that enhances the VList component
|
|
88
|
+
*/
|
|
89
|
+
export declare const withFilter: <T extends VListItem = VListItem>(config: VListConfig<T> & {
|
|
90
|
+
filter?: FilterConfig;
|
|
91
|
+
}) => (component: any) => any;
|
|
92
|
+
/**
|
|
93
|
+
* Type helper for VList with filter
|
|
94
|
+
*/
|
|
95
|
+
export interface WithFilterComponent {
|
|
96
|
+
/** Set a single filter value */
|
|
97
|
+
setFilter(name: string, value: any): void;
|
|
98
|
+
/** Set multiple filters at once */
|
|
99
|
+
setFilters(filters: Record<string, any>): void;
|
|
100
|
+
/** Clear all filters */
|
|
101
|
+
clearFilters(): void;
|
|
102
|
+
/** Get all current filters */
|
|
103
|
+
getFilters(): Record<string, any>;
|
|
104
|
+
/** Get a single filter value */
|
|
105
|
+
getFilter(name: string): any;
|
|
106
|
+
/** Check if any filter is active */
|
|
107
|
+
isFiltered(): boolean;
|
|
108
|
+
/** Check if filter panel is open */
|
|
109
|
+
isFilterOpen(): boolean;
|
|
110
|
+
/** Open the filter panel */
|
|
111
|
+
openFilter(): void;
|
|
112
|
+
/** Close the filter panel */
|
|
113
|
+
closeFilter(): void;
|
|
114
|
+
/** Toggle filter panel visibility */
|
|
115
|
+
toggleFilter(): void;
|
|
116
|
+
}
|
|
@@ -6,3 +6,15 @@
|
|
|
6
6
|
export { withViewport } from "./viewport";
|
|
7
7
|
export { withAPI } from "./api";
|
|
8
8
|
export { withSelection } from "./selection";
|
|
9
|
+
export { withLayout } from "./layout";
|
|
10
|
+
export { withSearch } from "./search";
|
|
11
|
+
export { withFilter } from "./filter";
|
|
12
|
+
export { withStats } from "./stats";
|
|
13
|
+
export { withVelocity } from "./velocity";
|
|
14
|
+
export { withScrollRestore } from "./scroll-restore";
|
|
15
|
+
export type { LayoutSchema, LayoutResult, WithLayoutComponent } from "./layout";
|
|
16
|
+
export type { SearchConfig, WithSearchComponent } from "./search";
|
|
17
|
+
export type { FilterConfig, WithFilterComponent } from "./filter";
|
|
18
|
+
export type { StatsConfig, WithStatsComponent } from "./stats";
|
|
19
|
+
export type { VelocityConfig, WithVelocityComponent } from "./velocity";
|
|
20
|
+
export type { ScrollRestoreConfig, PendingScrollPosition, PendingScrollLookup, WithScrollRestoreComponent, } from "./scroll-restore";
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout feature for VList
|
|
3
|
+
*
|
|
4
|
+
* Processes a layout schema and builds the complete UI structure around
|
|
5
|
+
* the virtual scrolling viewport. This enables VList to manage its own
|
|
6
|
+
* layout (header, filters, search, viewport, footer) without requiring
|
|
7
|
+
* a complex wrapper with functional composition.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* const vlist = createVList({
|
|
12
|
+
* container: document.getElementById('app'),
|
|
13
|
+
* class: 'users',
|
|
14
|
+
* layout: [
|
|
15
|
+
* ['head', { class: 'head' },
|
|
16
|
+
* ['title', { text: 'Users' }]
|
|
17
|
+
* ],
|
|
18
|
+
* ['viewport'],
|
|
19
|
+
* ['foot', { class: 'foot' },
|
|
20
|
+
* ['count', { text: '0' }]
|
|
21
|
+
* ]
|
|
22
|
+
* ],
|
|
23
|
+
* template: userTemplate,
|
|
24
|
+
* collection: { adapter: { read: fetchUsers } }
|
|
25
|
+
* })
|
|
26
|
+
*
|
|
27
|
+
* // Access layout elements via flat map
|
|
28
|
+
* vlist.layout.title.textContent = 'Users (1,245)'
|
|
29
|
+
* vlist.layout.count.textContent = '1,245'
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
import type { VListConfig, VListItem } from "../types";
|
|
33
|
+
/**
|
|
34
|
+
* Layout schema type - array-based schema compatible with createLayout
|
|
35
|
+
*/
|
|
36
|
+
export type LayoutSchema = any[];
|
|
37
|
+
/**
|
|
38
|
+
* Layout result - flat map of all named elements from the layout
|
|
39
|
+
*/
|
|
40
|
+
export interface LayoutResult {
|
|
41
|
+
[key: string]: any;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Adds layout functionality to VList
|
|
45
|
+
*
|
|
46
|
+
* This feature:
|
|
47
|
+
* 1. Processes the layout schema using createLayout
|
|
48
|
+
* 2. Renders the layout inside the VList's root element
|
|
49
|
+
* 3. Finds the 'viewport' element where virtual scrolling will render
|
|
50
|
+
* 4. Exposes all named elements via vlist.layout flat map
|
|
51
|
+
*
|
|
52
|
+
* @param config - VList configuration with optional layout schema
|
|
53
|
+
* @returns Feature function that enhances the VList component
|
|
54
|
+
*/
|
|
55
|
+
export declare const withLayout: <T extends VListItem = VListItem>(config: VListConfig<T> & {
|
|
56
|
+
layout?: LayoutSchema;
|
|
57
|
+
}) => (component: any) => any;
|
|
58
|
+
/**
|
|
59
|
+
* Type helper for VList with layout
|
|
60
|
+
*/
|
|
61
|
+
export interface WithLayoutComponent {
|
|
62
|
+
/** Flat map of all named layout elements */
|
|
63
|
+
layout: LayoutResult;
|
|
64
|
+
/** Get a specific layout element by name */
|
|
65
|
+
getLayoutElement(name: string): any;
|
|
66
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scroll Restore feature for VList
|
|
3
|
+
*
|
|
4
|
+
* Provides a mechanism to queue a pending scroll position and selection
|
|
5
|
+
* that gets executed on the next reload. Useful for restoring list state
|
|
6
|
+
* after navigation, filter changes, or other operations that cause a reload.
|
|
7
|
+
*
|
|
8
|
+
* This feature works with VList's `reloadAt()` method, providing a convenient
|
|
9
|
+
* API for queuing scroll restoration that automatically executes on reload.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const vlist = createVList({
|
|
14
|
+
* layout: [...],
|
|
15
|
+
* scrollRestore: {
|
|
16
|
+
* enabled: true,
|
|
17
|
+
* // Optional: auto-clear pending after successful restore
|
|
18
|
+
* autoClear: true,
|
|
19
|
+
* },
|
|
20
|
+
* collection: { ... }
|
|
21
|
+
* })
|
|
22
|
+
*
|
|
23
|
+
* // Queue a scroll restoration before triggering a reload
|
|
24
|
+
* vlist.setPendingScroll({
|
|
25
|
+
* position: 100, // Scroll to index 100
|
|
26
|
+
* selectId: 'item-123', // Select this item after scroll
|
|
27
|
+
* })
|
|
28
|
+
*
|
|
29
|
+
* // On next reload(), the pending scroll will be applied
|
|
30
|
+
* await vlist.reload() // Will use reloadAt(100, 'item-123')
|
|
31
|
+
*
|
|
32
|
+
* // Alternative: queue scroll with position lookup callback
|
|
33
|
+
* vlist.setPendingScrollWithLookup({
|
|
34
|
+
* id: 'user-456',
|
|
35
|
+
* lookupPosition: async (id) => {
|
|
36
|
+
* const response = await fetch(`/api/users/position?id=${id}`)
|
|
37
|
+
* const data = await response.json()
|
|
38
|
+
* return data.position
|
|
39
|
+
* }
|
|
40
|
+
* })
|
|
41
|
+
*
|
|
42
|
+
* // Events
|
|
43
|
+
* vlist.on('scroll-restore:pending', ({ position, selectId }) => {
|
|
44
|
+
* console.log('Scroll restore queued')
|
|
45
|
+
* })
|
|
46
|
+
*
|
|
47
|
+
* vlist.on('scroll-restore:applied', ({ position, selectId }) => {
|
|
48
|
+
* console.log('Scroll restore applied')
|
|
49
|
+
* })
|
|
50
|
+
*
|
|
51
|
+
* vlist.on('scroll-restore:cleared', () => {
|
|
52
|
+
* console.log('Pending scroll cleared')
|
|
53
|
+
* })
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
import type { VListConfig, VListItem } from "../types";
|
|
57
|
+
/**
|
|
58
|
+
* Scroll restore configuration
|
|
59
|
+
*/
|
|
60
|
+
export interface ScrollRestoreConfig {
|
|
61
|
+
/** Whether scroll restore is enabled (default: true) */
|
|
62
|
+
enabled?: boolean;
|
|
63
|
+
/** Auto-clear pending scroll after successful restore (default: true) */
|
|
64
|
+
autoClear?: boolean;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Pending scroll with pre-calculated position
|
|
68
|
+
*/
|
|
69
|
+
export interface PendingScrollPosition {
|
|
70
|
+
/** The index position to scroll to */
|
|
71
|
+
position: number;
|
|
72
|
+
/** Optional ID of item to select after scroll */
|
|
73
|
+
selectId?: string | number;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Pending scroll with position lookup
|
|
77
|
+
*/
|
|
78
|
+
export interface PendingScrollLookup {
|
|
79
|
+
/** The ID to look up position for */
|
|
80
|
+
id: string | number;
|
|
81
|
+
/** Alternative ID for position lookup (e.g., different ID format) */
|
|
82
|
+
altId?: string | number;
|
|
83
|
+
/** Async function to look up position from ID */
|
|
84
|
+
lookupPosition: (id: string | number) => Promise<number>;
|
|
85
|
+
/** Fallback position if lookup fails (default: 0) */
|
|
86
|
+
fallbackPosition?: number;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Adds scroll restore functionality to VList component
|
|
90
|
+
*
|
|
91
|
+
* This feature:
|
|
92
|
+
* 1. Provides API to queue pending scroll position/selection
|
|
93
|
+
* 2. Intercepts reload to apply pending scroll via reloadAt()
|
|
94
|
+
* 3. Supports both pre-calculated positions and position lookups
|
|
95
|
+
* 4. Emits events for tracking scroll restore state
|
|
96
|
+
* 5. Auto-clears pending state after successful restore (configurable)
|
|
97
|
+
*
|
|
98
|
+
* @param config - VList configuration with scrollRestore options
|
|
99
|
+
* @returns Feature function that enhances the VList component
|
|
100
|
+
*/
|
|
101
|
+
export declare const withScrollRestore: <T extends VListItem = VListItem>(config: VListConfig<T> & {
|
|
102
|
+
scrollRestore?: ScrollRestoreConfig;
|
|
103
|
+
}) => (component: any) => any;
|
|
104
|
+
/**
|
|
105
|
+
* Type helper for VList with scroll restore
|
|
106
|
+
*/
|
|
107
|
+
export interface WithScrollRestoreComponent {
|
|
108
|
+
/** Set pending scroll with pre-calculated position */
|
|
109
|
+
setPendingScroll(pending: PendingScrollPosition): void;
|
|
110
|
+
/** Set pending scroll with position lookup */
|
|
111
|
+
setPendingScrollWithLookup(pending: PendingScrollLookup): void;
|
|
112
|
+
/** Clear any pending scroll */
|
|
113
|
+
clearPendingScroll(): void;
|
|
114
|
+
/** Check if there's a pending scroll */
|
|
115
|
+
hasPendingScroll(): boolean;
|
|
116
|
+
/** Get pending scroll info */
|
|
117
|
+
getPendingScroll(): PendingScrollPosition | PendingScrollLookup | null;
|
|
118
|
+
/** Force apply pending scroll immediately */
|
|
119
|
+
applyPendingScrollNow(): Promise<void>;
|
|
120
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search feature for VList
|
|
3
|
+
*
|
|
4
|
+
* Provides generic, layout-agnostic search functionality that works with
|
|
5
|
+
* any layout structure. The feature references layout elements by name
|
|
6
|
+
* and handles search state, events, and integration with the collection adapter.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const vlist = createVList({
|
|
11
|
+
* layout: [
|
|
12
|
+
* ['head', { class: 'head' },
|
|
13
|
+
* [createIconButton, 'search-toggle', { icon: iconSearch, toggle: true }]
|
|
14
|
+
* ],
|
|
15
|
+
* [createSearch, 'search-input', { placeholder: 'Search...' }],
|
|
16
|
+
* ['viewport'],
|
|
17
|
+
* ],
|
|
18
|
+
*
|
|
19
|
+
* search: {
|
|
20
|
+
* toggleButton: 'search-toggle',
|
|
21
|
+
* searchBar: 'search-input',
|
|
22
|
+
* debounce: 300,
|
|
23
|
+
* },
|
|
24
|
+
*
|
|
25
|
+
* collection: {
|
|
26
|
+
* adapter: {
|
|
27
|
+
* read: async ({ page, limit, search }) => {
|
|
28
|
+
* let url = `/api/items?page=${page}&limit=${limit}`
|
|
29
|
+
* if (search) url += `&q=${encodeURIComponent(search)}`
|
|
30
|
+
* return fetch(url).then(r => r.json())
|
|
31
|
+
* }
|
|
32
|
+
* }
|
|
33
|
+
* }
|
|
34
|
+
* })
|
|
35
|
+
*
|
|
36
|
+
* // Events
|
|
37
|
+
* vlist.on('search:open', () => console.log('Search opened'))
|
|
38
|
+
* vlist.on('search:change', ({ query }) => console.log('Searching:', query))
|
|
39
|
+
*
|
|
40
|
+
* // API
|
|
41
|
+
* vlist.search('john')
|
|
42
|
+
* vlist.clearSearch()
|
|
43
|
+
* console.log(vlist.getSearchQuery())
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
import type { VListConfig, VListItem } from "../types";
|
|
47
|
+
/**
|
|
48
|
+
* Search configuration
|
|
49
|
+
*/
|
|
50
|
+
export interface SearchConfig {
|
|
51
|
+
/** Layout element name for toggle button */
|
|
52
|
+
toggleButton?: string;
|
|
53
|
+
/** Layout element name for search input/bar */
|
|
54
|
+
searchBar?: string;
|
|
55
|
+
/** Automatically reload on search change (default: true) */
|
|
56
|
+
autoReload?: boolean;
|
|
57
|
+
/** Debounce input in ms (default: 300) */
|
|
58
|
+
debounce?: number;
|
|
59
|
+
/** Minimum query length to trigger search (default: 1) */
|
|
60
|
+
minLength?: number;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Adds search functionality to VList component
|
|
64
|
+
*
|
|
65
|
+
* This feature:
|
|
66
|
+
* 1. Connects to layout elements by name (toggle button, search bar)
|
|
67
|
+
* 2. Manages search state (query, open/closed)
|
|
68
|
+
* 3. Emits events for app-specific handling
|
|
69
|
+
* 4. Provides API methods for programmatic control
|
|
70
|
+
* 5. Triggers list reload on search changes (configurable)
|
|
71
|
+
*
|
|
72
|
+
* @param config - VList configuration with search options
|
|
73
|
+
* @returns Feature function that enhances the VList component
|
|
74
|
+
*/
|
|
75
|
+
export declare const withSearch: <T extends VListItem = VListItem>(config: VListConfig<T> & {
|
|
76
|
+
search?: SearchConfig;
|
|
77
|
+
}) => (component: any) => any;
|
|
78
|
+
/**
|
|
79
|
+
* Type helper for VList with search
|
|
80
|
+
*/
|
|
81
|
+
export interface WithSearchComponent {
|
|
82
|
+
/** Set search query programmatically */
|
|
83
|
+
search(query: string): void;
|
|
84
|
+
/** Clear search query */
|
|
85
|
+
clearSearch(): void;
|
|
86
|
+
/** Get current search query */
|
|
87
|
+
getSearchQuery(): string;
|
|
88
|
+
/** Check if currently in search mode */
|
|
89
|
+
isSearching(): boolean;
|
|
90
|
+
/** Check if search bar is open */
|
|
91
|
+
isSearchOpen(): boolean;
|
|
92
|
+
/** Open the search bar */
|
|
93
|
+
openSearch(): void;
|
|
94
|
+
/** Close the search bar */
|
|
95
|
+
closeSearch(): void;
|
|
96
|
+
/** Toggle search bar visibility */
|
|
97
|
+
toggleSearch(): void;
|
|
98
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stats feature for VList
|
|
3
|
+
*
|
|
4
|
+
* Tracks list statistics (count, position, progress) and automatically
|
|
5
|
+
* updates layout elements. Provides a clean API for accessing stats and
|
|
6
|
+
* emits events when stats change.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const vlist = createVList({
|
|
11
|
+
* layout: [
|
|
12
|
+
* ['head', { class: 'head' },
|
|
13
|
+
* ['title', { text: 'Users' }]
|
|
14
|
+
* ],
|
|
15
|
+
* ['viewport'],
|
|
16
|
+
* ['foot', { class: 'foot' },
|
|
17
|
+
* ['position', { text: '0' }],
|
|
18
|
+
* ['slash', { text: '/' }],
|
|
19
|
+
* ['count', { text: '0' }],
|
|
20
|
+
* ['progress', { text: '0%' }]
|
|
21
|
+
* ]
|
|
22
|
+
* ],
|
|
23
|
+
*
|
|
24
|
+
* stats: {
|
|
25
|
+
* elements: {
|
|
26
|
+
* count: 'count',
|
|
27
|
+
* position: 'position',
|
|
28
|
+
* progress: 'progress'
|
|
29
|
+
* },
|
|
30
|
+
* format: {
|
|
31
|
+
* count: (n) => n.toLocaleString(),
|
|
32
|
+
* position: (n) => n.toLocaleString(),
|
|
33
|
+
* progress: (p) => `${p}%`
|
|
34
|
+
* }
|
|
35
|
+
* },
|
|
36
|
+
*
|
|
37
|
+
* collection: {
|
|
38
|
+
* adapter: {
|
|
39
|
+
* read: async ({ page, limit }) => {
|
|
40
|
+
* const response = await fetch(`/api/items?page=${page}&limit=${limit}`)
|
|
41
|
+
* return response.json()
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
* }
|
|
45
|
+
* })
|
|
46
|
+
*
|
|
47
|
+
* // Events
|
|
48
|
+
* vlist.on('stats:change', ({ count, position, progress }) => {
|
|
49
|
+
* console.log(`Viewing ${position} of ${count} (${progress}%)`)
|
|
50
|
+
* })
|
|
51
|
+
*
|
|
52
|
+
* // API
|
|
53
|
+
* const stats = vlist.getStats()
|
|
54
|
+
* console.log(stats.count, stats.position, stats.progress)
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
import type { VListConfig, VListItem } from "../types";
|
|
58
|
+
/**
|
|
59
|
+
* Stats configuration
|
|
60
|
+
*/
|
|
61
|
+
export interface StatsConfig {
|
|
62
|
+
/** Layout element names to update */
|
|
63
|
+
elements?: {
|
|
64
|
+
/** Element name for total count display */
|
|
65
|
+
count?: string;
|
|
66
|
+
/** Element name for current position display */
|
|
67
|
+
position?: string;
|
|
68
|
+
/** Element name for progress percentage display */
|
|
69
|
+
progress?: string;
|
|
70
|
+
};
|
|
71
|
+
/** Format functions for display values */
|
|
72
|
+
format?: {
|
|
73
|
+
/** Format count value (default: toLocaleString) */
|
|
74
|
+
count?: (count: number) => string;
|
|
75
|
+
/** Format position value (default: toLocaleString) */
|
|
76
|
+
position?: (position: number) => string;
|
|
77
|
+
/** Format progress value (default: `${p}%`) */
|
|
78
|
+
progress?: (percent: number) => string;
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Stats state
|
|
83
|
+
*/
|
|
84
|
+
interface StatsState {
|
|
85
|
+
count: number;
|
|
86
|
+
position: number;
|
|
87
|
+
progress: number;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Adds stats tracking functionality to VList component
|
|
91
|
+
*
|
|
92
|
+
* This feature:
|
|
93
|
+
* 1. Tracks count (total items), position (first visible item), and progress (scroll %)
|
|
94
|
+
* 2. Automatically updates layout elements when stats change
|
|
95
|
+
* 3. Emits 'stats:change' event for app-specific handling
|
|
96
|
+
* 4. Provides getStats() API for programmatic access
|
|
97
|
+
*
|
|
98
|
+
* @param config - VList configuration with stats options
|
|
99
|
+
* @returns Feature function that enhances the VList component
|
|
100
|
+
*/
|
|
101
|
+
export declare const withStats: <T extends VListItem = VListItem>(config: VListConfig<T> & {
|
|
102
|
+
stats?: StatsConfig;
|
|
103
|
+
}) => (component: any) => any;
|
|
104
|
+
/**
|
|
105
|
+
* Type helper for VList with stats
|
|
106
|
+
*/
|
|
107
|
+
export interface WithStatsComponent {
|
|
108
|
+
/** Get all current stats */
|
|
109
|
+
getStats(): StatsState;
|
|
110
|
+
/** Get total item count */
|
|
111
|
+
getCount(): number;
|
|
112
|
+
/** Get current position (1-based) */
|
|
113
|
+
getPosition(): number;
|
|
114
|
+
/** Get current progress percentage (0-100) */
|
|
115
|
+
getProgress(): number;
|
|
116
|
+
/** Manually set the total count */
|
|
117
|
+
setStatsCount(count: number): void;
|
|
118
|
+
}
|
|
119
|
+
export {};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Velocity feature for VList
|
|
3
|
+
*
|
|
4
|
+
* Displays scroll velocity in layout elements. Listens to viewport velocity
|
|
5
|
+
* events and updates designated layout elements with formatted velocity values.
|
|
6
|
+
*
|
|
7
|
+
* This feature provides the display mechanism. Application-specific features
|
|
8
|
+
* like global averaging across lists and localStorage persistence should be
|
|
9
|
+
* handled at the application level.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const vlist = createVList({
|
|
14
|
+
* layout: [
|
|
15
|
+
* ['head', { class: 'head' },
|
|
16
|
+
* ['title', { text: 'Users' }]
|
|
17
|
+
* ],
|
|
18
|
+
* ['viewport'],
|
|
19
|
+
* ['foot', { class: 'foot' },
|
|
20
|
+
* ['velocity', { class: 'velocity' },
|
|
21
|
+
* ['velocity-current', { text: '0.00' }],
|
|
22
|
+
* ['velocity-sep', { text: '/' }],
|
|
23
|
+
* ['velocity-avg', { text: '0.00' }],
|
|
24
|
+
* ['velocity-label', { text: 'px/ms' }]
|
|
25
|
+
* ]
|
|
26
|
+
* ]
|
|
27
|
+
* ],
|
|
28
|
+
*
|
|
29
|
+
* velocity: {
|
|
30
|
+
* elements: {
|
|
31
|
+
* current: 'velocity-current',
|
|
32
|
+
* average: 'velocity-avg'
|
|
33
|
+
* },
|
|
34
|
+
* format: (v) => v.toFixed(2),
|
|
35
|
+
* // Optional: track average within this list instance
|
|
36
|
+
* trackAverage: true,
|
|
37
|
+
* // Optional: max velocity to include in average (filters out scrollbar drag)
|
|
38
|
+
* maxVelocityForAverage: 50
|
|
39
|
+
* },
|
|
40
|
+
*
|
|
41
|
+
* collection: { ... }
|
|
42
|
+
* })
|
|
43
|
+
*
|
|
44
|
+
* // Events
|
|
45
|
+
* vlist.on('velocity:change', ({ velocity, direction, average }) => {
|
|
46
|
+
* console.log(`Velocity: ${velocity} px/ms (avg: ${average})`)
|
|
47
|
+
* })
|
|
48
|
+
*
|
|
49
|
+
* // API
|
|
50
|
+
* const velocity = vlist.getVelocity()
|
|
51
|
+
* const average = vlist.getAverageVelocity()
|
|
52
|
+
* vlist.resetVelocityAverage()
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
import type { VListConfig, VListItem } from "../types";
|
|
56
|
+
/**
|
|
57
|
+
* Velocity configuration
|
|
58
|
+
*/
|
|
59
|
+
export interface VelocityConfig {
|
|
60
|
+
/** Layout element names to update */
|
|
61
|
+
elements?: {
|
|
62
|
+
/** Element name for current velocity display */
|
|
63
|
+
current?: string;
|
|
64
|
+
/** Element name for average velocity display */
|
|
65
|
+
average?: string;
|
|
66
|
+
};
|
|
67
|
+
/** Format function for velocity values (default: toFixed(2)) */
|
|
68
|
+
format?: (velocity: number) => string;
|
|
69
|
+
/** Whether to track average velocity within this instance (default: false) */
|
|
70
|
+
trackAverage?: boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Maximum velocity to include in average calculation (default: 50)
|
|
73
|
+
* Higher velocities (e.g., from scrollbar dragging) are excluded
|
|
74
|
+
*/
|
|
75
|
+
maxVelocityForAverage?: number;
|
|
76
|
+
/**
|
|
77
|
+
* Minimum velocity to include in average calculation (default: 0.1)
|
|
78
|
+
* Filters out noise from near-zero velocities
|
|
79
|
+
*/
|
|
80
|
+
minVelocityForAverage?: number;
|
|
81
|
+
/**
|
|
82
|
+
* Callback for external average tracking (e.g., global across lists)
|
|
83
|
+
* When provided, allows the app to manage its own averaging logic
|
|
84
|
+
*/
|
|
85
|
+
onVelocityUpdate?: (velocity: number) => void;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Adds velocity display functionality to VList component
|
|
89
|
+
*
|
|
90
|
+
* This feature:
|
|
91
|
+
* 1. Listens to viewport:velocity-changed events
|
|
92
|
+
* 2. Updates layout elements with formatted velocity values
|
|
93
|
+
* 3. Optionally tracks average velocity within the instance
|
|
94
|
+
* 4. Emits 'velocity:change' event for app-specific handling
|
|
95
|
+
* 5. Provides API for getting velocity and average
|
|
96
|
+
*
|
|
97
|
+
* @param config - VList configuration with velocity options
|
|
98
|
+
* @returns Feature function that enhances the VList component
|
|
99
|
+
*/
|
|
100
|
+
export declare const withVelocity: <T extends VListItem = VListItem>(config: VListConfig<T> & {
|
|
101
|
+
velocity?: VelocityConfig;
|
|
102
|
+
}) => (component: any) => any;
|
|
103
|
+
/**
|
|
104
|
+
* Type helper for VList with velocity
|
|
105
|
+
*/
|
|
106
|
+
export interface WithVelocityComponent {
|
|
107
|
+
/** Get current velocity in px/ms */
|
|
108
|
+
getVelocity(): number;
|
|
109
|
+
/** Get current scroll direction */
|
|
110
|
+
getVelocityDirection(): "forward" | "backward";
|
|
111
|
+
/** Get average velocity in px/ms */
|
|
112
|
+
getAverageVelocity(): number;
|
|
113
|
+
/** Get velocity statistics */
|
|
114
|
+
getVelocityStats(): {
|
|
115
|
+
current: number;
|
|
116
|
+
direction: "forward" | "backward";
|
|
117
|
+
average: number;
|
|
118
|
+
sampleCount: number;
|
|
119
|
+
};
|
|
120
|
+
/** Reset average velocity tracking */
|
|
121
|
+
resetVelocityAverage(): void;
|
|
122
|
+
/** Manually update average display (for external tracking) */
|
|
123
|
+
setAverageVelocityDisplay(average: number): void;
|
|
124
|
+
}
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Viewport feature for VList
|
|
3
3
|
* Integrates the core viewport functionality with VList component
|
|
4
|
+
*
|
|
5
|
+
* When used with withLayout, this feature respects the viewport container
|
|
6
|
+
* defined in the layout schema, rendering virtual scrolling content inside it.
|
|
4
7
|
*/
|
|
5
8
|
import type { VListConfig, VListItem } from "../types";
|
|
6
9
|
/**
|
|
7
10
|
* Adds viewport functionality to VList
|
|
11
|
+
*
|
|
12
|
+
* This feature:
|
|
13
|
+
* 1. Configures the viewport for virtual scrolling
|
|
14
|
+
* 2. When withLayout is used, renders into the layout's viewport container
|
|
15
|
+
* 3. Handles parent/container attachment for standalone usage
|
|
8
16
|
*/
|
|
9
17
|
export declare const withViewport: <T extends VListItem = VListItem>(config: VListConfig<T>) => (component: any) => any;
|