@uinstinct/svelte-wheel-picker 0.1.0 → 0.1.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/use-controllable-state.svelte.js +50 -31
- package/dist/use-typeahead-search.svelte.js +64 -46
- package/dist/use-wheel-physics.svelte.js +185 -181
- package/dist/wheel-physics-utils.js +25 -24
- package/package.json +12 -13
|
@@ -1,42 +1,61 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _ControllableState_internal, _ControllableState_onChange, _ControllableState_isControlled, _ControllableState_controlledValue;
|
|
13
|
+
var ControllableState = /** @class */ (function () {
|
|
14
|
+
function ControllableState(opts) {
|
|
15
|
+
_ControllableState_internal.set(this, $state(undefined));
|
|
16
|
+
_ControllableState_onChange.set(this, void 0);
|
|
17
|
+
_ControllableState_isControlled.set(this, void 0);
|
|
18
|
+
// $state so that reactive consumers (selectedIndex $derived) re-evaluate when prop changes
|
|
19
|
+
_ControllableState_controlledValue.set(this, $state(undefined));
|
|
20
|
+
__classPrivateFieldSet(this, _ControllableState_isControlled, typeof opts.onChange === 'function', "f");
|
|
21
|
+
__classPrivateFieldSet(this, _ControllableState_onChange, opts.onChange, "f");
|
|
22
|
+
__classPrivateFieldSet(this, _ControllableState_controlledValue, opts.value, "f");
|
|
23
|
+
if (__classPrivateFieldGet(this, _ControllableState_isControlled, "f")) {
|
|
24
|
+
__classPrivateFieldSet(this, _ControllableState_internal, opts.value, "f");
|
|
13
25
|
}
|
|
14
26
|
else {
|
|
15
|
-
this
|
|
27
|
+
__classPrivateFieldSet(this, _ControllableState_internal, opts.defaultValue, "f");
|
|
16
28
|
}
|
|
17
29
|
}
|
|
18
30
|
/**
|
|
19
31
|
* Update the tracked controlled value when the external `value` prop changes.
|
|
20
32
|
* Must be called from a $effect in the consuming component whenever `value` changes.
|
|
21
33
|
*/
|
|
22
|
-
updateControlledValue(value) {
|
|
23
|
-
this
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
34
|
+
ControllableState.prototype.updateControlledValue = function (value) {
|
|
35
|
+
__classPrivateFieldSet(this, _ControllableState_controlledValue, value, "f");
|
|
36
|
+
};
|
|
37
|
+
Object.defineProperty(ControllableState.prototype, "current", {
|
|
38
|
+
get: function () {
|
|
39
|
+
if (__classPrivateFieldGet(this, _ControllableState_isControlled, "f")) {
|
|
40
|
+
return __classPrivateFieldGet(this, _ControllableState_controlledValue, "f");
|
|
41
|
+
}
|
|
42
|
+
return __classPrivateFieldGet(this, _ControllableState_internal, "f");
|
|
43
|
+
},
|
|
44
|
+
set: function (next) {
|
|
45
|
+
var _a;
|
|
46
|
+
if (__classPrivateFieldGet(this, _ControllableState_isControlled, "f")) {
|
|
47
|
+
(_a = __classPrivateFieldGet(this, _ControllableState_onChange, "f")) === null || _a === void 0 ? void 0 : _a.call(this, next);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
__classPrivateFieldSet(this, _ControllableState_internal, next, "f");
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
enumerable: false,
|
|
54
|
+
configurable: true
|
|
55
|
+
});
|
|
56
|
+
return ControllableState;
|
|
57
|
+
}());
|
|
58
|
+
_ControllableState_internal = new WeakMap(), _ControllableState_onChange = new WeakMap(), _ControllableState_isControlled = new WeakMap(), _ControllableState_controlledValue = new WeakMap();
|
|
40
59
|
export function useControllableState(opts) {
|
|
41
60
|
return new ControllableState(opts);
|
|
42
61
|
}
|
|
@@ -1,59 +1,77 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
2
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
3
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
4
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
|
+
};
|
|
6
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
7
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
10
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
11
|
+
};
|
|
12
|
+
var _TypeaheadSearch_instances, _TypeaheadSearch_buffer, _TypeaheadSearch_lastKey, _TypeaheadSearch_lastTime, _TypeaheadSearch_timer, _TypeaheadSearch_getSearchText, _TypeaheadSearch_findFirst, _TypeaheadSearch_cycleMatch;
|
|
13
|
+
var TypeaheadSearch = /** @class */ (function () {
|
|
14
|
+
function TypeaheadSearch() {
|
|
15
|
+
_TypeaheadSearch_instances.add(this);
|
|
16
|
+
_TypeaheadSearch_buffer.set(this, $state(''));
|
|
17
|
+
_TypeaheadSearch_lastKey.set(this, $state(''));
|
|
18
|
+
_TypeaheadSearch_lastTime.set(this, 0);
|
|
19
|
+
_TypeaheadSearch_timer.set(this, null);
|
|
20
|
+
}
|
|
21
|
+
TypeaheadSearch.prototype.search = function (key, options, currentIndex) {
|
|
22
|
+
var _this = this;
|
|
23
|
+
var now = Date.now();
|
|
24
|
+
var withinWindow = now - __classPrivateFieldGet(this, _TypeaheadSearch_lastTime, "f") < 500;
|
|
25
|
+
var singleChar = key.length === 1;
|
|
10
26
|
if (!singleChar)
|
|
11
27
|
return -1;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
this
|
|
15
|
-
this
|
|
28
|
+
var lowerKey = key.toLowerCase();
|
|
29
|
+
var isSameKey = withinWindow && lowerKey === __classPrivateFieldGet(this, _TypeaheadSearch_lastKey, "f");
|
|
30
|
+
__classPrivateFieldSet(this, _TypeaheadSearch_lastKey, lowerKey, "f");
|
|
31
|
+
__classPrivateFieldSet(this, _TypeaheadSearch_lastTime, now, "f");
|
|
16
32
|
// Reset timer
|
|
17
|
-
if (this
|
|
18
|
-
clearTimeout(this
|
|
19
|
-
this
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}, 500);
|
|
33
|
+
if (__classPrivateFieldGet(this, _TypeaheadSearch_timer, "f"))
|
|
34
|
+
clearTimeout(__classPrivateFieldGet(this, _TypeaheadSearch_timer, "f"));
|
|
35
|
+
__classPrivateFieldSet(this, _TypeaheadSearch_timer, setTimeout(function () {
|
|
36
|
+
__classPrivateFieldSet(_this, _TypeaheadSearch_buffer, '', "f");
|
|
37
|
+
__classPrivateFieldSet(_this, _TypeaheadSearch_lastKey, '', "f");
|
|
38
|
+
}, 500), "f");
|
|
23
39
|
if (isSameKey) {
|
|
24
40
|
// Same key cycling (D-02): find next match after currentIndex
|
|
25
|
-
return this
|
|
41
|
+
return __classPrivateFieldGet(this, _TypeaheadSearch_instances, "m", _TypeaheadSearch_cycleMatch).call(this, lowerKey, options, currentIndex);
|
|
26
42
|
}
|
|
27
43
|
else {
|
|
28
44
|
// Accumulate or start fresh
|
|
29
|
-
this
|
|
30
|
-
return this
|
|
45
|
+
__classPrivateFieldSet(this, _TypeaheadSearch_buffer, withinWindow ? __classPrivateFieldGet(this, _TypeaheadSearch_buffer, "f") + lowerKey : lowerKey, "f");
|
|
46
|
+
return __classPrivateFieldGet(this, _TypeaheadSearch_instances, "m", _TypeaheadSearch_findFirst).call(this, __classPrivateFieldGet(this, _TypeaheadSearch_buffer, "f"), options);
|
|
31
47
|
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return options.findIndex((o) => !o.disabled && this.#getSearchText(o).startsWith(prefix));
|
|
38
|
-
}
|
|
39
|
-
#cycleMatch(key, options, fromIndex) {
|
|
40
|
-
const prefix = key.toLowerCase();
|
|
41
|
-
const matches = options
|
|
42
|
-
.map((o, i) => ({ i, matches: !o.disabled && this.#getSearchText(o).startsWith(prefix) }))
|
|
43
|
-
.filter((x) => x.matches)
|
|
44
|
-
.map((x) => x.i);
|
|
45
|
-
if (matches.length === 0)
|
|
46
|
-
return -1;
|
|
47
|
-
const afterCurrent = matches.find((i) => i > fromIndex);
|
|
48
|
-
return afterCurrent ?? matches[0]; // wrap around
|
|
49
|
-
}
|
|
50
|
-
destroy() {
|
|
51
|
-
if (this.#timer) {
|
|
52
|
-
clearTimeout(this.#timer);
|
|
53
|
-
this.#timer = null;
|
|
48
|
+
};
|
|
49
|
+
TypeaheadSearch.prototype.destroy = function () {
|
|
50
|
+
if (__classPrivateFieldGet(this, _TypeaheadSearch_timer, "f")) {
|
|
51
|
+
clearTimeout(__classPrivateFieldGet(this, _TypeaheadSearch_timer, "f"));
|
|
52
|
+
__classPrivateFieldSet(this, _TypeaheadSearch_timer, null, "f");
|
|
54
53
|
}
|
|
55
|
-
}
|
|
56
|
-
|
|
54
|
+
};
|
|
55
|
+
return TypeaheadSearch;
|
|
56
|
+
}());
|
|
57
|
+
_TypeaheadSearch_buffer = new WeakMap(), _TypeaheadSearch_lastKey = new WeakMap(), _TypeaheadSearch_lastTime = new WeakMap(), _TypeaheadSearch_timer = new WeakMap(), _TypeaheadSearch_instances = new WeakSet(), _TypeaheadSearch_getSearchText = function _TypeaheadSearch_getSearchText(option) {
|
|
58
|
+
var _a;
|
|
59
|
+
return ((_a = option.textValue) !== null && _a !== void 0 ? _a : option.label).toLowerCase();
|
|
60
|
+
}, _TypeaheadSearch_findFirst = function _TypeaheadSearch_findFirst(prefix, options) {
|
|
61
|
+
var _this = this;
|
|
62
|
+
return options.findIndex(function (o) { return !o.disabled && __classPrivateFieldGet(_this, _TypeaheadSearch_instances, "m", _TypeaheadSearch_getSearchText).call(_this, o).startsWith(prefix); });
|
|
63
|
+
}, _TypeaheadSearch_cycleMatch = function _TypeaheadSearch_cycleMatch(key, options, fromIndex) {
|
|
64
|
+
var _this = this;
|
|
65
|
+
var prefix = key.toLowerCase();
|
|
66
|
+
var matches = options
|
|
67
|
+
.map(function (o, i) { return ({ i: i, matches: !o.disabled && __classPrivateFieldGet(_this, _TypeaheadSearch_instances, "m", _TypeaheadSearch_getSearchText).call(_this, o).startsWith(prefix) }); })
|
|
68
|
+
.filter(function (x) { return x.matches; })
|
|
69
|
+
.map(function (x) { return x.i; });
|
|
70
|
+
if (matches.length === 0)
|
|
71
|
+
return -1;
|
|
72
|
+
var afterCurrent = matches.find(function (i) { return i > fromIndex; });
|
|
73
|
+
return afterCurrent !== null && afterCurrent !== void 0 ? afterCurrent : matches[0]; // wrap around
|
|
74
|
+
};
|
|
57
75
|
export function useTypeaheadSearch() {
|
|
58
76
|
return new TypeaheadSearch();
|
|
59
77
|
}
|
|
@@ -10,53 +10,67 @@
|
|
|
10
10
|
* - Boundary resistance uses RESISTANCE constant from React v1.2.2 source.
|
|
11
11
|
* - Disabled options are always skipped when computing snap targets.
|
|
12
12
|
*/
|
|
13
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
14
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
15
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
16
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
17
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
18
|
+
};
|
|
19
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
20
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
21
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
22
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
23
|
+
};
|
|
24
|
+
var _WheelPhysics_instances, _WheelPhysics_itemHeight, _WheelPhysics_visibleCount, _WheelPhysics_dragSensitivity, _WheelPhysics_scrollSensitivity, _WheelPhysics_options, _WheelPhysics_onSnap, _WheelPhysics_infinite, _WheelPhysics_rafId, _WheelPhysics_isDragging, _WheelPhysics_dragStartOffset, _WheelPhysics_dragStartY, _WheelPhysics_yList, _WheelPhysics_lastWheelTime, _WheelPhysics_animating, _WheelPhysics_cancelRaf, _WheelPhysics_indexToOffset, _WheelPhysics_offsetToIndex;
|
|
13
25
|
import { easeOutCubic, indexToOffset, offsetToIndex, clampIndex, wrapIndex, snapToNearestEnabled, calculateVelocity, computeSnapTarget, computeAnimationDuration, RESISTANCE, DEFAULT_DRAG_SENSITIVITY, DEFAULT_SCROLL_SENSITIVITY, DEFAULT_ITEM_HEIGHT, DEFAULT_VISIBLE_COUNT, SNAP_BACK_DECELERATION, } from './wheel-physics-utils.js';
|
|
14
26
|
// Re-export for convenience so consumers only need one import
|
|
15
27
|
export { DEFAULT_DRAG_SENSITIVITY, DEFAULT_SCROLL_SENSITIVITY, DEFAULT_ITEM_HEIGHT, DEFAULT_VISIBLE_COUNT, };
|
|
16
|
-
|
|
17
|
-
// ---------------------------------------------------------------------------
|
|
18
|
-
// Public reactive state ($state) — the ONLY field bound to the DOM transform
|
|
19
|
-
// ---------------------------------------------------------------------------
|
|
20
|
-
offset = $state(0);
|
|
21
|
-
// ---------------------------------------------------------------------------
|
|
22
|
-
// Private configuration (set in constructor, may be updated by update())
|
|
23
|
-
// ---------------------------------------------------------------------------
|
|
24
|
-
#itemHeight;
|
|
25
|
-
#visibleCount;
|
|
26
|
-
#dragSensitivity;
|
|
27
|
-
#scrollSensitivity;
|
|
28
|
-
#options;
|
|
29
|
-
#onSnap;
|
|
30
|
-
#infinite;
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
// Private non-reactive animation/drag state (NOT $state — Pitfall 2)
|
|
33
|
-
// ---------------------------------------------------------------------------
|
|
34
|
-
/** Current RAF handle — null when no animation running */
|
|
35
|
-
#rafId = null;
|
|
36
|
-
/** True between pointerdown and pointerup */
|
|
37
|
-
#isDragging = false;
|
|
38
|
-
/** The offset value when the current drag began */
|
|
39
|
-
#dragStartOffset = 0;
|
|
40
|
-
/** clientY at the start of the current drag (used for direct delta) */
|
|
41
|
-
#dragStartY = 0;
|
|
42
|
-
/** Recent pointer positions for velocity calculation: [clientY, timestamp][] */
|
|
43
|
-
#yList = [];
|
|
44
|
-
/** Timestamp of the last wheel event (100ms debounce guard) */
|
|
45
|
-
#lastWheelTime = -Infinity;
|
|
46
|
-
/** True while a snap or inertia animation is running */
|
|
47
|
-
#animating = false;
|
|
28
|
+
var WheelPhysics = /** @class */ (function () {
|
|
48
29
|
// ---------------------------------------------------------------------------
|
|
49
30
|
// Constructor
|
|
50
31
|
// ---------------------------------------------------------------------------
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
this
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
this
|
|
58
|
-
|
|
59
|
-
|
|
32
|
+
function WheelPhysics(opts) {
|
|
33
|
+
var _a, _b, _c, _d, _e;
|
|
34
|
+
_WheelPhysics_instances.add(this);
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Public reactive state ($state) — the ONLY field bound to the DOM transform
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
this.offset = $state(0);
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Private configuration (set in constructor, may be updated by update())
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
_WheelPhysics_itemHeight.set(this, void 0);
|
|
43
|
+
_WheelPhysics_visibleCount.set(this, void 0);
|
|
44
|
+
_WheelPhysics_dragSensitivity.set(this, void 0);
|
|
45
|
+
_WheelPhysics_scrollSensitivity.set(this, void 0);
|
|
46
|
+
_WheelPhysics_options.set(this, void 0);
|
|
47
|
+
_WheelPhysics_onSnap.set(this, void 0);
|
|
48
|
+
_WheelPhysics_infinite.set(this, void 0);
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// Private non-reactive animation/drag state (NOT $state — Pitfall 2)
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
/** Current RAF handle — null when no animation running */
|
|
53
|
+
_WheelPhysics_rafId.set(this, null);
|
|
54
|
+
/** True between pointerdown and pointerup */
|
|
55
|
+
_WheelPhysics_isDragging.set(this, false);
|
|
56
|
+
/** The offset value when the current drag began */
|
|
57
|
+
_WheelPhysics_dragStartOffset.set(this, 0);
|
|
58
|
+
/** clientY at the start of the current drag (used for direct delta) */
|
|
59
|
+
_WheelPhysics_dragStartY.set(this, 0);
|
|
60
|
+
/** Recent pointer positions for velocity calculation: [clientY, timestamp][] */
|
|
61
|
+
_WheelPhysics_yList.set(this, []);
|
|
62
|
+
/** Timestamp of the last wheel event (100ms debounce guard) */
|
|
63
|
+
_WheelPhysics_lastWheelTime.set(this, -Infinity);
|
|
64
|
+
/** True while a snap or inertia animation is running */
|
|
65
|
+
_WheelPhysics_animating.set(this, false);
|
|
66
|
+
__classPrivateFieldSet(this, _WheelPhysics_itemHeight, (_a = opts.itemHeight) !== null && _a !== void 0 ? _a : DEFAULT_ITEM_HEIGHT, "f");
|
|
67
|
+
__classPrivateFieldSet(this, _WheelPhysics_visibleCount, (_b = opts.visibleCount) !== null && _b !== void 0 ? _b : DEFAULT_VISIBLE_COUNT, "f");
|
|
68
|
+
__classPrivateFieldSet(this, _WheelPhysics_dragSensitivity, (_c = opts.dragSensitivity) !== null && _c !== void 0 ? _c : DEFAULT_DRAG_SENSITIVITY, "f");
|
|
69
|
+
__classPrivateFieldSet(this, _WheelPhysics_scrollSensitivity, (_d = opts.scrollSensitivity) !== null && _d !== void 0 ? _d : DEFAULT_SCROLL_SENSITIVITY, "f");
|
|
70
|
+
__classPrivateFieldSet(this, _WheelPhysics_infinite, (_e = opts.infinite) !== null && _e !== void 0 ? _e : false, "f");
|
|
71
|
+
__classPrivateFieldSet(this, _WheelPhysics_options, opts.options, "f");
|
|
72
|
+
__classPrivateFieldSet(this, _WheelPhysics_onSnap, opts.onSnap, "f");
|
|
73
|
+
this.offset = __classPrivateFieldGet(this, _WheelPhysics_instances, "m", _WheelPhysics_indexToOffset).call(this, opts.initialIndex);
|
|
60
74
|
}
|
|
61
75
|
// ---------------------------------------------------------------------------
|
|
62
76
|
// Configuration update (called when props change in parent component)
|
|
@@ -65,47 +79,47 @@ export class WheelPhysics {
|
|
|
65
79
|
* Update configuration when parent props change.
|
|
66
80
|
* This does NOT re-trigger animation — it takes effect on the next interaction.
|
|
67
81
|
*/
|
|
68
|
-
update(opts) {
|
|
82
|
+
WheelPhysics.prototype.update = function (opts) {
|
|
69
83
|
if (opts.itemHeight !== undefined)
|
|
70
|
-
this
|
|
84
|
+
__classPrivateFieldSet(this, _WheelPhysics_itemHeight, opts.itemHeight, "f");
|
|
71
85
|
if (opts.visibleCount !== undefined)
|
|
72
|
-
this
|
|
86
|
+
__classPrivateFieldSet(this, _WheelPhysics_visibleCount, opts.visibleCount, "f");
|
|
73
87
|
if (opts.dragSensitivity !== undefined)
|
|
74
|
-
this
|
|
88
|
+
__classPrivateFieldSet(this, _WheelPhysics_dragSensitivity, opts.dragSensitivity, "f");
|
|
75
89
|
if (opts.scrollSensitivity !== undefined)
|
|
76
|
-
this
|
|
90
|
+
__classPrivateFieldSet(this, _WheelPhysics_scrollSensitivity, opts.scrollSensitivity, "f");
|
|
77
91
|
if (opts.infinite !== undefined)
|
|
78
|
-
this
|
|
92
|
+
__classPrivateFieldSet(this, _WheelPhysics_infinite, opts.infinite, "f");
|
|
79
93
|
if (opts.options !== undefined)
|
|
80
|
-
this
|
|
94
|
+
__classPrivateFieldSet(this, _WheelPhysics_options, opts.options, "f");
|
|
81
95
|
if (opts.onSnap !== undefined)
|
|
82
|
-
this
|
|
83
|
-
}
|
|
96
|
+
__classPrivateFieldSet(this, _WheelPhysics_onSnap, opts.onSnap, "f");
|
|
97
|
+
};
|
|
84
98
|
// ---------------------------------------------------------------------------
|
|
85
99
|
// Drag handlers (pointer events)
|
|
86
100
|
// ---------------------------------------------------------------------------
|
|
87
101
|
/**
|
|
88
102
|
* Called on pointerdown. Cancels any running animation and begins tracking.
|
|
89
103
|
*/
|
|
90
|
-
startDrag(clientY) {
|
|
91
|
-
this
|
|
92
|
-
this
|
|
93
|
-
this
|
|
94
|
-
this
|
|
95
|
-
this
|
|
96
|
-
this
|
|
97
|
-
}
|
|
104
|
+
WheelPhysics.prototype.startDrag = function (clientY) {
|
|
105
|
+
__classPrivateFieldGet(this, _WheelPhysics_instances, "m", _WheelPhysics_cancelRaf).call(this);
|
|
106
|
+
__classPrivateFieldSet(this, _WheelPhysics_isDragging, true, "f");
|
|
107
|
+
__classPrivateFieldSet(this, _WheelPhysics_animating, false, "f");
|
|
108
|
+
__classPrivateFieldSet(this, _WheelPhysics_dragStartOffset, this.offset, "f");
|
|
109
|
+
__classPrivateFieldSet(this, _WheelPhysics_dragStartY, clientY, "f");
|
|
110
|
+
__classPrivateFieldSet(this, _WheelPhysics_yList, [[clientY, performance.now()]], "f");
|
|
111
|
+
};
|
|
98
112
|
/**
|
|
99
113
|
* Called on pointermove. Updates offset applying boundary resistance at ends.
|
|
100
114
|
*/
|
|
101
|
-
moveDrag(clientY) {
|
|
102
|
-
if (!this
|
|
115
|
+
WheelPhysics.prototype.moveDrag = function (clientY) {
|
|
116
|
+
if (!__classPrivateFieldGet(this, _WheelPhysics_isDragging, "f"))
|
|
103
117
|
return;
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (this
|
|
118
|
+
var delta = clientY - __classPrivateFieldGet(this, _WheelPhysics_dragStartY, "f");
|
|
119
|
+
var maxOffset = __classPrivateFieldGet(this, _WheelPhysics_instances, "m", _WheelPhysics_indexToOffset).call(this, 0);
|
|
120
|
+
var minOffset = __classPrivateFieldGet(this, _WheelPhysics_instances, "m", _WheelPhysics_indexToOffset).call(this, __classPrivateFieldGet(this, _WheelPhysics_options, "f").length - 1);
|
|
121
|
+
var newOffset = __classPrivateFieldGet(this, _WheelPhysics_dragStartOffset, "f") + delta;
|
|
122
|
+
if (__classPrivateFieldGet(this, _WheelPhysics_infinite, "f")) {
|
|
109
123
|
// Infinite mode: normalize offset when the drag exceeds the ghost item bounds.
|
|
110
124
|
// The DOM has 3×N items (before-ghosts + real + after-ghosts), covering rawIndex
|
|
111
125
|
// -N..2N-1. When the pointer is captured outside the container, the user can drag
|
|
@@ -114,18 +128,18 @@ export class WheelPhysics {
|
|
|
114
128
|
//
|
|
115
129
|
// Applying the same shift to #dragStartOffset keeps future delta computations
|
|
116
130
|
// consistent so the drag feels continuous across the normalization boundary.
|
|
117
|
-
|
|
131
|
+
var loopDistance = __classPrivateFieldGet(this, _WheelPhysics_options, "f").length * __classPrivateFieldGet(this, _WheelPhysics_itemHeight, "f");
|
|
118
132
|
// After-ghost overflow: newOffset went past the last after-ghost (rawIndex >= 2N)
|
|
119
|
-
|
|
133
|
+
var afterGhostEnd = __classPrivateFieldGet(this, _WheelPhysics_instances, "m", _WheelPhysics_indexToOffset).call(this, 2 * __classPrivateFieldGet(this, _WheelPhysics_options, "f").length);
|
|
120
134
|
// Before-ghost overflow: newOffset went past the first before-ghost (rawIndex < -N)
|
|
121
|
-
|
|
135
|
+
var beforeGhostEnd = __classPrivateFieldGet(this, _WheelPhysics_instances, "m", _WheelPhysics_indexToOffset).call(this, -__classPrivateFieldGet(this, _WheelPhysics_options, "f").length - 1);
|
|
122
136
|
while (newOffset < afterGhostEnd) {
|
|
123
137
|
newOffset += loopDistance;
|
|
124
|
-
this
|
|
138
|
+
__classPrivateFieldSet(this, _WheelPhysics_dragStartOffset, __classPrivateFieldGet(this, _WheelPhysics_dragStartOffset, "f") + loopDistance, "f");
|
|
125
139
|
}
|
|
126
140
|
while (newOffset > beforeGhostEnd) {
|
|
127
141
|
newOffset -= loopDistance;
|
|
128
|
-
this
|
|
142
|
+
__classPrivateFieldSet(this, _WheelPhysics_dragStartOffset, __classPrivateFieldGet(this, _WheelPhysics_dragStartOffset, "f") - loopDistance, "f");
|
|
129
143
|
}
|
|
130
144
|
}
|
|
131
145
|
else {
|
|
@@ -139,31 +153,31 @@ export class WheelPhysics {
|
|
|
139
153
|
}
|
|
140
154
|
this.offset = newOffset;
|
|
141
155
|
// Track last 5 pointer positions for velocity calculation
|
|
142
|
-
this
|
|
143
|
-
if (this
|
|
144
|
-
this
|
|
156
|
+
__classPrivateFieldGet(this, _WheelPhysics_yList, "f").push([clientY, performance.now()]);
|
|
157
|
+
if (__classPrivateFieldGet(this, _WheelPhysics_yList, "f").length > 5) {
|
|
158
|
+
__classPrivateFieldGet(this, _WheelPhysics_yList, "f").shift();
|
|
145
159
|
}
|
|
146
|
-
}
|
|
160
|
+
};
|
|
147
161
|
/**
|
|
148
162
|
* Called on pointerup. Computes velocity and kicks off inertia or direct snap.
|
|
149
163
|
*/
|
|
150
|
-
endDrag() {
|
|
151
|
-
console.log('[endDrag] called, isDragging=', this
|
|
152
|
-
if (!this
|
|
164
|
+
WheelPhysics.prototype.endDrag = function () {
|
|
165
|
+
console.log('[endDrag] called, isDragging=', __classPrivateFieldGet(this, _WheelPhysics_isDragging, "f"), 'offset=', this.offset);
|
|
166
|
+
if (!__classPrivateFieldGet(this, _WheelPhysics_isDragging, "f"))
|
|
153
167
|
return;
|
|
154
|
-
this
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
168
|
+
__classPrivateFieldSet(this, _WheelPhysics_isDragging, false, "f");
|
|
169
|
+
var velocity = calculateVelocity(__classPrivateFieldGet(this, _WheelPhysics_yList, "f"), __classPrivateFieldGet(this, _WheelPhysics_itemHeight, "f"));
|
|
170
|
+
var rawIndex = __classPrivateFieldGet(this, _WheelPhysics_instances, "m", _WheelPhysics_offsetToIndex).call(this, this.offset);
|
|
171
|
+
var N = __classPrivateFieldGet(this, _WheelPhysics_options, "f").length;
|
|
172
|
+
var currentIndex = __classPrivateFieldGet(this, _WheelPhysics_infinite, "f")
|
|
159
173
|
? wrapIndex(rawIndex, N)
|
|
160
174
|
: clampIndex(rawIndex, N);
|
|
161
|
-
console.log('[endDrag] velocity=', velocity, 'rawIndex=', rawIndex, 'currentIndex=', currentIndex, 'infinite=', this
|
|
175
|
+
console.log('[endDrag] velocity=', velocity, 'rawIndex=', rawIndex, 'currentIndex=', currentIndex, 'infinite=', __classPrivateFieldGet(this, _WheelPhysics_infinite, "f"));
|
|
162
176
|
if (Math.abs(velocity) < 0.5) {
|
|
163
177
|
// Slow release — snap directly to nearest enabled option
|
|
164
|
-
|
|
178
|
+
var snapIndex = snapToNearestEnabled(currentIndex, __classPrivateFieldGet(this, _WheelPhysics_options, "f"));
|
|
165
179
|
console.log('[endDrag] slow path, snapIndex=', snapIndex);
|
|
166
|
-
if (this
|
|
180
|
+
if (__classPrivateFieldGet(this, _WheelPhysics_infinite, "f")) {
|
|
167
181
|
// Preserve ghost-section context so the snap animation continues in the
|
|
168
182
|
// same direction as the drag rather than jumping backward to real-section.
|
|
169
183
|
// rawIndex is in [-N, 2N-1] (guaranteed by moveDrag normalization).
|
|
@@ -171,7 +185,7 @@ export class WheelPhysics {
|
|
|
171
185
|
// before-ghost (rawIndex < 0): animate to snapIndex - N
|
|
172
186
|
// after-ghost (rawIndex >= N): animate to snapIndex + N
|
|
173
187
|
// real section (rawIndex in [0, N-1]): animate to snapIndex directly
|
|
174
|
-
|
|
188
|
+
var loopOffset = rawIndex < 0 ? -N : rawIndex >= N ? N : 0;
|
|
175
189
|
this.animateTo(snapIndex + loopOffset);
|
|
176
190
|
}
|
|
177
191
|
else {
|
|
@@ -182,25 +196,25 @@ export class WheelPhysics {
|
|
|
182
196
|
// Inertia — compute overshoot target
|
|
183
197
|
// Use rawIndex (not currentIndex) so the overshoot accounts for the current
|
|
184
198
|
// ghost-loop position, giving the correct item index after inertia deceleration.
|
|
185
|
-
|
|
186
|
-
if (this
|
|
199
|
+
var rawTarget = computeSnapTarget(rawIndex, velocity, __classPrivateFieldGet(this, _WheelPhysics_dragSensitivity, "f"));
|
|
200
|
+
if (__classPrivateFieldGet(this, _WheelPhysics_infinite, "f")) {
|
|
187
201
|
// snapIndex is the nearest enabled item to the overshoot target (in [0, N-1])
|
|
188
|
-
|
|
189
|
-
|
|
202
|
+
var wrapped = wrapIndex(rawTarget, N);
|
|
203
|
+
var snapIndex = snapToNearestEnabled(wrapped, __classPrivateFieldGet(this, _WheelPhysics_options, "f"));
|
|
190
204
|
// Animate to the ghost-section position of snapIndex matching the current
|
|
191
205
|
// loop, so the animation moves in the same direction as the drag.
|
|
192
206
|
// snapIndex is in [0,N-1]; loopOffset is -N, 0, or +N based on current section.
|
|
193
|
-
|
|
207
|
+
var loopOffset = rawIndex < 0 ? -N : rawIndex >= N ? N : 0;
|
|
194
208
|
console.log('[endDrag] inertia path, rawTarget=', rawTarget, 'wrapped=', wrapped, 'snapIndex=', snapIndex, 'loopOffset=', loopOffset);
|
|
195
209
|
this.animateTo(snapIndex + loopOffset);
|
|
196
210
|
}
|
|
197
211
|
else {
|
|
198
|
-
|
|
199
|
-
|
|
212
|
+
var clamped = clampIndex(rawTarget, N);
|
|
213
|
+
var snapIndex = snapToNearestEnabled(clamped, __classPrivateFieldGet(this, _WheelPhysics_options, "f"));
|
|
200
214
|
this.animateTo(snapIndex);
|
|
201
215
|
}
|
|
202
216
|
}
|
|
203
|
-
}
|
|
217
|
+
};
|
|
204
218
|
// ---------------------------------------------------------------------------
|
|
205
219
|
// Wheel event handler
|
|
206
220
|
// ---------------------------------------------------------------------------
|
|
@@ -210,29 +224,29 @@ export class WheelPhysics {
|
|
|
210
224
|
* deltaY > 0: scroll down → move to next item (higher index)
|
|
211
225
|
* deltaY < 0: scroll up → move to previous item (lower index)
|
|
212
226
|
*/
|
|
213
|
-
handleWheel(deltaY) {
|
|
214
|
-
|
|
215
|
-
if (now - this
|
|
227
|
+
WheelPhysics.prototype.handleWheel = function (deltaY) {
|
|
228
|
+
var now = performance.now();
|
|
229
|
+
if (now - __classPrivateFieldGet(this, _WheelPhysics_lastWheelTime, "f") < 100)
|
|
216
230
|
return;
|
|
217
|
-
this
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
? wrapIndex(rawIndex, this
|
|
221
|
-
: clampIndex(rawIndex, this
|
|
231
|
+
__classPrivateFieldSet(this, _WheelPhysics_lastWheelTime, now, "f");
|
|
232
|
+
var rawIndex = __classPrivateFieldGet(this, _WheelPhysics_instances, "m", _WheelPhysics_offsetToIndex).call(this, this.offset);
|
|
233
|
+
var currentIndex = __classPrivateFieldGet(this, _WheelPhysics_infinite, "f")
|
|
234
|
+
? wrapIndex(rawIndex, __classPrivateFieldGet(this, _WheelPhysics_options, "f").length)
|
|
235
|
+
: clampIndex(rawIndex, __classPrivateFieldGet(this, _WheelPhysics_options, "f").length);
|
|
222
236
|
// deltaY > 0 = scroll down = move to next item (increment index)
|
|
223
|
-
|
|
224
|
-
if (this
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
237
|
+
var direction = deltaY > 0 ? 1 : -1;
|
|
238
|
+
if (__classPrivateFieldGet(this, _WheelPhysics_infinite, "f")) {
|
|
239
|
+
var next = currentIndex + direction;
|
|
240
|
+
var wrapped = wrapIndex(next, __classPrivateFieldGet(this, _WheelPhysics_options, "f").length);
|
|
241
|
+
var snapIndex = snapToNearestEnabled(wrapped, __classPrivateFieldGet(this, _WheelPhysics_options, "f"));
|
|
228
242
|
this.animateTo(snapIndex);
|
|
229
243
|
}
|
|
230
244
|
else {
|
|
231
|
-
|
|
232
|
-
|
|
245
|
+
var targetIndex = clampIndex(currentIndex + direction, __classPrivateFieldGet(this, _WheelPhysics_options, "f").length);
|
|
246
|
+
var snapIndex = snapToNearestEnabled(targetIndex, __classPrivateFieldGet(this, _WheelPhysics_options, "f"));
|
|
233
247
|
this.animateTo(snapIndex);
|
|
234
248
|
}
|
|
235
|
-
}
|
|
249
|
+
};
|
|
236
250
|
// ---------------------------------------------------------------------------
|
|
237
251
|
// Animation
|
|
238
252
|
// ---------------------------------------------------------------------------
|
|
@@ -242,96 +256,86 @@ export class WheelPhysics {
|
|
|
242
256
|
*
|
|
243
257
|
* Cancels any currently running animation before starting.
|
|
244
258
|
*/
|
|
245
|
-
animateTo(targetIndex) {
|
|
259
|
+
WheelPhysics.prototype.animateTo = function (targetIndex) {
|
|
260
|
+
var _this = this;
|
|
246
261
|
console.log('[animateTo] targetIndex=', targetIndex, 'from offset=', this.offset);
|
|
247
|
-
this
|
|
248
|
-
this
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (!
|
|
262
|
+
__classPrivateFieldGet(this, _WheelPhysics_instances, "m", _WheelPhysics_cancelRaf).call(this);
|
|
263
|
+
__classPrivateFieldSet(this, _WheelPhysics_animating, true, "f");
|
|
264
|
+
var startOffset = this.offset;
|
|
265
|
+
var targetOffset = __classPrivateFieldGet(this, _WheelPhysics_instances, "m", _WheelPhysics_indexToOffset).call(this, targetIndex);
|
|
266
|
+
var distance = Math.abs(targetIndex - __classPrivateFieldGet(this, _WheelPhysics_instances, "m", _WheelPhysics_offsetToIndex).call(this, startOffset));
|
|
267
|
+
var durationSec = computeAnimationDuration(distance, __classPrivateFieldGet(this, _WheelPhysics_scrollSensitivity, "f"));
|
|
268
|
+
var durationMs = durationSec * 1000;
|
|
269
|
+
var startTime = performance.now();
|
|
270
|
+
var tick = function (now) {
|
|
271
|
+
if (!__classPrivateFieldGet(_this, _WheelPhysics_animating, "f"))
|
|
257
272
|
return;
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
273
|
+
var elapsed = now - startTime;
|
|
274
|
+
var progress = Math.min(elapsed / durationMs, 1);
|
|
275
|
+
var eased = easeOutCubic(progress);
|
|
276
|
+
_this.offset = startOffset + (targetOffset - startOffset) * eased;
|
|
262
277
|
if (progress < 1) {
|
|
263
|
-
|
|
278
|
+
__classPrivateFieldSet(_this, _WheelPhysics_rafId, requestAnimationFrame(tick), "f");
|
|
264
279
|
}
|
|
265
280
|
else {
|
|
266
281
|
// Snap to exact target to avoid float accumulation
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
282
|
+
_this.offset = targetOffset;
|
|
283
|
+
__classPrivateFieldSet(_this, _WheelPhysics_rafId, null, "f");
|
|
284
|
+
__classPrivateFieldSet(_this, _WheelPhysics_animating, false, "f");
|
|
285
|
+
__classPrivateFieldGet(_this, _WheelPhysics_onSnap, "f").call(_this, targetIndex);
|
|
271
286
|
}
|
|
272
287
|
};
|
|
273
|
-
this
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
288
|
+
__classPrivateFieldSet(this, _WheelPhysics_rafId, requestAnimationFrame(tick), "f");
|
|
289
|
+
};
|
|
290
|
+
Object.defineProperty(WheelPhysics.prototype, "currentIndex", {
|
|
291
|
+
/**
|
|
292
|
+
* Returns the option index that the current offset visually corresponds to.
|
|
293
|
+
* Used to guard against redundant animations when the wheel is already positioned correctly.
|
|
294
|
+
*/
|
|
295
|
+
get: function () {
|
|
296
|
+
var raw = __classPrivateFieldGet(this, _WheelPhysics_instances, "m", _WheelPhysics_offsetToIndex).call(this, this.offset);
|
|
297
|
+
return __classPrivateFieldGet(this, _WheelPhysics_infinite, "f")
|
|
298
|
+
? wrapIndex(raw, __classPrivateFieldGet(this, _WheelPhysics_options, "f").length)
|
|
299
|
+
: clampIndex(raw, __classPrivateFieldGet(this, _WheelPhysics_options, "f").length);
|
|
300
|
+
},
|
|
301
|
+
enumerable: false,
|
|
302
|
+
configurable: true
|
|
303
|
+
});
|
|
285
304
|
/**
|
|
286
305
|
* Immediately sets the offset to the position for the given index, no animation.
|
|
287
306
|
* Used for initial render and controlled value updates.
|
|
288
307
|
*/
|
|
289
|
-
jumpTo(index) {
|
|
290
|
-
this
|
|
291
|
-
this.offset = this
|
|
292
|
-
}
|
|
308
|
+
WheelPhysics.prototype.jumpTo = function (index) {
|
|
309
|
+
__classPrivateFieldGet(this, _WheelPhysics_instances, "m", _WheelPhysics_cancelRaf).call(this);
|
|
310
|
+
this.offset = __classPrivateFieldGet(this, _WheelPhysics_instances, "m", _WheelPhysics_indexToOffset).call(this, index);
|
|
311
|
+
};
|
|
293
312
|
/**
|
|
294
313
|
* Cancels any in-progress animation.
|
|
295
314
|
*/
|
|
296
|
-
cancelAnimation() {
|
|
297
|
-
this
|
|
298
|
-
}
|
|
315
|
+
WheelPhysics.prototype.cancelAnimation = function () {
|
|
316
|
+
__classPrivateFieldGet(this, _WheelPhysics_instances, "m", _WheelPhysics_cancelRaf).call(this);
|
|
317
|
+
};
|
|
299
318
|
/**
|
|
300
319
|
* Cleans up RAF on component destroy.
|
|
301
320
|
*/
|
|
302
|
-
destroy() {
|
|
321
|
+
WheelPhysics.prototype.destroy = function () {
|
|
303
322
|
this.cancelAnimation();
|
|
323
|
+
};
|
|
324
|
+
return WheelPhysics;
|
|
325
|
+
}());
|
|
326
|
+
export { WheelPhysics };
|
|
327
|
+
_WheelPhysics_itemHeight = new WeakMap(), _WheelPhysics_visibleCount = new WeakMap(), _WheelPhysics_dragSensitivity = new WeakMap(), _WheelPhysics_scrollSensitivity = new WeakMap(), _WheelPhysics_options = new WeakMap(), _WheelPhysics_onSnap = new WeakMap(), _WheelPhysics_infinite = new WeakMap(), _WheelPhysics_rafId = new WeakMap(), _WheelPhysics_isDragging = new WeakMap(), _WheelPhysics_dragStartOffset = new WeakMap(), _WheelPhysics_dragStartY = new WeakMap(), _WheelPhysics_yList = new WeakMap(), _WheelPhysics_lastWheelTime = new WeakMap(), _WheelPhysics_animating = new WeakMap(), _WheelPhysics_instances = new WeakSet(), _WheelPhysics_cancelRaf = function _WheelPhysics_cancelRaf() {
|
|
328
|
+
if (__classPrivateFieldGet(this, _WheelPhysics_rafId, "f") !== null) {
|
|
329
|
+
cancelAnimationFrame(__classPrivateFieldGet(this, _WheelPhysics_rafId, "f"));
|
|
330
|
+
__classPrivateFieldSet(this, _WheelPhysics_rafId, null, "f");
|
|
304
331
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
this.#animating = false;
|
|
314
|
-
}
|
|
315
|
-
/**
|
|
316
|
-
* Converts an option index to a translateY offset, accounting for before-ghost
|
|
317
|
-
* rows prepended to the DOM container in infinite mode.
|
|
318
|
-
*
|
|
319
|
-
* In infinite mode the container begins with N = options.length ghost rows, so
|
|
320
|
-
* real item[i] sits at DOM position (N + i) * itemHeight. The offset must be
|
|
321
|
-
* shifted by -N * itemHeight relative to the non-infinite formula.
|
|
322
|
-
*/
|
|
323
|
-
#indexToOffset(index) {
|
|
324
|
-
const ghostCount = this.#infinite ? this.#options.length : 0;
|
|
325
|
-
return indexToOffset(index + ghostCount, this.#itemHeight, this.#visibleCount);
|
|
326
|
-
}
|
|
327
|
-
/**
|
|
328
|
-
* Converts a translateY offset back to an option index, accounting for the
|
|
329
|
-
* before-ghost prefix in infinite mode (inverse of #indexToOffset).
|
|
330
|
-
*/
|
|
331
|
-
#offsetToIndex(offset) {
|
|
332
|
-
const ghostCount = this.#infinite ? this.#options.length : 0;
|
|
333
|
-
return offsetToIndex(offset, this.#itemHeight, this.#visibleCount) - ghostCount;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
332
|
+
__classPrivateFieldSet(this, _WheelPhysics_animating, false, "f");
|
|
333
|
+
}, _WheelPhysics_indexToOffset = function _WheelPhysics_indexToOffset(index) {
|
|
334
|
+
var ghostCount = __classPrivateFieldGet(this, _WheelPhysics_infinite, "f") ? __classPrivateFieldGet(this, _WheelPhysics_options, "f").length : 0;
|
|
335
|
+
return indexToOffset(index + ghostCount, __classPrivateFieldGet(this, _WheelPhysics_itemHeight, "f"), __classPrivateFieldGet(this, _WheelPhysics_visibleCount, "f"));
|
|
336
|
+
}, _WheelPhysics_offsetToIndex = function _WheelPhysics_offsetToIndex(offset) {
|
|
337
|
+
var ghostCount = __classPrivateFieldGet(this, _WheelPhysics_infinite, "f") ? __classPrivateFieldGet(this, _WheelPhysics_options, "f").length : 0;
|
|
338
|
+
return offsetToIndex(offset, __classPrivateFieldGet(this, _WheelPhysics_itemHeight, "f"), __classPrivateFieldGet(this, _WheelPhysics_visibleCount, "f")) - ghostCount;
|
|
339
|
+
};
|
|
336
340
|
// Unused export to prevent unused import warnings
|
|
337
341
|
void SNAP_BACK_DECELERATION;
|
|
@@ -11,21 +11,21 @@
|
|
|
11
11
|
// Physics constants (from React source v1.2.2)
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
13
|
/** Boundary resistance factor — how much drag is applied when pulling past the ends. */
|
|
14
|
-
export
|
|
14
|
+
export var RESISTANCE = 0.3;
|
|
15
15
|
/** Maximum scroll velocity in items/second. */
|
|
16
|
-
export
|
|
16
|
+
export var MAX_VELOCITY = 30;
|
|
17
17
|
/** Default drag sensitivity (pointer drag delta multiplier for inertia). */
|
|
18
|
-
export
|
|
18
|
+
export var DEFAULT_DRAG_SENSITIVITY = 3;
|
|
19
19
|
/** Default scroll sensitivity (wheel event multiplier for snap animation duration). */
|
|
20
|
-
export
|
|
20
|
+
export var DEFAULT_SCROLL_SENSITIVITY = 5;
|
|
21
21
|
/** Default height in pixels of each option row. */
|
|
22
|
-
export
|
|
22
|
+
export var DEFAULT_ITEM_HEIGHT = 30;
|
|
23
23
|
/** Default number of visible option rows. */
|
|
24
|
-
export
|
|
24
|
+
export var DEFAULT_VISIBLE_COUNT = 5;
|
|
25
25
|
/** Deceleration constant used in snap-back calculations. */
|
|
26
|
-
export
|
|
26
|
+
export var SNAP_BACK_DECELERATION = 10;
|
|
27
27
|
/** Minimum scaleY for cylindrical mode to prevent items collapsing to zero height. */
|
|
28
|
-
export
|
|
28
|
+
export var MIN_CYLINDRICAL_SCALE = 0.1;
|
|
29
29
|
// ---------------------------------------------------------------------------
|
|
30
30
|
// Pure physics functions
|
|
31
31
|
// ---------------------------------------------------------------------------
|
|
@@ -99,17 +99,18 @@ export function wrapIndex(index, optionsLength) {
|
|
|
99
99
|
* @returns The nearest enabled index
|
|
100
100
|
*/
|
|
101
101
|
export function snapToNearestEnabled(targetIndex, options) {
|
|
102
|
-
|
|
102
|
+
var _a, _b, _c;
|
|
103
|
+
if (!((_a = options[targetIndex]) === null || _a === void 0 ? void 0 : _a.disabled)) {
|
|
103
104
|
return targetIndex;
|
|
104
105
|
}
|
|
105
106
|
// Walk outward from targetIndex to find the nearest enabled option
|
|
106
|
-
for (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (lower >= 0 && !options[lower]
|
|
107
|
+
for (var delta = 1; delta < options.length; delta++) {
|
|
108
|
+
var lower = targetIndex - delta;
|
|
109
|
+
var upper = targetIndex + delta;
|
|
110
|
+
if (lower >= 0 && !((_b = options[lower]) === null || _b === void 0 ? void 0 : _b.disabled)) {
|
|
110
111
|
return lower;
|
|
111
112
|
}
|
|
112
|
-
if (upper < options.length && !options[upper]
|
|
113
|
+
if (upper < options.length && !((_c = options[upper]) === null || _c === void 0 ? void 0 : _c.disabled)) {
|
|
113
114
|
return upper;
|
|
114
115
|
}
|
|
115
116
|
}
|
|
@@ -130,13 +131,13 @@ export function calculateVelocity(yList, itemHeight) {
|
|
|
130
131
|
if (yList.length < 2) {
|
|
131
132
|
return 0;
|
|
132
133
|
}
|
|
133
|
-
|
|
134
|
-
|
|
134
|
+
var _a = yList[yList.length - 2], y1 = _a[0], t1 = _a[1];
|
|
135
|
+
var _b = yList[yList.length - 1], y2 = _b[0], t2 = _b[1];
|
|
135
136
|
if (t2 === t1) {
|
|
136
137
|
return 0;
|
|
137
138
|
}
|
|
138
|
-
|
|
139
|
-
|
|
139
|
+
var velocity = ((y2 - y1) / itemHeight) * (1000 / (t2 - t1));
|
|
140
|
+
var clamped = Math.max(-MAX_VELOCITY, Math.min(MAX_VELOCITY, velocity));
|
|
140
141
|
return clamped;
|
|
141
142
|
}
|
|
142
143
|
/**
|
|
@@ -152,11 +153,11 @@ export function calculateVelocity(yList, itemHeight) {
|
|
|
152
153
|
* @returns The rounded target index after inertia overshoot
|
|
153
154
|
*/
|
|
154
155
|
export function computeSnapTarget(currentIndexFromOffset, velocity, dragSensitivity) {
|
|
155
|
-
|
|
156
|
-
|
|
156
|
+
var baseDeceleration = dragSensitivity * 10;
|
|
157
|
+
var overshoot = (0.5 * velocity * velocity) / baseDeceleration;
|
|
157
158
|
// Velocity sign is inverted relative to index direction:
|
|
158
159
|
// drag down (positive velocity) increases offset → decreases index → overshoot toward lower index.
|
|
159
|
-
|
|
160
|
+
var rawTarget = currentIndexFromOffset - Math.sign(velocity) * overshoot;
|
|
160
161
|
return Math.round(rawTarget);
|
|
161
162
|
}
|
|
162
163
|
/**
|
|
@@ -170,7 +171,7 @@ export function computeSnapTarget(currentIndexFromOffset, velocity, dragSensitiv
|
|
|
170
171
|
* @returns Animation duration in seconds
|
|
171
172
|
*/
|
|
172
173
|
export function computeAnimationDuration(distance, scrollSensitivity) {
|
|
173
|
-
|
|
174
|
+
var raw = Math.sqrt(Math.abs(distance) / scrollSensitivity);
|
|
174
175
|
return Math.max(0.1, Math.min(0.6, raw));
|
|
175
176
|
}
|
|
176
177
|
/**
|
|
@@ -192,7 +193,7 @@ export function computeAnimationDuration(distance, scrollSensitivity) {
|
|
|
192
193
|
* @returns scaleY in range [MIN_CYLINDRICAL_SCALE, 1.0]
|
|
193
194
|
*/
|
|
194
195
|
export function cylindricalScaleY(slotIndex, offset, itemHeight, visibleCount) {
|
|
195
|
-
|
|
196
|
-
|
|
196
|
+
var dist = slotIndex + offset / itemHeight - Math.floor(visibleCount / 2);
|
|
197
|
+
var angle = (dist * Math.PI) / visibleCount;
|
|
197
198
|
return Math.max(MIN_CYLINDRICAL_SCALE, Math.cos(angle));
|
|
198
199
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uinstinct/svelte-wheel-picker",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "iOS-style wheel picker for Svelte 5 with inertia scrolling, infinite loop, and keyboard navigation",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,17 +25,6 @@
|
|
|
25
25
|
"peerDependencies": {
|
|
26
26
|
"svelte": "^5.0.0"
|
|
27
27
|
},
|
|
28
|
-
"scripts": {
|
|
29
|
-
"dev": "vite dev",
|
|
30
|
-
"build": "vite build",
|
|
31
|
-
"package": "svelte-package && rm -rf dist/__tests__ && rm -f dist/*.test.js dist/*.test.d.ts && publint",
|
|
32
|
-
"prepack": "npm run package",
|
|
33
|
-
"test": "PLAYWRIGHT_BROWSERS_PATH=.playwright vitest run",
|
|
34
|
-
"test:watch": "PLAYWRIGHT_BROWSERS_PATH=.playwright vitest",
|
|
35
|
-
"lint": "eslint .",
|
|
36
|
-
"format": "prettier --write .",
|
|
37
|
-
"registry:build": "shadcn-svelte registry build"
|
|
38
|
-
},
|
|
39
28
|
"devDependencies": {
|
|
40
29
|
"@eslint/js": "10.0.1",
|
|
41
30
|
"@sveltejs/adapter-vercel": "^6.3.3",
|
|
@@ -57,5 +46,15 @@
|
|
|
57
46
|
"vite": "8.0.1",
|
|
58
47
|
"vitest": "4.1.0",
|
|
59
48
|
"vitest-browser-svelte": "2.1.0"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"dev": "vite dev",
|
|
52
|
+
"build": "vite build",
|
|
53
|
+
"package": "svelte-package && rm -rf dist/__tests__ && rm -f dist/*.test.js dist/*.test.d.ts && publint",
|
|
54
|
+
"test": "PLAYWRIGHT_BROWSERS_PATH=.playwright vitest run",
|
|
55
|
+
"test:watch": "PLAYWRIGHT_BROWSERS_PATH=.playwright vitest",
|
|
56
|
+
"lint": "eslint .",
|
|
57
|
+
"format": "prettier --write .",
|
|
58
|
+
"registry:build": "shadcn-svelte registry build"
|
|
60
59
|
}
|
|
61
|
-
}
|
|
60
|
+
}
|