mtrl-addons 0.1.2 → 0.2.1
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/build.js +139 -86
- package/package.json +13 -4
- package/scripts/debug/vlist-selection.ts +121 -0
- package/src/components/index.ts +5 -41
- package/src/components/{list → vlist}/config.ts +66 -95
- package/src/components/vlist/constants.ts +23 -0
- package/src/components/vlist/features/api.ts +322 -0
- package/src/components/vlist/features/index.ts +10 -0
- package/src/components/vlist/features/selection.ts +444 -0
- package/src/components/vlist/features/viewport.ts +65 -0
- package/src/components/vlist/index.ts +16 -0
- package/src/components/{list → vlist}/types.ts +104 -26
- package/src/components/vlist/vlist.ts +92 -0
- package/src/core/compose/features/gestures/index.ts +227 -0
- package/src/core/compose/features/gestures/longpress.ts +383 -0
- package/src/core/compose/features/gestures/pan.ts +424 -0
- package/src/core/compose/features/gestures/pinch.ts +475 -0
- package/src/core/compose/features/gestures/rotate.ts +485 -0
- package/src/core/compose/features/gestures/swipe.ts +492 -0
- package/src/core/compose/features/gestures/tap.ts +334 -0
- package/src/core/compose/features/index.ts +2 -38
- package/src/core/compose/index.ts +13 -29
- package/src/core/gestures/index.ts +31 -0
- package/src/core/gestures/longpress.ts +68 -0
- package/src/core/gestures/manager.ts +418 -0
- package/src/core/gestures/pan.ts +48 -0
- package/src/core/gestures/pinch.ts +58 -0
- package/src/core/gestures/rotate.ts +58 -0
- package/src/core/gestures/swipe.ts +66 -0
- package/src/core/gestures/tap.ts +45 -0
- package/src/core/gestures/types.ts +387 -0
- package/src/core/gestures/utils.ts +128 -0
- package/src/core/index.ts +27 -151
- package/src/core/layout/schema.ts +73 -35
- package/src/core/layout/types.ts +5 -2
- package/src/core/viewport/constants.ts +140 -0
- package/src/core/viewport/features/base.ts +73 -0
- package/src/core/viewport/features/collection.ts +882 -0
- package/src/core/viewport/features/events.ts +130 -0
- package/src/core/viewport/features/index.ts +20 -0
- package/src/core/{list-manager/features/viewport → viewport/features}/item-size.ts +27 -30
- package/src/core/{list-manager/features/viewport → viewport/features}/loading.ts +4 -4
- package/src/core/viewport/features/momentum.ts +260 -0
- package/src/core/viewport/features/placeholders.ts +335 -0
- package/src/core/viewport/features/rendering.ts +568 -0
- package/src/core/viewport/features/scrollbar.ts +434 -0
- package/src/core/viewport/features/scrolling.ts +618 -0
- package/src/core/viewport/features/utils.ts +88 -0
- package/src/core/viewport/features/virtual.ts +384 -0
- package/src/core/viewport/index.ts +31 -0
- package/src/core/viewport/types.ts +133 -0
- package/src/core/viewport/utils/speed-tracker.ts +79 -0
- package/src/core/viewport/viewport.ts +246 -0
- package/src/index.ts +0 -7
- package/src/styles/components/_vlist.scss +331 -0
- package/src/styles/index.scss +1 -1
- package/test/components/vlist-selection.test.ts +240 -0
- package/test/components/vlist.test.ts +63 -0
- package/test/core/collection/adapter.test.ts +161 -0
- package/bun.lock +0 -792
- package/src/components/list/api.ts +0 -314
- package/src/components/list/constants.ts +0 -56
- package/src/components/list/features/api.ts +0 -428
- package/src/components/list/features/index.ts +0 -31
- package/src/components/list/features/list-manager.ts +0 -502
- package/src/components/list/index.ts +0 -39
- package/src/components/list/list.ts +0 -234
- package/src/core/collection/base-collection.ts +0 -100
- package/src/core/collection/collection-composer.ts +0 -178
- package/src/core/collection/collection.ts +0 -745
- package/src/core/collection/constants.ts +0 -172
- package/src/core/collection/events.ts +0 -428
- package/src/core/collection/features/api/loading.ts +0 -279
- package/src/core/collection/features/operations/data-operations.ts +0 -147
- package/src/core/collection/index.ts +0 -104
- package/src/core/collection/state.ts +0 -497
- package/src/core/collection/types.ts +0 -404
- package/src/core/compose/features/collection.ts +0 -119
- package/src/core/compose/features/selection.ts +0 -213
- package/src/core/compose/features/styling.ts +0 -108
- package/src/core/list-manager/api.ts +0 -599
- package/src/core/list-manager/config.ts +0 -593
- package/src/core/list-manager/constants.ts +0 -268
- package/src/core/list-manager/features/api.ts +0 -58
- package/src/core/list-manager/features/collection/collection.ts +0 -705
- package/src/core/list-manager/features/collection/index.ts +0 -17
- package/src/core/list-manager/features/viewport/constants.ts +0 -42
- package/src/core/list-manager/features/viewport/index.ts +0 -16
- package/src/core/list-manager/features/viewport/placeholders.ts +0 -281
- package/src/core/list-manager/features/viewport/rendering.ts +0 -575
- package/src/core/list-manager/features/viewport/scrollbar.ts +0 -495
- package/src/core/list-manager/features/viewport/scrolling.ts +0 -795
- package/src/core/list-manager/features/viewport/template.ts +0 -220
- package/src/core/list-manager/features/viewport/viewport.ts +0 -654
- package/src/core/list-manager/features/viewport/virtual.ts +0 -309
- package/src/core/list-manager/index.ts +0 -279
- package/src/core/list-manager/list-manager.ts +0 -206
- package/src/core/list-manager/types.ts +0 -439
- package/src/core/list-manager/utils/calculations.ts +0 -290
- package/src/core/list-manager/utils/range-calculator.ts +0 -349
- package/src/core/list-manager/utils/speed-tracker.ts +0 -273
- package/src/styles/components/_list.scss +0 -244
- package/src/types/mtrl.d.ts +0 -6
- package/test/components/list.test.ts +0 -256
- package/test/core/collection/failed-ranges.test.ts +0 -270
- package/test/core/compose/features.test.ts +0 -183
- package/test/core/list-manager/features/collection.test.ts +0 -704
- package/test/core/list-manager/features/viewport.test.ts +0 -698
- package/test/core/list-manager/list-manager.test.ts +0 -593
- package/test/core/list-manager/utils/calculations.test.ts +0 -433
- package/test/core/list-manager/utils/range-calculator.test.ts +0 -569
- package/test/core/list-manager/utils/speed-tracker.test.ts +0 -530
- package/tsconfig.build.json +0 -23
- /package/src/components/{list → vlist}/features.ts +0 -0
- /package/src/core/{compose → viewport}/features/performance.ts +0 -0
|
@@ -1,28 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Types
|
|
3
|
-
*
|
|
4
|
-
* Extends collection types with list-specific functionality
|
|
2
|
+
* VList Types - Virtual List with direct viewport integration
|
|
5
3
|
*/
|
|
6
4
|
|
|
7
|
-
import type {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
5
|
+
import type { BaseComponent, ElementComponent } from "mtrl";
|
|
6
|
+
// Collection types are not exposed by mtrl; define minimal interfaces locally
|
|
7
|
+
export interface CollectionItem {
|
|
8
|
+
id: string | number;
|
|
9
|
+
[key: string]: any;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface CollectionConfig<T = any> {
|
|
13
|
+
adapter?: {
|
|
14
|
+
read(params?: any): Promise<{ items: T[]; meta?: any; error?: any }>;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface Collection<T = any> {
|
|
19
|
+
loadMissingRanges?: (
|
|
20
|
+
range: { start: number; end: number },
|
|
21
|
+
reason?: string
|
|
22
|
+
) => Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
import type { ViewportComponent } from "../../core/viewport/types";
|
|
18
25
|
|
|
19
26
|
/**
|
|
20
27
|
* List item interface - extends collection item
|
|
21
28
|
*/
|
|
22
|
-
export interface ListItem extends CollectionItem {
|
|
23
|
-
id: string;
|
|
24
|
-
[key: string]: any;
|
|
25
|
-
}
|
|
29
|
+
export interface ListItem extends CollectionItem {}
|
|
26
30
|
|
|
27
31
|
/**
|
|
28
32
|
* List adapter interface - extends collection adapter
|
|
@@ -71,7 +75,7 @@ export interface ListAdapterResponse<T extends ListItem = ListItem> {
|
|
|
71
75
|
/**
|
|
72
76
|
* List template definition
|
|
73
77
|
*/
|
|
74
|
-
export type ListTemplate =
|
|
78
|
+
export type ListTemplate = (item: any, index: number) => string | HTMLElement;
|
|
75
79
|
|
|
76
80
|
/**
|
|
77
81
|
* List item template function
|
|
@@ -89,8 +93,6 @@ export interface ListScrollConfig {
|
|
|
89
93
|
virtual?: boolean;
|
|
90
94
|
/** Item size (fixed) or 'auto' for dynamic - height for vertical, width for horizontal */
|
|
91
95
|
itemSize?: number | "auto";
|
|
92
|
-
/** Estimated item size for dynamic sizing */
|
|
93
|
-
estimatedItemSize?: number;
|
|
94
96
|
/** Number of items to render outside viewport */
|
|
95
97
|
overscan?: number;
|
|
96
98
|
/** Enable scroll animations */
|
|
@@ -145,6 +147,8 @@ export interface ListSelectionConfig {
|
|
|
145
147
|
selectedIndices?: number[];
|
|
146
148
|
/** Selection change callback */
|
|
147
149
|
onSelectionChange?: (selectedItems: any[], selectedIndices: number[]) => void;
|
|
150
|
+
/** Require keyboard modifiers for multi-select (default: false) */
|
|
151
|
+
requireModifiers?: boolean;
|
|
148
152
|
}
|
|
149
153
|
|
|
150
154
|
/**
|
|
@@ -174,12 +178,13 @@ export interface ListPaginationConfig {
|
|
|
174
178
|
/**
|
|
175
179
|
* Complete List component configuration
|
|
176
180
|
*/
|
|
177
|
-
export interface ListConfig<T =
|
|
181
|
+
export interface ListConfig<T extends ListItem = ListItem>
|
|
182
|
+
extends ListStyleConfig {
|
|
178
183
|
// Data layer (Collection) configuration
|
|
179
184
|
collection?: Partial<CollectionConfig<T>>;
|
|
180
185
|
|
|
181
186
|
// Performance layer (List Manager) configuration
|
|
182
|
-
listManager?: Partial<
|
|
187
|
+
listManager?: Partial<any>;
|
|
183
188
|
|
|
184
189
|
// Pagination configuration
|
|
185
190
|
pagination?: ListPaginationConfig;
|
|
@@ -325,7 +330,7 @@ export interface ListEvents<T = any> {
|
|
|
325
330
|
/**
|
|
326
331
|
* List component API
|
|
327
332
|
*/
|
|
328
|
-
export interface ListAPI<T =
|
|
333
|
+
export interface ListAPI<T extends ListItem = ListItem> {
|
|
329
334
|
// Data management
|
|
330
335
|
/** Load data */
|
|
331
336
|
loadData(): Promise<void>;
|
|
@@ -451,7 +456,7 @@ export interface ListAPI<T = any> {
|
|
|
451
456
|
/**
|
|
452
457
|
* List component interface (extends mtrl component patterns)
|
|
453
458
|
*/
|
|
454
|
-
export interface ListComponent<T =
|
|
459
|
+
export interface ListComponent<T extends ListItem = ListItem>
|
|
455
460
|
extends BaseComponent,
|
|
456
461
|
ElementComponent,
|
|
457
462
|
ListAPI<T> {
|
|
@@ -459,7 +464,7 @@ export interface ListComponent<T = any>
|
|
|
459
464
|
collection: Collection<T>;
|
|
460
465
|
|
|
461
466
|
/** List manager instance (performance layer) */
|
|
462
|
-
listManager:
|
|
467
|
+
listManager: any;
|
|
463
468
|
|
|
464
469
|
/** Current list state */
|
|
465
470
|
state: ListState;
|
|
@@ -511,3 +516,76 @@ export interface ListFeatures {
|
|
|
511
516
|
styling?: boolean;
|
|
512
517
|
performance?: boolean;
|
|
513
518
|
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* VList configuration interface
|
|
522
|
+
*/
|
|
523
|
+
export interface VListConfig<T extends ListItem = ListItem> {
|
|
524
|
+
// Container
|
|
525
|
+
parent?: HTMLElement | string;
|
|
526
|
+
container?: HTMLElement | string; // Also support container
|
|
527
|
+
|
|
528
|
+
// Basic properties
|
|
529
|
+
class?: string;
|
|
530
|
+
className?: string; // Also support className
|
|
531
|
+
prefix?: string;
|
|
532
|
+
ariaLabel?: string;
|
|
533
|
+
debug?: boolean;
|
|
534
|
+
|
|
535
|
+
// Data source
|
|
536
|
+
items?: T[];
|
|
537
|
+
|
|
538
|
+
// Template for rendering items
|
|
539
|
+
template?: (
|
|
540
|
+
item: T,
|
|
541
|
+
index: number
|
|
542
|
+
) => string | HTMLElement | any[] | Record<string, any>;
|
|
543
|
+
|
|
544
|
+
// Collection configuration
|
|
545
|
+
collection?: {
|
|
546
|
+
adapter?: ListAdapter<T>;
|
|
547
|
+
transform?: (item: T) => T;
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
// Pagination configuration
|
|
551
|
+
pagination?: {
|
|
552
|
+
strategy?: "page" | "offset" | "cursor";
|
|
553
|
+
limit?: number;
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
// Virtual scrolling configuration
|
|
557
|
+
virtual?: {
|
|
558
|
+
itemSize?: number;
|
|
559
|
+
overscan?: number;
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
// Scrolling configuration
|
|
563
|
+
scrolling?: {
|
|
564
|
+
orientation?: "vertical" | "horizontal";
|
|
565
|
+
animation?: boolean;
|
|
566
|
+
measureItems?: boolean;
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
// Performance settings
|
|
570
|
+
performance?: {
|
|
571
|
+
recycleElements?: boolean;
|
|
572
|
+
bufferSize?: number;
|
|
573
|
+
renderDebounce?: number;
|
|
574
|
+
maxConcurrentRequests?: number;
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
// Selection configuration
|
|
578
|
+
selection?: ListSelectionConfig;
|
|
579
|
+
|
|
580
|
+
// Event handlers
|
|
581
|
+
on?: ListEventHandlers<T>;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
export type VListComponent<T extends ListItem = ListItem> = ListComponent<T> & {
|
|
585
|
+
viewport: ViewportComponent["viewport"];
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
export type VListItem = ListItem;
|
|
589
|
+
export type VListAPI<T extends ListItem = ListItem> = ListAPI<T>;
|
|
590
|
+
export type VListState = ListState;
|
|
591
|
+
export type VListEvents<T = any> = ListEvents<T>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// src/components/vlist/vlist.ts
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* VList Component - Virtual List with direct viewport integration
|
|
5
|
+
*
|
|
6
|
+
* A simplified virtual list that uses the viewport feature directly
|
|
7
|
+
* without the list-manager abstraction layer.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { VListConfig, VListComponent, VListItem } from "./types";
|
|
11
|
+
|
|
12
|
+
// Import mtrl compose system
|
|
13
|
+
import { pipe } from "mtrl";
|
|
14
|
+
import { createBase, withElement } from "mtrl";
|
|
15
|
+
import { withEvents, withLifecycle } from "mtrl";
|
|
16
|
+
|
|
17
|
+
// Import viewport feature
|
|
18
|
+
import { withViewport } from "./features/viewport";
|
|
19
|
+
import { withAPI } from "./features/api";
|
|
20
|
+
import { withSelection } from "./features/selection";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Creates a new VList component using direct viewport integration
|
|
24
|
+
*
|
|
25
|
+
* @param {VListConfig} config - List configuration options
|
|
26
|
+
* @returns {VListComponent} A fully configured virtual list component
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* const vlist = createVList({
|
|
31
|
+
* container: '#my-list',
|
|
32
|
+
* collection: myAdapter,
|
|
33
|
+
* rangeSize: 20,
|
|
34
|
+
* paginationStrategy: 'page',
|
|
35
|
+
* template: (item, index) => [
|
|
36
|
+
* { class: 'viewport-item', attributes: { 'data-id': item.id }},
|
|
37
|
+
* [{ class: 'viewport-item__name', text: item.name }],
|
|
38
|
+
* [{ class: 'viewport-item__value', text: item.value }]
|
|
39
|
+
* ]
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export const createVList = <T extends VListItem = VListItem>(
|
|
44
|
+
config: VListConfig<T> = {}
|
|
45
|
+
): VListComponent<T> => {
|
|
46
|
+
try {
|
|
47
|
+
// console.log(`📋 Creating VList component with direct viewport integration`);
|
|
48
|
+
|
|
49
|
+
// Note: Transform should be applied by the collection feature in viewport
|
|
50
|
+
// VList should not intercept collection reads as it bypasses the loading manager
|
|
51
|
+
|
|
52
|
+
// Create the component through functional composition
|
|
53
|
+
const enhancers = [
|
|
54
|
+
// 1. Foundation layer
|
|
55
|
+
createBase,
|
|
56
|
+
withEvents(),
|
|
57
|
+
withElement({
|
|
58
|
+
tag: "div",
|
|
59
|
+
className: config.className || "mtrl-vlist",
|
|
60
|
+
attributes: {
|
|
61
|
+
role: "list",
|
|
62
|
+
"aria-label": config.ariaLabel || "Virtual List",
|
|
63
|
+
},
|
|
64
|
+
}),
|
|
65
|
+
|
|
66
|
+
// 2. Viewport integration
|
|
67
|
+
withViewport(config),
|
|
68
|
+
|
|
69
|
+
// 3. Component lifecycle
|
|
70
|
+
withLifecycle(),
|
|
71
|
+
|
|
72
|
+
// 4. Public API layer
|
|
73
|
+
withAPI(config),
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
// 4.5. Selection capabilities (if enabled) - must be after API
|
|
77
|
+
if (config.selection?.enabled) {
|
|
78
|
+
enhancers.push(withSelection(config));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const component = pipe(...enhancers)({
|
|
82
|
+
...config,
|
|
83
|
+
componentName: "vlist",
|
|
84
|
+
prefix: config.prefix || "mtrl",
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
return component as VListComponent<T>;
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error("❌ [VLIST] Failed to create VList component:", error);
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
// src/core/compose/features/gestures.ts
|
|
2
|
+
/**
|
|
3
|
+
* @module core/compose/features
|
|
4
|
+
* @description Adds gesture recognition capabilities to components
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { BaseComponent, ElementComponent } from "mtrl";
|
|
8
|
+
import {
|
|
9
|
+
createGestureManager,
|
|
10
|
+
GestureManager,
|
|
11
|
+
GestureConfig,
|
|
12
|
+
GestureHandler,
|
|
13
|
+
AnyGestureEvent,
|
|
14
|
+
} from "../../../gestures";
|
|
15
|
+
import { hasLifecycle, hasEmit } from "mtrl";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Configuration for gestures feature
|
|
19
|
+
*/
|
|
20
|
+
export interface GesturesFeatureConfig extends GestureConfig {
|
|
21
|
+
/**
|
|
22
|
+
* Whether to enable gesture recognition immediately
|
|
23
|
+
* @default true
|
|
24
|
+
*/
|
|
25
|
+
enableGestures?: boolean;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Initial gesture event handlers
|
|
29
|
+
*/
|
|
30
|
+
gestureHandlers?: Record<string, GestureHandler>;
|
|
31
|
+
|
|
32
|
+
[key: string]: any;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Component with gesture recognition capabilities
|
|
37
|
+
*/
|
|
38
|
+
export interface GesturesComponent extends BaseComponent {
|
|
39
|
+
/**
|
|
40
|
+
* Gesture manager instance
|
|
41
|
+
*/
|
|
42
|
+
gestures: GestureManager;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Add a gesture event handler
|
|
46
|
+
* @param eventType - Type of gesture event
|
|
47
|
+
* @param handler - Event handler function
|
|
48
|
+
* @returns GesturesComponent for chaining
|
|
49
|
+
*/
|
|
50
|
+
onGesture: (eventType: string, handler: GestureHandler) => GesturesComponent;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Remove a gesture event handler
|
|
54
|
+
* @param eventType - Type of gesture event
|
|
55
|
+
* @param handler - Event handler function
|
|
56
|
+
* @returns GesturesComponent for chaining
|
|
57
|
+
*/
|
|
58
|
+
offGesture: (eventType: string, handler: GestureHandler) => GesturesComponent;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Check if a gesture type is supported on the current device
|
|
62
|
+
* @param gestureType - Type of gesture to check
|
|
63
|
+
* @returns Whether the gesture is supported
|
|
64
|
+
*/
|
|
65
|
+
isGestureSupported: (gestureType: string) => boolean;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Enable gesture recognition
|
|
69
|
+
* @returns GesturesComponent for chaining
|
|
70
|
+
*/
|
|
71
|
+
enableGestures: () => GesturesComponent;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Disable gesture recognition
|
|
75
|
+
* @returns GesturesComponent for chaining
|
|
76
|
+
*/
|
|
77
|
+
disableGestures: () => GesturesComponent;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Adds gesture recognition capabilities to a component.
|
|
82
|
+
* This is a comprehensive gesture feature that adds support for all gesture types.
|
|
83
|
+
* For more lightweight, specific gestures, use the individual gesture features.
|
|
84
|
+
*
|
|
85
|
+
* @param config - Configuration object containing gesture settings
|
|
86
|
+
* @returns Function that enhances a component with gesture capabilities
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* // Add gesture recognition to a component
|
|
91
|
+
* const component = pipe(
|
|
92
|
+
* createBase,
|
|
93
|
+
* withElement(...),
|
|
94
|
+
* withGestures({
|
|
95
|
+
* swipeThreshold: 50,
|
|
96
|
+
* gestureHandlers: {
|
|
97
|
+
* 'tap': (e) => handleTap(e),
|
|
98
|
+
* 'swipeleft': (e) => navigateForward(e),
|
|
99
|
+
* 'swiperight': (e) => navigateBack(e)
|
|
100
|
+
* }
|
|
101
|
+
* })
|
|
102
|
+
* )(config);
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export const withGestures =
|
|
106
|
+
(config: GesturesFeatureConfig = {}) =>
|
|
107
|
+
<C extends ElementComponent>(component: C): C & GesturesComponent => {
|
|
108
|
+
if (!component.element) {
|
|
109
|
+
console.warn("Cannot add gesture recognition: missing element");
|
|
110
|
+
return component as C & GesturesComponent;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Default configuration
|
|
114
|
+
const {
|
|
115
|
+
enableGestures = true,
|
|
116
|
+
gestureHandlers = {},
|
|
117
|
+
...gestureConfig
|
|
118
|
+
} = config;
|
|
119
|
+
|
|
120
|
+
// Create gesture manager
|
|
121
|
+
const gestureManager = createGestureManager(
|
|
122
|
+
component.element,
|
|
123
|
+
gestureConfig
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
// Add initial gesture handlers
|
|
127
|
+
Object.entries(gestureHandlers).forEach(([eventType, handler]) => {
|
|
128
|
+
gestureManager.on(eventType, handler);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Enable/disable based on config
|
|
132
|
+
if (!enableGestures) {
|
|
133
|
+
gestureManager.disable();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Connect with existing event system if available
|
|
137
|
+
if (hasEmit(component)) {
|
|
138
|
+
// Forward gesture events to the component's event system
|
|
139
|
+
const forwardGestureEvents = (event: AnyGestureEvent) => {
|
|
140
|
+
component.emit(event.type, event);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// Register forwarder for common gesture types
|
|
144
|
+
[
|
|
145
|
+
"tap",
|
|
146
|
+
"swipe",
|
|
147
|
+
"swipeleft",
|
|
148
|
+
"swiperight",
|
|
149
|
+
"swipeup",
|
|
150
|
+
"swipedown",
|
|
151
|
+
"longpress",
|
|
152
|
+
"pinch",
|
|
153
|
+
"rotate",
|
|
154
|
+
"pan",
|
|
155
|
+
].forEach((type) => {
|
|
156
|
+
gestureManager.on(type, forwardGestureEvents);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Handle lifecycle integration
|
|
161
|
+
if (hasLifecycle(component)) {
|
|
162
|
+
const originalDestroy = component.lifecycle.destroy;
|
|
163
|
+
|
|
164
|
+
component.lifecycle.destroy = () => {
|
|
165
|
+
// Clean up gesture manager
|
|
166
|
+
gestureManager.destroy();
|
|
167
|
+
|
|
168
|
+
// Call original destroy method
|
|
169
|
+
originalDestroy.call(component.lifecycle);
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Create enhanced component
|
|
174
|
+
return {
|
|
175
|
+
...component,
|
|
176
|
+
gestures: gestureManager,
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Add a gesture event handler
|
|
180
|
+
* @param eventType - Type of gesture event
|
|
181
|
+
* @param handler - Event handler function
|
|
182
|
+
* @returns GesturesComponent for chaining
|
|
183
|
+
*/
|
|
184
|
+
onGesture(eventType: string, handler: GestureHandler) {
|
|
185
|
+
gestureManager.on(eventType, handler);
|
|
186
|
+
return this;
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Remove a gesture event handler
|
|
191
|
+
* @param eventType - Type of gesture event
|
|
192
|
+
* @param handler - Event handler function
|
|
193
|
+
* @returns GesturesComponent for chaining
|
|
194
|
+
*/
|
|
195
|
+
offGesture(eventType: string, handler: GestureHandler) {
|
|
196
|
+
gestureManager.off(eventType, handler);
|
|
197
|
+
return this;
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Check if a gesture type is supported on the current device
|
|
202
|
+
* @param gestureType - Type of gesture to check
|
|
203
|
+
* @returns Whether the gesture is supported
|
|
204
|
+
*/
|
|
205
|
+
isGestureSupported(gestureType: string) {
|
|
206
|
+
return gestureManager.isSupported(gestureType);
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Enable gesture recognition
|
|
211
|
+
* @returns GesturesComponent for chaining
|
|
212
|
+
*/
|
|
213
|
+
enableGestures() {
|
|
214
|
+
gestureManager.enable();
|
|
215
|
+
return this;
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Disable gesture recognition
|
|
220
|
+
* @returns GesturesComponent for chaining
|
|
221
|
+
*/
|
|
222
|
+
disableGestures() {
|
|
223
|
+
gestureManager.disable();
|
|
224
|
+
return this;
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
};
|