@enact/limestone 1.9.3 → 1.9.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.
|
@@ -35,7 +35,7 @@ jobs:
|
|
|
35
35
|
|
|
36
36
|
- name: Clone and setup Enact CLI
|
|
37
37
|
run: |
|
|
38
|
-
git clone --branch=7.2.
|
|
38
|
+
git clone --branch=release/7.2.x.develop --depth 1 https://github.com/enactjs/cli ../cli
|
|
39
39
|
pushd ../cli
|
|
40
40
|
npm install
|
|
41
41
|
npm link
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
The following is a curated list of changes in the Enact limestone module, newest changes on the top.
|
|
4
4
|
|
|
5
|
+
## [1.9.4] - 2026-06-18
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- `limestone/VirtualList` focus jump and scroll freeze when scrolled by long press
|
|
10
|
+
|
|
5
11
|
## [1.9.3] - 2026-04-20
|
|
6
12
|
|
|
7
13
|
### Fixed
|
|
@@ -27,6 +27,14 @@ var keyDownUp = function keyDownUp(keyCode) {
|
|
|
27
27
|
});
|
|
28
28
|
};
|
|
29
29
|
};
|
|
30
|
+
var keyDownRepeat = function keyDownRepeat(keyCode) {
|
|
31
|
+
return function (elm) {
|
|
32
|
+
return _react.fireEvent.keyDown(elm, {
|
|
33
|
+
keyCode: keyCode,
|
|
34
|
+
repeat: true
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
};
|
|
30
38
|
var pressLeftKey = keyDownUp(37);
|
|
31
39
|
var pressRightKey = keyDownUp(39);
|
|
32
40
|
var pressUpKey = keyDownUp(38);
|
|
@@ -148,6 +156,37 @@ describe('VirtualList useEvent', function () {
|
|
|
148
156
|
expect(spy).toHaveBeenCalled();
|
|
149
157
|
global.Element.prototype.scrollTo = scrollToFn;
|
|
150
158
|
});
|
|
159
|
+
test('should handle repeat keydown on first VirtualList entry without error', function () {
|
|
160
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_VirtualList["default"], {
|
|
161
|
+
clientSize: clientSize,
|
|
162
|
+
dataSize: dataSize,
|
|
163
|
+
itemRenderer: renderItem,
|
|
164
|
+
itemSize: itemSize
|
|
165
|
+
}));
|
|
166
|
+
var list = _react.screen.getByRole('list');
|
|
167
|
+
var item0 = list.children.item(0).children.item(0);
|
|
168
|
+
focus(item0);
|
|
169
|
+
expect(currentFocusIndex).toBe(0);
|
|
170
|
+
keyDownRepeat(40)(item0);
|
|
171
|
+
expect(currentFocusIndex).toBe(0);
|
|
172
|
+
});
|
|
173
|
+
test('should handle repeat keydown when data-index jumps unexpectedly without error', function () {
|
|
174
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_VirtualList["default"], {
|
|
175
|
+
clientSize: clientSize,
|
|
176
|
+
dataSize: dataSize,
|
|
177
|
+
itemRenderer: renderItem,
|
|
178
|
+
itemSize: itemSize
|
|
179
|
+
}));
|
|
180
|
+
var list = _react.screen.getByRole('list');
|
|
181
|
+
var item0 = list.children.item(0).children.item(0);
|
|
182
|
+
var item1 = list.children.item(1).children.item(0);
|
|
183
|
+
focus(item0);
|
|
184
|
+
pressDownKey(item0);
|
|
185
|
+
expect(currentFocusIndex).toBe(1);
|
|
186
|
+
item1.dataset.index = '20';
|
|
187
|
+
keyDownRepeat(40)(item1);
|
|
188
|
+
expect(currentFocusIndex).toBe(1);
|
|
189
|
+
});
|
|
151
190
|
test('should scroll by page-down key', function () {
|
|
152
191
|
var spy = jest.fn(function () {});
|
|
153
192
|
var scrollToFn = global.Element.prototype.scrollTo;
|
package/VirtualList/useEvent.js
CHANGED
|
@@ -28,13 +28,14 @@ var isDown = (0, _keymap.is)('down'),
|
|
|
28
28
|
// should return -1 if index is not a number or a negative value
|
|
29
29
|
return number >= 0 ? number : -1;
|
|
30
30
|
};
|
|
31
|
-
var prevKeyDownIndex = -1;
|
|
32
31
|
var useEventKey = exports.useEventKey = function useEventKey(props, instances, context) {
|
|
33
32
|
// Mutable value
|
|
34
33
|
|
|
35
34
|
var mutableRef = (0, _react.useRef)({
|
|
36
35
|
fn: null
|
|
37
36
|
});
|
|
37
|
+
var prevKeyDownIndexRef = (0, _react.useRef)(-1);
|
|
38
|
+
var hasProcessedKeyDownRef = (0, _react.useRef)(false);
|
|
38
39
|
|
|
39
40
|
// Functions
|
|
40
41
|
|
|
@@ -121,6 +122,7 @@ var useEventKey = exports.useEventKey = function useEventKey(props, instances, c
|
|
|
121
122
|
var handle5WayKeyUp = context.handle5WayKeyUp,
|
|
122
123
|
handleDirectionKeyDown = context.handleDirectionKeyDown,
|
|
123
124
|
handlePageUpDownKeyDown = context.handlePageUpDownKeyDown,
|
|
125
|
+
resetAccelerator = context.resetAccelerator,
|
|
124
126
|
spotlightAcceleratorProcessKey = context.spotlightAcceleratorProcessKey;
|
|
125
127
|
function handleKeyDown(ev) {
|
|
126
128
|
var keyCode = ev.keyCode,
|
|
@@ -163,15 +165,50 @@ var useEventKey = exports.useEventKey = function useEventKey(props, instances, c
|
|
|
163
165
|
isRightMovement = _getNextIndex.isRightMovement,
|
|
164
166
|
isWrapped = _getNextIndex.isWrapped,
|
|
165
167
|
nextIndex = _getNextIndex.nextIndex;
|
|
168
|
+
var _scrollContentHandle$2 = scrollContentHandle.current,
|
|
169
|
+
dimensionToExtent = _scrollContentHandle$2.dimensionToExtent,
|
|
170
|
+
isPrimaryDirectionVertical = _scrollContentHandle$2.isPrimaryDirectionVertical;
|
|
171
|
+
|
|
172
|
+
// VirtualList recycles DOM nodes during scroll. If a node gets reused for a different index
|
|
173
|
+
// while browser focus stays on it, target.dataset.index reflects the new (wrong) index.
|
|
174
|
+
// Detect this by checking if the index jumped unnaturally during key repeat.
|
|
175
|
+
var isForwardKey = isPrimaryDirectionVertical ? isDownKey : isRightMovement;
|
|
176
|
+
var isBackwardKey = isPrimaryDirectionVertical ? isUpKey : isLeftMovement;
|
|
177
|
+
var isOutdatedIndex = repeat && prevKeyDownIndexRef.current !== -1 && (isForwardKey && (prevKeyDownIndexRef.current > index || index > prevKeyDownIndexRef.current + dimensionToExtent) || isBackwardKey && (prevKeyDownIndexRef.current < index || index < prevKeyDownIndexRef.current - dimensionToExtent));
|
|
178
|
+
|
|
179
|
+
// Block the first repeat event when entering VirtualList from outside with acceleration.
|
|
180
|
+
// prevKeyDownIndexRef is -1 only on first entry; a repeat here means key was held before entering.
|
|
181
|
+
var isFirstEntryRepeat = repeat && !hasProcessedKeyDownRef.current;
|
|
182
|
+
if (isFirstEntryRepeat) {
|
|
183
|
+
ev.preventDefault();
|
|
184
|
+
ev.stopPropagation();
|
|
185
|
+
resetAccelerator();
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (isOutdatedIndex) {
|
|
189
|
+
ev.preventDefault();
|
|
190
|
+
ev.stopPropagation();
|
|
191
|
+
resetAccelerator();
|
|
192
|
+
var correctedNextIndex = isForwardKey ? prevKeyDownIndexRef.current + dimensionToExtent : prevKeyDownIndexRef.current - dimensionToExtent;
|
|
193
|
+
if (correctedNextIndex >= 0 && correctedNextIndex < props.dataSize) {
|
|
194
|
+
var currentItemNode = instances.itemRefs.current[prevKeyDownIndexRef.current % scrollContentHandle.current.state.numOfItems];
|
|
195
|
+
var correctedTarget = currentItemNode && parseInt(currentItemNode.dataset.index) === prevKeyDownIndexRef.current ? currentItemNode : target;
|
|
196
|
+
handleDirectionKeyDown(ev, 'acceleratedKeyDown', {
|
|
197
|
+
isWrapped: false,
|
|
198
|
+
keyCode: keyCode,
|
|
199
|
+
nextIndex: correctedNextIndex,
|
|
200
|
+
repeat: repeat,
|
|
201
|
+
target: correctedTarget
|
|
202
|
+
});
|
|
203
|
+
prevKeyDownIndexRef.current = correctedNextIndex;
|
|
204
|
+
}
|
|
205
|
+
// At list boundary: keep prevKeyDownIndexRef.current unchanged so next event stays recoverable
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
166
208
|
if (nextIndex >= 0) {
|
|
167
209
|
// if the candidate is another item
|
|
168
210
|
ev.preventDefault();
|
|
169
211
|
ev.stopPropagation();
|
|
170
|
-
if (repeat && prevKeyDownIndex !== -1 && (isDownKey && prevKeyDownIndex > index || isUpKey && prevKeyDownIndex < index)) {
|
|
171
|
-
// Ignore keyEvent from item with wrong data-index (Workaround for data-index bug)
|
|
172
|
-
// Sometimes keyDown event occurs before the data-index updated, it causes reverse focus change
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
212
|
if (props.scrollContainerHandle && props.scrollContainerHandle.current) {
|
|
176
213
|
props.scrollContainerHandle.current.lastInputType = 'arrowKey';
|
|
177
214
|
}
|
|
@@ -188,9 +225,6 @@ var useEventKey = exports.useEventKey = function useEventKey(props, instances, c
|
|
|
188
225
|
focusableScrollbar = props.focusableScrollbar,
|
|
189
226
|
isHorizontalScrollbarVisible = props.isHorizontalScrollbarVisible,
|
|
190
227
|
isVerticalScrollbarVisible = props.isVerticalScrollbarVisible;
|
|
191
|
-
var _scrollContentHandle$2 = scrollContentHandle.current,
|
|
192
|
-
dimensionToExtent = _scrollContentHandle$2.dimensionToExtent,
|
|
193
|
-
isPrimaryDirectionVertical = _scrollContentHandle$2.isPrimaryDirectionVertical;
|
|
194
228
|
var column = index % dimensionToExtent;
|
|
195
229
|
var row = (index - column) % dataSize / dimensionToExtent;
|
|
196
230
|
var directions = {};
|
|
@@ -236,7 +270,8 @@ var useEventKey = exports.useEventKey = function useEventKey(props, instances, c
|
|
|
236
270
|
}
|
|
237
271
|
}
|
|
238
272
|
}
|
|
239
|
-
|
|
273
|
+
prevKeyDownIndexRef.current = index;
|
|
274
|
+
hasProcessedKeyDownRef.current = true;
|
|
240
275
|
if (isLeaving) {
|
|
241
276
|
handleDirectionKeyDown(ev, 'keyLeave');
|
|
242
277
|
}
|
|
@@ -99,6 +99,9 @@ var useSpottable = function useSpottable(props, instances) {
|
|
|
99
99
|
handle5WayKeyUp: function handle5WayKeyUp() {
|
|
100
100
|
SpotlightAccelerator.reset();
|
|
101
101
|
},
|
|
102
|
+
resetAccelerator: function resetAccelerator() {
|
|
103
|
+
SpotlightAccelerator.reset();
|
|
104
|
+
},
|
|
102
105
|
spotlightAcceleratorProcessKey: function spotlightAcceleratorProcessKey(ev) {
|
|
103
106
|
return SpotlightAccelerator.processKey(ev, nop);
|
|
104
107
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enact/limestone",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.4",
|
|
4
4
|
"description": "Large-screen/TV support library for Enact, containing a variety of UI components.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
"@enovaui/core-tokens": "^0.14.0",
|
|
48
48
|
"@enovaui/webos-tokens": "^0.14.0",
|
|
49
49
|
"classnames": "^2.5.1",
|
|
50
|
-
"ilib": "^14.
|
|
50
|
+
"ilib": "^14.22.0",
|
|
51
51
|
"invariant": "^2.2.4",
|
|
52
52
|
"prop-types": "^15.8.1",
|
|
53
53
|
"ramda": "^0.32.0",
|
|
54
|
-
"react": "^19.2.
|
|
55
|
-
"react-dom": "^19.2.
|
|
54
|
+
"react": "^19.2.7",
|
|
55
|
+
"react-dom": "^19.2.7",
|
|
56
56
|
"warning": "^4.0.3"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|