@enact/limestone 1.10.0 → 1.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/PULL_REQUEST_TEMPLATE.md +1 -0
- package/ActionGuide/ActionGuide.d.ts +1 -1
- package/ActionGuide/ActionGuide.module.css +7 -0
- package/Alert/Alert.d.ts +9 -0
- package/Alert/Alert.js +63 -21
- package/Alert/Alert.module.css +41 -9
- package/Alert/AlertImage.module.css +5 -1
- package/Alert/tests/Alert-specs.js +6 -2
- package/BodyText/BodyText.d.ts +1 -1
- package/BodyText/BodyText.js +14 -9
- package/BodyText/BodyText.module.css +22 -1
- package/Button/Button.d.ts +3 -3
- package/Button/Button.module.css +81 -63
- package/CHANGELOG.md +87 -0
- package/Card/Card.d.ts +81 -9
- package/Card/Card.js +324 -84
- package/Card/Card.module.css +200 -25
- package/Card/tests/Card-specs.js +100 -0
- package/Checkbox/Checkbox.d.ts +2 -2
- package/Checkbox/Checkbox.module.css +2 -5
- package/CheckboxItem/CheckboxItem.d.ts +8 -1
- package/CheckboxItem/CheckboxItem.js +39 -12
- package/CheckboxItem/CheckboxItem.module.css +228 -4
- package/Chips/Chip.module.css +5 -2
- package/ContextualMenuDecorator/ContextualMenuDecorator.d.ts +2 -2
- package/ContextualPopupDecorator/ContextualPopup.module.css +1 -1
- package/ContextualPopupDecorator/ContextualPopupDecorator.js +2 -4
- package/ContextualPopupDecorator/tests/ContextualPopupDecorator-specs.js +39 -2
- package/Dropdown/Dropdown.d.ts +2 -2
- package/Dropdown/Dropdown.module.css +7 -7
- package/FixedPopupPanels/FixedPopupPanels.d.ts +2 -2
- package/FlexiblePopupPanels/FlexiblePopupPanels.module.css +15 -3
- package/FlexiblePopupPanels/index.d.ts +2 -2
- package/FormCheckboxItem/FormCheckboxItem.d.ts +1 -1
- package/FormCheckboxItem/FormCheckboxItem.js +1 -0
- package/FormCheckboxItem/FormCheckboxItem.module.css +1 -1
- package/Heading/Heading.d.ts +2 -2
- package/Heading/Heading.module.css +16 -0
- package/Icon/Icon.d.ts +22 -1
- package/Icon/Icon.js +21 -0
- package/Icon/Icon.module.css +12 -0
- package/Icon/IconList.js +43 -1
- package/IconItem/IconItem.d.ts +2 -2
- package/IconItem/IconItem.module.css +27 -14
- package/Image/Image.d.ts +1 -1
- package/Image/Image.module.css +1 -1
- package/ImageItem/ImageItem.d.ts +2 -2
- package/ImageItem/ImageItem.js +3 -16
- package/ImageItem/ImageItem.module.css +122 -97
- package/ImageItem/tests/ImageItem-specs.js +6 -5
- package/Input/Input.module.css +33 -16
- package/Input/InputField.module.css +22 -4
- package/Input/index.d.ts +1 -1
- package/Input/tests/Input-specs.js +2 -2
- package/Input/tests/InputField-specs.js +1 -1
- package/Item/Item.d.ts +2 -2
- package/Item/Item.module.css +29 -16
- package/KeyGuide/KeyGuide.d.ts +2 -2
- package/KeyGuide/KeyGuide.module.css +10 -0
- package/MediaOverlay/MediaOverlay.d.ts +2 -2
- package/MediaOverlay/MediaOverlay.module.css +18 -9
- package/MediaPlayer/MediaControls.module.css +3 -0
- package/MediaPlayer/MediaSlider.module.css +1 -0
- package/MediaPlayer/Times.module.css +5 -1
- package/MediaPlayer/index.d.ts +2 -2
- package/PageViews/PageViews.module.css +6 -1
- package/Panels/Header.module.css +74 -56
- package/Panels/Panel.module.css +1 -1
- package/Panels/index.d.ts +1 -1
- package/Picker/Picker.d.ts +1 -1
- package/Popup/Popup.module.css +4 -1
- package/PopupTabLayout/PopupTabLayout.d.ts +6 -6
- package/PopupTabLayout/PopupTabLayout.module.css +24 -6
- package/ProgressBar/ProgressBar.d.ts +1 -1
- package/ProgressBar/ProgressBar.module.css +12 -12
- package/ProgressBar/ProgressBarTooltip.module.css +7 -7
- package/ProgressButton/ProgressButton.d.ts +2 -2
- package/QuickGuidePanels/QuickGuidePanels.module.css +1 -1
- package/RadioItem/RadioItem.d.ts +1 -1
- package/RadioItem/RadioItem.module.css +21 -18
- package/Scroller/EditableWrapper.js +2 -1
- package/Scroller/Scroller.d.ts +12 -0
- package/Scroller/Scroller.js +15 -0
- package/Scroller/Scroller.module.css +10 -0
- package/Scroller/tests/Scroller-specs.js +120 -2
- package/Scroller/useThemeScroller.js +25 -2
- package/Slider/Slider.d.ts +1 -1
- package/Slider/Slider.module.css +539 -303
- package/Spinner/Spinner.d.ts +1 -1
- package/Spinner/Spinner.module.css +2 -2
- package/Steps/Steps.d.ts +1 -1
- package/Steps/Steps.js +12 -6
- package/Steps/Steps.module.css +19 -2
- package/Switch/Switch.module.css +17 -6
- package/SwitchItem/SwitchItem.d.ts +1 -1
- package/TabLayout/RefocusDecorator.js +1 -1
- package/TabLayout/TabGroup.module.css +13 -7
- package/TabLayout/TabLayout.js +4 -0
- package/ThemeDecorator/ThemeDecorator.d.ts +1 -1
- package/ThemeDecorator/ThemeDecorator.module.css +22 -1
- package/TimePicker/TimePicker.module.css +3 -0
- package/TooltipDecorator/Tooltip.js +68 -7
- package/TooltipDecorator/Tooltip.module.css +44 -23
- package/TooltipDecorator/TooltipDecorator.d.ts +52 -0
- package/TooltipDecorator/TooltipDecorator.js +42 -0
- package/TooltipDecorator/TooltipLabel.js +67 -14
- package/TooltipDecorator/tests/TooltipDecorator-specs.js +46 -0
- package/TooltipDecorator/useTooltip.js +14 -2
- package/VideoPlayer/Feedback.module.css +3 -0
- package/VideoPlayer/FeedbackTooltip.module.css +7 -0
- package/VideoPlayer/MediaTitle.module.css +9 -1
- package/VirtualList/VirtualList.d.ts +24 -0
- package/VirtualList/VirtualList.js +30 -0
- package/VirtualList/tests/stickTo-specs.js +115 -0
- package/VirtualList/tests/useEvent-specs.js +39 -0
- package/VirtualList/useEvent.js +45 -10
- package/VirtualList/useThemeVirtualList.js +20 -2
- package/WizardPanels/WizardPanels.module.css +1 -1
- package/fonts/Limestone_Icons.ttf +0 -0
- package/internal/DateComponentPicker/DateComponentPicker.module.css +3 -3
- package/internal/DateTime/DateTime.module.css +3 -0
- package/internal/Picker/Picker.js +8 -10
- package/internal/Picker/Picker.module.css +92 -137
- package/package.json +14 -17
- package/styles/color-mixins.less +4 -60
- package/styles/colors-game.less +5 -5
- package/styles/colors.less +9 -10
- package/styles/mixins.less +0 -46
- package/styles/motion-mixins.less +16 -7
- package/styles/motions.less +2 -2
- package/styles/variables.less +186 -69
- package/useScroll/ScrollbarPlaceholder.js +8 -3
- package/useScroll/useScroll.js +3 -1
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
require("@testing-library/jest-dom");
|
|
4
|
+
var _spotlight = _interopRequireDefault(require("@enact/spotlight"));
|
|
4
5
|
var _react = require("@testing-library/react");
|
|
6
|
+
var _react2 = require("react");
|
|
5
7
|
var _Scroller = _interopRequireDefault(require("../Scroller"));
|
|
6
8
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
7
9
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
|
|
@@ -66,7 +68,7 @@ describe('Scroller', function () {
|
|
|
66
68
|
});
|
|
67
69
|
});
|
|
68
70
|
describe('focusable Scrollbar', function () {
|
|
69
|
-
test('should have
|
|
71
|
+
test('should have focusable body and thumb when \'focusableScrollbar\' is "byEnter"', function () {
|
|
70
72
|
var id = 'scroller';
|
|
71
73
|
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_Scroller["default"], {
|
|
72
74
|
"data-testid": id,
|
|
@@ -86,7 +88,7 @@ describe('Scroller', function () {
|
|
|
86
88
|
expect(scrollBody).toHaveClass(expected);
|
|
87
89
|
expect(verticalScrollbar).toHaveClass(expected);
|
|
88
90
|
});
|
|
89
|
-
test('should have
|
|
91
|
+
test('should have focusable scroll thumb when \'focusableScrollbar\' is true', function () {
|
|
90
92
|
var id = 'scroller';
|
|
91
93
|
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_Scroller["default"], {
|
|
92
94
|
"data-testid": id,
|
|
@@ -101,6 +103,93 @@ describe('Scroller', function () {
|
|
|
101
103
|
expect(scrollBody).not.toHaveClass(expected);
|
|
102
104
|
expect(verticalScrollbar).toHaveClass(expected);
|
|
103
105
|
});
|
|
106
|
+
describe('ScrollbarPlaceholder focus restoration', function () {
|
|
107
|
+
var focusSpy, pointerModeSpy, currentSpy, pausedSpy, containerSpy;
|
|
108
|
+
var placeholderElement;
|
|
109
|
+
var renderWithFocusedPlaceholder = function renderWithFocusedPlaceholder() {
|
|
110
|
+
placeholderElement = null;
|
|
111
|
+
currentSpy.mockImplementation(function () {
|
|
112
|
+
return placeholderElement;
|
|
113
|
+
});
|
|
114
|
+
var onRender = function onRender(id, phase) {
|
|
115
|
+
if (phase === 'mount') {
|
|
116
|
+
placeholderElement = document.querySelector('[data-spotlight-ignore-restore]');
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
var view = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_react2.Profiler, {
|
|
120
|
+
id: "placeholder",
|
|
121
|
+
onRender: onRender,
|
|
122
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Scroller["default"], {
|
|
123
|
+
focusableScrollbar: "byEnter",
|
|
124
|
+
verticalScrollbar: "visible",
|
|
125
|
+
children: contents
|
|
126
|
+
})
|
|
127
|
+
}));
|
|
128
|
+
currentSpy.mockImplementation(function () {
|
|
129
|
+
return null;
|
|
130
|
+
});
|
|
131
|
+
focusSpy.mockClear();
|
|
132
|
+
return view;
|
|
133
|
+
};
|
|
134
|
+
beforeEach(function () {
|
|
135
|
+
jest.useFakeTimers();
|
|
136
|
+
focusSpy = jest.spyOn(_spotlight["default"], 'focus').mockImplementation(function () {
|
|
137
|
+
return true;
|
|
138
|
+
});
|
|
139
|
+
pointerModeSpy = jest.spyOn(_spotlight["default"], 'getPointerMode').mockReturnValue(false);
|
|
140
|
+
currentSpy = jest.spyOn(_spotlight["default"], 'getCurrent').mockReturnValue(null);
|
|
141
|
+
pausedSpy = jest.spyOn(_spotlight["default"], 'isPaused').mockReturnValue(false);
|
|
142
|
+
containerSpy = jest.spyOn(_spotlight["default"], 'getActiveContainer').mockReturnValue('active-container');
|
|
143
|
+
});
|
|
144
|
+
afterEach(function () {
|
|
145
|
+
focusSpy.mockRestore();
|
|
146
|
+
pointerModeSpy.mockRestore();
|
|
147
|
+
currentSpy.mockRestore();
|
|
148
|
+
pausedSpy.mockRestore();
|
|
149
|
+
containerSpy.mockRestore();
|
|
150
|
+
jest.useRealTimers();
|
|
151
|
+
});
|
|
152
|
+
test('should focus the active container after the placeholder disappears', function () {
|
|
153
|
+
renderWithFocusedPlaceholder();
|
|
154
|
+
(0, _react.act)(function () {
|
|
155
|
+
return jest.advanceTimersByTime(0);
|
|
156
|
+
});
|
|
157
|
+
expect(focusSpy).toHaveBeenCalledWith('active-container', {
|
|
158
|
+
toOuterContainer: true
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
test('should not focus when pointer mode is active', function () {
|
|
162
|
+
pointerModeSpy.mockReturnValue(true);
|
|
163
|
+
renderWithFocusedPlaceholder();
|
|
164
|
+
(0, _react.act)(function () {
|
|
165
|
+
return jest.advanceTimersByTime(0);
|
|
166
|
+
});
|
|
167
|
+
expect(focusSpy).not.toHaveBeenCalled();
|
|
168
|
+
});
|
|
169
|
+
test('should defer focus while spotlight is paused, then focus after 400ms once it unpauses', function () {
|
|
170
|
+
pausedSpy.mockReturnValue(true);
|
|
171
|
+
renderWithFocusedPlaceholder();
|
|
172
|
+
(0, _react.act)(function () {
|
|
173
|
+
return jest.advanceTimersByTime(0);
|
|
174
|
+
});
|
|
175
|
+
expect(focusSpy).not.toHaveBeenCalled();
|
|
176
|
+
pausedSpy.mockReturnValue(false);
|
|
177
|
+
(0, _react.act)(function () {
|
|
178
|
+
return jest.advanceTimersByTime(400);
|
|
179
|
+
});
|
|
180
|
+
expect(focusSpy).toHaveBeenCalledWith('active-container', {
|
|
181
|
+
toOuterContainer: true
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
test('should not focus after the 400ms retry if spotlight is still paused', function () {
|
|
185
|
+
pausedSpy.mockReturnValue(true);
|
|
186
|
+
renderWithFocusedPlaceholder();
|
|
187
|
+
(0, _react.act)(function () {
|
|
188
|
+
return jest.advanceTimersByTime(400);
|
|
189
|
+
});
|
|
190
|
+
expect(focusSpy).not.toHaveBeenCalled();
|
|
191
|
+
});
|
|
192
|
+
});
|
|
104
193
|
});
|
|
105
194
|
describe('Scrollbar accessibility', function () {
|
|
106
195
|
test('should set a custom "aria-label" to the scroll thumb in the horizontal scroll bar', function () {
|
|
@@ -156,4 +245,33 @@ describe('Scroller', function () {
|
|
|
156
245
|
expect(verticalScrollbar).toHaveClass('vertical');
|
|
157
246
|
});
|
|
158
247
|
});
|
|
248
|
+
describe('stickTo', function () {
|
|
249
|
+
test('should compute a stick-to-start scroll position when a contained item is focused', function () {
|
|
250
|
+
var scrollToFn = global.Element.prototype.scrollTo;
|
|
251
|
+
global.Element.prototype.scrollTo = jest.fn();
|
|
252
|
+
var pointerSpy = jest.spyOn(_spotlight["default"], 'getPointerMode').mockReturnValue(false);
|
|
253
|
+
var currentSpy = jest.spyOn(_spotlight["default"], 'getCurrent');
|
|
254
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_Scroller["default"], {
|
|
255
|
+
direction: "horizontal",
|
|
256
|
+
scrollToContentContainerOnFocus: false,
|
|
257
|
+
stickTo: "start",
|
|
258
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
259
|
+
style: {
|
|
260
|
+
width: '4000px'
|
|
261
|
+
},
|
|
262
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
|
|
263
|
+
"data-testid": "stick-target",
|
|
264
|
+
children: "Target"
|
|
265
|
+
})
|
|
266
|
+
})
|
|
267
|
+
}));
|
|
268
|
+
var target = _react.screen.getByTestId('stick-target');
|
|
269
|
+
currentSpy.mockReturnValue(target);
|
|
270
|
+
_react.fireEvent.focusIn(target);
|
|
271
|
+
expect(target).toBeInTheDocument();
|
|
272
|
+
currentSpy.mockRestore();
|
|
273
|
+
pointerSpy.mockRestore();
|
|
274
|
+
global.Element.prototype.scrollTo = scrollToFn;
|
|
275
|
+
});
|
|
276
|
+
});
|
|
159
277
|
});
|
|
@@ -284,8 +284,11 @@ var useSpottable = function useSpottable(props, instances) {
|
|
|
284
284
|
itemLeft = _getFocusedItemBounds.left,
|
|
285
285
|
itemWidth = _getFocusedItemBounds.width;
|
|
286
286
|
var rtl = props.rtl,
|
|
287
|
+
stickTo = props.stickTo,
|
|
287
288
|
coordinateCoefficient = rtl && !(_platform["default"].chrome < 85) ? -1 : 1,
|
|
288
|
-
|
|
289
|
+
_scrollContentHandle$ = scrollContentHandle.current.scrollBounds,
|
|
290
|
+
clientWidth = _scrollContentHandle$.clientWidth,
|
|
291
|
+
maxLeft = _scrollContentHandle$.maxLeft,
|
|
289
292
|
rtlDirection = rtl ? -1 : 1,
|
|
290
293
|
_scrollContentNode$ge = scrollContentNode.getBoundingClientRect(),
|
|
291
294
|
containerLeft = _scrollContentNode$ge.left,
|
|
@@ -293,6 +296,18 @@ var useSpottable = function useSpottable(props, instances) {
|
|
|
293
296
|
currentScrollLeft = rtl && coordinateCoefficient === 1 ? scrollContentHandle.current.scrollBounds.maxLeft - scrollLastPosition : scrollLastPosition,
|
|
294
297
|
newItemLeft = coordinateCoefficient * scrollContentNode.scrollLeft + (itemLeft - containerLeft);
|
|
295
298
|
var nextScrollLeft = scrollContentHandle.current.scrollPos.left;
|
|
299
|
+
if (stickTo === 'start') {
|
|
300
|
+
// Anchor the focused item to a fixed "focus position" near the start edge so the focus
|
|
301
|
+
// indicator stays put while the list scrolls beneath it. The offset matches the in-view
|
|
302
|
+
// threshold (`affordanceSize`) used by `calculatePositionOnFocus`.
|
|
303
|
+
var affordanceLeft = _resolution["default"].scale(_useScroll.affordanceSize);
|
|
304
|
+
|
|
305
|
+
// Position the item at the fixed slot, then clamp to the scroll bounds. Clamping handles
|
|
306
|
+
// the end of the list: the item can no longer reach the slot, so the list scrolls only to
|
|
307
|
+
// its last position while the focused item (including its full width) stays visible.
|
|
308
|
+
nextScrollLeft += rtlDirection * (newItemLeft - currentScrollLeft - affordanceLeft);
|
|
309
|
+
return Math.max(0, Math.min(nextScrollLeft, maxLeft));
|
|
310
|
+
}
|
|
296
311
|
if (newItemLeft + itemWidth > clientWidth + currentScrollLeft && itemWidth < clientWidth) {
|
|
297
312
|
// If focus is moved to an element outside of view area (to the right), scroller will move
|
|
298
313
|
// to the right just enough to show the current `focusedItem`. This does not apply to
|
|
@@ -325,7 +340,11 @@ var useSpottable = function useSpottable(props, instances) {
|
|
|
325
340
|
}
|
|
326
341
|
var containerRect = (0, _utils.getRect)(containerNode);
|
|
327
342
|
var itemRect = (0, _utils.getRect)(item);
|
|
328
|
-
|
|
343
|
+
|
|
344
|
+
// When anchoring focus to a fixed slot, always recompute the scroll position so each newly
|
|
345
|
+
// focused item is pulled to the slot rather than only when it falls outside the view.
|
|
346
|
+
var stickToStart = props.stickTo === 'start';
|
|
347
|
+
if (horizontal && (stickToStart || !(itemRect.left >= containerRect.left + _resolution["default"].scale(_useScroll.affordanceSize) && itemRect.right <= containerRect.right - _resolution["default"].scale(_useScroll.affordanceSize)))) {
|
|
329
348
|
scrollContentHandle.current.scrollPos.left = calculateScrollLeft(item, scrollPosition);
|
|
330
349
|
}
|
|
331
350
|
if (vertical && !(itemRect.top >= containerRect.top && itemRect.bottom <= containerRect.bottom - _resolution["default"].scale(_useScroll.affordanceSize))) {
|
|
@@ -363,6 +382,7 @@ var useThemeScroller = exports.useThemeScroller = function useThemeScroller(prop
|
|
|
363
382
|
delete rest.scrollContentHandle;
|
|
364
383
|
delete rest.setThemeScrollContentHandle;
|
|
365
384
|
delete rest.spotlightId;
|
|
385
|
+
delete rest.stickTo;
|
|
366
386
|
|
|
367
387
|
// Hooks
|
|
368
388
|
var isScrollbarVisible = isHorizontalScrollbarVisible || isVerticalScrollbarVisible;
|
|
@@ -377,6 +397,9 @@ var useThemeScroller = exports.useThemeScroller = function useThemeScroller(prop
|
|
|
377
397
|
var _ref3 = props.focusableScrollbar === 'byEnter' ? getFocusableBodyProps(scrollContainerRef, contentId, isScrollbarVisible) : {},
|
|
378
398
|
setNavigableFilter = _ref3.setNavigableFilter,
|
|
379
399
|
focusableBodyProps = _objectWithoutProperties(_ref3, _excluded2);
|
|
400
|
+
if (focusableBodyProps.className) {
|
|
401
|
+
focusableBodyProps.className = (0, _classnames["default"])(focusableBodyProps.className, isVerticalScrollbarVisible && _ScrollerModule["default"].hasVerticalScrollbar, isHorizontalScrollbarVisible && _ScrollerModule["default"].hasHorizontalScrollbar);
|
|
402
|
+
}
|
|
380
403
|
(0, _react.useLayoutEffect)(function () {
|
|
381
404
|
// Initial filter setting
|
|
382
405
|
if (setNavigableFilter) {
|
package/Slider/Slider.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { ChangeableProps as ui_Changeable_ChangeableProps } from "@enact/ui/Changeable";
|
|
4
4
|
import { SpottableProps as spotlight_Spottable_SpottableProps } from "@enact/spotlight/Spottable";
|
|
5
|
-
import { SkinnableProps as limestone_Skinnable_SkinnableProps } from "limestone/Skinnable";
|
|
5
|
+
import { SkinnableProps as limestone_Skinnable_SkinnableProps } from "@enact/limestone/Skinnable";
|
|
6
6
|
import { SlottableProps as ui_Slottable_SlottableProps } from "@enact/ui/Slottable";
|
|
7
7
|
import { SliderDecoratorProps as ui_Slider_SliderDecoratorProps } from "@enact/ui/Slider";
|
|
8
8
|
import * as React from "react";
|