@enact/limestone 1.10.1 → 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.
Files changed (122) hide show
  1. package/.github/PULL_REQUEST_TEMPLATE.md +1 -0
  2. package/ActionGuide/ActionGuide.d.ts +1 -1
  3. package/ActionGuide/ActionGuide.module.css +3 -0
  4. package/Alert/Alert.d.ts +9 -0
  5. package/Alert/Alert.js +63 -21
  6. package/Alert/Alert.module.css +41 -9
  7. package/Alert/AlertImage.module.css +5 -1
  8. package/Alert/tests/Alert-specs.js +6 -2
  9. package/BodyText/BodyText.d.ts +1 -1
  10. package/BodyText/BodyText.js +14 -9
  11. package/BodyText/BodyText.module.css +1 -1
  12. package/Button/Button.d.ts +3 -3
  13. package/Button/Button.module.css +14 -28
  14. package/CHANGELOG.md +48 -1
  15. package/Card/Card.d.ts +81 -9
  16. package/Card/Card.js +321 -84
  17. package/Card/Card.module.css +171 -20
  18. package/Card/tests/Card-specs.js +100 -0
  19. package/Checkbox/Checkbox.d.ts +2 -2
  20. package/Checkbox/Checkbox.module.css +2 -9
  21. package/CheckboxItem/CheckboxItem.d.ts +8 -1
  22. package/CheckboxItem/CheckboxItem.js +39 -12
  23. package/CheckboxItem/CheckboxItem.module.css +228 -4
  24. package/Chips/Chip.module.css +2 -2
  25. package/ContextualMenuDecorator/ContextualMenuDecorator.d.ts +2 -2
  26. package/ContextualPopupDecorator/ContextualPopup.module.css +1 -1
  27. package/ContextualPopupDecorator/ContextualPopupDecorator.js +2 -4
  28. package/ContextualPopupDecorator/tests/ContextualPopupDecorator-specs.js +39 -2
  29. package/Dropdown/Dropdown.d.ts +2 -2
  30. package/Dropdown/Dropdown.module.css +7 -7
  31. package/FixedPopupPanels/FixedPopupPanels.d.ts +2 -2
  32. package/FlexiblePopupPanels/FlexiblePopupPanels.module.css +15 -3
  33. package/FlexiblePopupPanels/index.d.ts +2 -2
  34. package/FormCheckboxItem/FormCheckboxItem.d.ts +1 -1
  35. package/FormCheckboxItem/FormCheckboxItem.js +1 -0
  36. package/FormCheckboxItem/FormCheckboxItem.module.css +1 -1
  37. package/Heading/Heading.d.ts +2 -2
  38. package/Icon/Icon.d.ts +22 -1
  39. package/Icon/Icon.js +21 -0
  40. package/Icon/IconList.js +43 -1
  41. package/IconItem/IconItem.d.ts +2 -2
  42. package/IconItem/IconItem.module.css +11 -14
  43. package/Image/Image.d.ts +1 -1
  44. package/Image/Image.module.css +1 -1
  45. package/ImageItem/ImageItem.d.ts +2 -2
  46. package/ImageItem/ImageItem.js +3 -16
  47. package/ImageItem/ImageItem.module.css +105 -97
  48. package/ImageItem/tests/ImageItem-specs.js +6 -5
  49. package/Input/Input.module.css +8 -7
  50. package/Input/InputField.module.css +4 -4
  51. package/Input/index.d.ts +1 -1
  52. package/Input/tests/Input-specs.js +2 -2
  53. package/Input/tests/InputField-specs.js +1 -1
  54. package/Item/Item.d.ts +2 -2
  55. package/Item/Item.module.css +27 -15
  56. package/KeyGuide/KeyGuide.d.ts +2 -2
  57. package/MediaOverlay/MediaOverlay.d.ts +2 -2
  58. package/MediaOverlay/MediaOverlay.module.css +2 -5
  59. package/MediaPlayer/MediaSlider.module.css +1 -0
  60. package/MediaPlayer/Times.module.css +1 -1
  61. package/MediaPlayer/index.d.ts +2 -2
  62. package/PageViews/PageViews.module.css +2 -1
  63. package/Panels/Header.module.css +40 -28
  64. package/Panels/Panel.module.css +1 -1
  65. package/Panels/index.d.ts +1 -1
  66. package/Picker/Picker.d.ts +1 -1
  67. package/Popup/Popup.module.css +4 -1
  68. package/PopupTabLayout/PopupTabLayout.d.ts +6 -6
  69. package/PopupTabLayout/PopupTabLayout.module.css +6 -6
  70. package/ProgressBar/ProgressBar.d.ts +1 -1
  71. package/ProgressBar/ProgressBar.module.css +12 -12
  72. package/ProgressBar/ProgressBarTooltip.module.css +7 -7
  73. package/ProgressButton/ProgressButton.d.ts +2 -2
  74. package/QuickGuidePanels/QuickGuidePanels.module.css +1 -1
  75. package/RadioItem/RadioItem.d.ts +1 -1
  76. package/RadioItem/RadioItem.module.css +18 -20
  77. package/Scroller/Scroller.d.ts +12 -0
  78. package/Scroller/Scroller.js +15 -0
  79. package/Scroller/tests/Scroller-specs.js +29 -0
  80. package/Scroller/useThemeScroller.js +22 -2
  81. package/Slider/Slider.d.ts +1 -1
  82. package/Slider/Slider.module.css +539 -300
  83. package/Spinner/Spinner.d.ts +1 -1
  84. package/Spinner/Spinner.module.css +2 -2
  85. package/Steps/Steps.d.ts +1 -1
  86. package/Steps/Steps.js +12 -6
  87. package/Steps/Steps.module.css +16 -2
  88. package/Switch/Switch.module.css +2 -5
  89. package/SwitchItem/SwitchItem.d.ts +1 -1
  90. package/TabLayout/RefocusDecorator.js +1 -1
  91. package/TabLayout/TabGroup.module.css +12 -6
  92. package/TabLayout/TabLayout.js +4 -0
  93. package/ThemeDecorator/ThemeDecorator.d.ts +1 -1
  94. package/ThemeDecorator/ThemeDecorator.module.css +22 -1
  95. package/TooltipDecorator/Tooltip.js +68 -7
  96. package/TooltipDecorator/Tooltip.module.css +40 -23
  97. package/TooltipDecorator/TooltipDecorator.d.ts +52 -0
  98. package/TooltipDecorator/TooltipDecorator.js +42 -0
  99. package/TooltipDecorator/TooltipLabel.js +67 -14
  100. package/TooltipDecorator/tests/TooltipDecorator-specs.js +46 -0
  101. package/TooltipDecorator/useTooltip.js +14 -2
  102. package/VideoPlayer/MediaTitle.module.css +1 -1
  103. package/VirtualList/VirtualList.d.ts +24 -0
  104. package/VirtualList/VirtualList.js +30 -0
  105. package/VirtualList/tests/stickTo-specs.js +115 -0
  106. package/VirtualList/tests/useEvent-specs.js +39 -0
  107. package/VirtualList/useEvent.js +45 -10
  108. package/VirtualList/useThemeVirtualList.js +20 -2
  109. package/WizardPanels/WizardPanels.module.css +1 -1
  110. package/fonts/Limestone_Icons.ttf +0 -0
  111. package/internal/DateComponentPicker/DateComponentPicker.module.css +3 -3
  112. package/internal/Picker/Picker.js +8 -10
  113. package/internal/Picker/Picker.module.css +74 -141
  114. package/package.json +11 -14
  115. package/styles/color-mixins.less +4 -60
  116. package/styles/colors-game.less +5 -5
  117. package/styles/colors.less +9 -10
  118. package/styles/mixins.less +0 -46
  119. package/styles/motion-mixins.less +16 -7
  120. package/styles/motions.less +2 -2
  121. package/styles/variables.less +71 -46
  122. package/useScroll/useScroll.js +3 -1
@@ -29,11 +29,37 @@ export interface TooltipDecoratorProps {
29
29
  * Disables the component but does not affect tooltip operation.
30
30
  */
31
31
  disabled?: boolean;
32
+ /**
33
+ * `Tooltip` without the arrow.
34
+ */
35
+ noArrow?: boolean;
36
+ /**
37
+ * Customizes the component by mapping the supplied collection of CSS class names to the
38
+ corresponding internal elements and states of this component.
39
+ *
40
+ * The following classes are supported:
41
+ * * `tooltip` - The root class name
42
+ */
43
+ tooltipCss?: object;
32
44
  /**
33
45
  * Time to wait (in milliseconds) before showing tooltip on hover.
34
46
  */
35
47
  tooltipDelay?: number;
36
48
  /**
49
+ * Source for the image.
50
+ String value or Object of values used to determine which image will appear on
51
+ a specific screenSize.
52
+ */
53
+ tooltipImage?: string | object;
54
+ /**
55
+ * The size of the image.
56
+ *
57
+ * The following properties should be provided:
58
+ * * `height` - The height of the image
59
+ * * `width` - The width of the image
60
+ */
61
+ tooltipImageSize?: object;
62
+ /**
37
63
  * Allows the tooltip to marquee.
38
64
  *
39
65
  * Specifying a
@@ -175,6 +201,10 @@ account for that in your provided offset value.
175
201
  the marquee to that size.
176
202
  */
177
203
  marquee?: boolean;
204
+ /**
205
+ * `Tooltip` without the arrow.
206
+ */
207
+ noArrow?: boolean;
178
208
  /**
179
209
  * Style object for tooltip position.
180
210
  */
@@ -187,6 +217,28 @@ When this is not specified, the implication is that the component is "absolutely
187
217
  positioned, relative to the viewport, rather than its parent layer.
188
218
  */
189
219
  relative?: boolean;
220
+ /**
221
+ * Customizes the component by mapping the supplied collection of CSS class names to the
222
+ corresponding internal elements and states of this component.
223
+ *
224
+ * The following classes are supported:
225
+ * * `tooltip` - The root class name
226
+ */
227
+ tooltipCss?: object;
228
+ /**
229
+ * Source for the image.
230
+ String value or Object of values used to determine which image will appear on
231
+ a specific screenSize.
232
+ */
233
+ tooltipImage?: string | object;
234
+ /**
235
+ * The size of the image.
236
+ *
237
+ * The following properties should be provided:
238
+ * * `height` - The height of the image
239
+ * * `width` - The width of the image
240
+ */
241
+ tooltipImageSize?: object;
190
242
  /**
191
243
  * Called when the tooltip mounts/unmounts, giving a reference to the DOM.
192
244
  */
@@ -124,6 +124,13 @@ var TooltipDecorator = exports.TooltipDecorator = (0, _hoc["default"])(defaultCo
124
124
  * @public
125
125
  */
126
126
  disabled: _propTypes["default"].bool,
127
+ /**
128
+ * `Tooltip` without the arrow.
129
+ *
130
+ * @type {Boolean}
131
+ * @public
132
+ */
133
+ noArrow: _propTypes["default"].bool,
127
134
  /**
128
135
  * Indicates the tooltip text direction is right-to-left.
129
136
  *
@@ -131,6 +138,18 @@ var TooltipDecorator = exports.TooltipDecorator = (0, _hoc["default"])(defaultCo
131
138
  * @private
132
139
  */
133
140
  rtl: _propTypes["default"].bool,
141
+ /**
142
+ * Customizes the component by mapping the supplied collection of CSS class names to the
143
+ * corresponding internal elements and states of this component.
144
+ *
145
+ * The following classes are supported:
146
+ *
147
+ * * `tooltip` - The root class name
148
+ *
149
+ * @type {Object}
150
+ * @public
151
+ */
152
+ tooltipCss: _propTypes["default"].object,
134
153
  /**
135
154
  * Time to wait (in milliseconds) before showing tooltip on hover.
136
155
  *
@@ -139,6 +158,29 @@ var TooltipDecorator = exports.TooltipDecorator = (0, _hoc["default"])(defaultCo
139
158
  * @public
140
159
  */
141
160
  tooltipDelay: _propTypes["default"].number,
161
+ /**
162
+ * Source for the image.
163
+ * String value or Object of values used to determine which image will appear on
164
+ * a specific screenSize.
165
+ *
166
+ * @type {String|Object}
167
+ * @public
168
+ */
169
+ tooltipImage: _propTypes["default"].oneOfType([_propTypes["default"].string, _propTypes["default"].object]),
170
+ /**
171
+ * The size of the image.
172
+ *
173
+ * The following properties should be provided:
174
+ * * `height` - The height of the image
175
+ * * `width` - The width of the image
176
+ *
177
+ * @type {Object}
178
+ * @public
179
+ */
180
+ tooltipImageSize: _propTypes["default"].shape({
181
+ height: _propTypes["default"].number,
182
+ width: _propTypes["default"].number
183
+ }),
142
184
  /**
143
185
  * Allows the tooltip to marquee.
144
186
  *
@@ -8,10 +8,11 @@ var _kind = _interopRequireDefault(require("@enact/core/kind"));
8
8
  var _util = require("@enact/i18n/util");
9
9
  var _resolution = require("@enact/ui/resolution");
10
10
  var _propTypes = _interopRequireDefault(require("prop-types"));
11
+ var _Image = _interopRequireDefault(require("../Image"));
11
12
  var _Marquee = _interopRequireDefault(require("../Marquee"));
12
13
  var _TooltipModule = _interopRequireDefault(require("./Tooltip.module.css"));
13
14
  var _jsxRuntime = require("react/jsx-runtime");
14
- var _excluded = ["centered", "children", "marquee"];
15
+ var _excluded = ["centered", "children", "css", "tooltipImage", "marquee"];
15
16
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
16
17
  function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
17
18
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
@@ -55,6 +56,36 @@ var TooltipLabel = exports.TooltipLabel = (0, _kind["default"])({
55
56
  * @public
56
57
  */
57
58
  marquee: _propTypes["default"].bool,
59
+ /**
60
+ * `Tooltip` without the arrow.
61
+ *
62
+ * @type {Boolean}
63
+ * @public
64
+ */
65
+ noArrow: _propTypes["default"].bool,
66
+ /**
67
+ * Source for the image.
68
+ * String value or Object of values used to determine which image will appear on
69
+ * a specific screenSize.
70
+ *
71
+ * @type {String|Object}
72
+ * @public
73
+ */
74
+ tooltipImage: _propTypes["default"].oneOfType([_propTypes["default"].string, _propTypes["default"].object]),
75
+ /**
76
+ * The size of the image.
77
+ *
78
+ * The following properties should be provided:
79
+ * * `height` - The height of the image
80
+ * * `width` - The width of the image
81
+ *
82
+ * @type {Object}
83
+ * @public
84
+ */
85
+ tooltipImageSize: _propTypes["default"].shape({
86
+ height: _propTypes["default"].number,
87
+ width: _propTypes["default"].number
88
+ }),
58
89
  /**
59
90
  * The width of tooltip content.
60
91
  *
@@ -73,43 +104,65 @@ var TooltipLabel = exports.TooltipLabel = (0, _kind["default"])({
73
104
  width: _propTypes["default"].oneOfType([_propTypes["default"].number, _propTypes["default"].string])
74
105
  },
75
106
  styles: {
76
- css: _TooltipModule["default"]
107
+ css: _TooltipModule["default"],
108
+ name: 'tooltipLabel',
109
+ publicClassNames: true
77
110
  },
78
111
  computed: {
79
112
  className: function className(_ref) {
80
- var marquee = _ref.marquee,
81
- width = _ref.width,
82
- styler = _ref.styler;
113
+ var tooltipImage = _ref.tooltipImage,
114
+ marquee = _ref.marquee,
115
+ noArrow = _ref.noArrow,
116
+ styler = _ref.styler,
117
+ width = _ref.width;
83
118
  return styler.append({
84
- multi: !marquee && !!width,
85
- marquee: marquee
119
+ multi: !marquee && (!!width || !!tooltipImage),
120
+ marquee: marquee,
121
+ noArrow: !!noArrow,
122
+ image: !!tooltipImage
86
123
  });
87
124
  },
88
125
  style: function style(_ref2) {
89
126
  var children = _ref2.children,
90
127
  width = _ref2.width,
128
+ tooltipImageSize = _ref2.tooltipImageSize,
91
129
  _style = _ref2.style;
130
+ var enforcedWidth = typeof width === 'number' ? (0, _resolution.scaleToRem)(width) : width;
92
131
  return _objectSpread(_objectSpread({}, _style), {}, {
93
132
  direction: (0, _util.isRtlText)(children) ? 'rtl' : 'ltr',
94
- '--lime-tooltip-label-width': typeof width === 'number' ? (0, _resolution.scaleToRem)(width) : width
133
+ '--lime-tooltip-label-width': tooltipImageSize !== null && tooltipImageSize !== void 0 && tooltipImageSize.width ? (0, _resolution.scaleToRem)(tooltipImageSize === null || tooltipImageSize === void 0 ? void 0 : tooltipImageSize.width) : enforcedWidth,
134
+ '--lime-tooltip-image-width': (tooltipImageSize === null || tooltipImageSize === void 0 ? void 0 : tooltipImageSize.width) && (0, _resolution.scaleToRem)(tooltipImageSize === null || tooltipImageSize === void 0 ? void 0 : tooltipImageSize.width),
135
+ '--lime-tooltip-image-height': (tooltipImageSize === null || tooltipImageSize === void 0 ? void 0 : tooltipImageSize.width) && (0, _resolution.scaleToRem)(tooltipImageSize === null || tooltipImageSize === void 0 ? void 0 : tooltipImageSize.height)
95
136
  });
96
137
  }
97
138
  },
98
139
  render: function render(_ref3) {
99
140
  var centered = _ref3.centered,
100
141
  children = _ref3.children,
142
+ css = _ref3.css,
143
+ tooltipImage = _ref3.tooltipImage,
101
144
  marquee = _ref3.marquee,
102
145
  rest = _objectWithoutProperties(_ref3, _excluded);
146
+ delete rest.noArrow;
147
+ delete rest.tooltipImageSize;
103
148
  delete rest.width;
104
149
  if (marquee) {
105
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Marquee["default"], _objectSpread(_objectSpread({}, rest), {}, {
106
- alignment: centered ? 'center' : null,
107
- marqueeOn: "render",
108
- children: children
150
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", _objectSpread(_objectSpread({}, rest), {}, {
151
+ children: [tooltipImage && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Image["default"], {
152
+ className: css.tooltipImage,
153
+ src: tooltipImage
154
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Marquee["default"], {
155
+ alignment: centered ? 'center' : null,
156
+ marqueeOn: "render",
157
+ children: children
158
+ })]
109
159
  }));
110
160
  } else {
111
- return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", _objectSpread(_objectSpread({}, rest), {}, {
112
- children: children
161
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", _objectSpread(_objectSpread({}, rest), {}, {
162
+ children: [tooltipImage && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Image["default"], {
163
+ className: css.tooltipImage,
164
+ src: tooltipImage
165
+ }), children]
113
166
  }));
114
167
  }
115
168
  }
@@ -12,6 +12,11 @@ function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.
12
12
  function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
13
13
  var FloatingLayerController = (0, _FloatingLayer.FloatingLayerDecorator)('div');
14
14
  var TooltipButton = (0, _TooltipDecorator["default"])(_Button["default"]);
15
+ var src = {
16
+ hd: 'https://placehold.co/200x200',
17
+ fhd: 'https://placehold.co/300x300',
18
+ uhd: 'https://placehold.co/600x600'
19
+ };
15
20
  describe('TooltipDecorator', function () {
16
21
  describe('TooltipLabel', function () {
17
22
  test('should apply alignment when `centered` and `marquee`', function () {
@@ -219,6 +224,47 @@ describe('TooltipDecorator', function () {
219
224
  expect(tooltipArrow).toHaveClass(expected);
220
225
  });
221
226
  }));
227
+ test('should have \'noArrow\' className when the prop is given', /*#__PURE__*/_asyncToGenerator(function* () {
228
+ var tooltipText = 'Tooltip';
229
+ (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(FloatingLayerController, {
230
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(TooltipButton, {
231
+ tooltipDelay: 0,
232
+ noArrow: true,
233
+ tooltipText: tooltipText,
234
+ children: "Label"
235
+ })
236
+ }));
237
+ var button = _react.screen.getByRole('button');
238
+ (0, _react.act)(function () {
239
+ return button.focus();
240
+ });
241
+ _react.fireEvent.mouseOver(button);
242
+ yield (0, _react.waitFor)(function () {
243
+ var tooltipNoArrow = _react.screen.getByText('Tooltip').parentElement.parentElement;
244
+ var expected = 'tooltip noArrow';
245
+ expect(tooltipNoArrow).toHaveClass(expected);
246
+ });
247
+ }));
248
+ test('should have properly display Image', /*#__PURE__*/_asyncToGenerator(function* () {
249
+ var tooltipText = 'Tooltip';
250
+ (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(FloatingLayerController, {
251
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(TooltipButton, {
252
+ tooltipDelay: 0,
253
+ tooltipImage: src,
254
+ tooltipText: tooltipText,
255
+ children: "Label"
256
+ })
257
+ }));
258
+ var button = _react.screen.getByRole('button');
259
+ (0, _react.act)(function () {
260
+ return button.focus();
261
+ });
262
+ _react.fireEvent.mouseOver(button);
263
+ yield (0, _react.waitFor)(function () {
264
+ var tooltipImage = _react.screen.getByText('Tooltip').children[0].children[0].tagName;
265
+ expect(tooltipImage).toBe('IMG');
266
+ });
267
+ }));
222
268
  });
223
269
  });
224
270
  });
@@ -45,9 +45,13 @@ var getTooltipDirection = function getTooltipDirection(tooltipPosition, tooltipT
45
45
  };
46
46
  var removeTooltipProps = function removeTooltipProps(_ref) {
47
47
  var props = Object.assign({}, (_objectDestructuringEmpty(_ref), _ref));
48
+ delete props.noArrow;
48
49
  delete props.rtl;
49
50
  delete props.screenEdgeKeepout;
51
+ delete props.tooltipCss;
50
52
  delete props.tooltipDelay;
53
+ delete props.tooltipImage;
54
+ delete props.tooltipImageSize;
51
55
  delete props.tooltipMarquee;
52
56
  delete props.tooltipPosition;
53
57
  delete props.tooltipProps;
@@ -71,7 +75,8 @@ var defaultScreenEdgeKeepout = exports.defaultScreenEdgeKeepout = 24 + 24;
71
75
  // A hook to show Limestone-styled tooltip components.
72
76
  var useTooltip = exports.useTooltip = function useTooltip(props) {
73
77
  var _useI18nContext;
74
- var _props$screenEdgeKeep = props.screenEdgeKeepout,
78
+ var noArrow = props.noArrow,
79
+ _props$screenEdgeKeep = props.screenEdgeKeepout,
75
80
  screenEdgeKeepout = _props$screenEdgeKeep === void 0 ? defaultScreenEdgeKeepout : _props$screenEdgeKeep,
76
81
  _props$tooltipDelay = props.tooltipDelay,
77
82
  tooltipDelay = _props$tooltipDelay === void 0 ? 500 : _props$tooltipDelay,
@@ -79,6 +84,9 @@ var useTooltip = exports.useTooltip = function useTooltip(props) {
79
84
  tooltipType = _props$tooltipType === void 0 ? 'balloon' : _props$tooltipType,
80
85
  _props$tooltipUpdateD = props.tooltipUpdateDelay,
81
86
  tooltipUpdateDelay = _props$tooltipUpdateD === void 0 ? 400 : _props$tooltipUpdateD,
87
+ tooltipCss = props.tooltipCss,
88
+ tooltipImage = props.tooltipImage,
89
+ tooltipImageSize = props.tooltipImageSize,
82
90
  tooltipMarquee = props.tooltipMarquee,
83
91
  tooltipPosition = props.tooltipPosition,
84
92
  tooltipProps = props.tooltipProps,
@@ -246,10 +254,14 @@ var useTooltip = exports.useTooltip = function useTooltip(props) {
246
254
  labelOffset: layout.labelOffset
247
255
  }, tooltipProps), {}, {
248
256
  arrowAnchor: layout.arrowAnchor,
257
+ noArrow: noArrow,
249
258
  direction: layout.tooltipDirection,
250
259
  marquee: tooltipMarquee,
251
260
  relative: tooltipRelative,
252
261
  style: tooltipStyle,
262
+ tooltipCss: tooltipCss,
263
+ tooltipImage: tooltipImage,
264
+ tooltipImageSize: tooltipImageSize,
253
265
  tooltipRef: getTooltipRef,
254
266
  type: tooltipType,
255
267
  width: tooltipWidth,
@@ -268,7 +280,7 @@ var useTooltip = exports.useTooltip = function useTooltip(props) {
268
280
  } else {
269
281
  return null;
270
282
  }
271
- }, [getTooltipRef, hideTooltip, layout, showing, tooltipMarquee, tooltipProps, tooltipRelative, tooltipText, tooltipType, tooltipWidth]);
283
+ }, [getTooltipRef, hideTooltip, layout, noArrow, showing, tooltipCss, tooltipImage, tooltipImageSize, tooltipMarquee, tooltipProps, tooltipRelative, tooltipText, tooltipType, tooltipWidth]);
272
284
  return {
273
285
  tooltip: tooltipText ? renderTooltip() : null,
274
286
  handlers: handlers,
@@ -1,5 +1,5 @@
1
1
  .titleFrame {
2
- width: calc(100% - 2 * 4rem );
2
+ width: calc(100% - 2 * 4rem );
3
3
  position: relative;
4
4
  flex-grow: 1;
5
5
  opacity: 1;
@@ -170,6 +170,18 @@ the `Spotlight` will store the last focus information based on `SpotlightId`
170
170
  And the `VirtualList` will restore the focus when it remounts while the navigation returns to the `Panel` .
171
171
  */
172
172
  spotlightId?: string;
173
+ /**
174
+ * Anchors the focused item to a fixed "focus position" at the start edge while the list scrolls
175
+ beneath it.
176
+ *
177
+ * When set to `'start'` , moving focus with 5-way keys keeps the focus indicator at a fixed slot
178
+ at the start of the list (top for vertical, leading edge for horizontal) and scrolls so the
179
+ newly focused item lands in that slot. At the end of the list, the list scrolls only to its
180
+ last position so the focused item stays visible.
181
+ *
182
+ * This is ignored when `snapToCenter` is set.
183
+ */
184
+ stickTo?: "start";
173
185
  /**
174
186
  * Specifies how to show vertical scrollbar.
175
187
  *
@@ -380,6 +392,18 @@ the `Spotlight` will store the last focus information based on `SpotlightId`
380
392
  And the `VirtualGridList` will restore the focus when it remounts while the navigation returns to the `Panel` .
381
393
  */
382
394
  spotlightId?: string;
395
+ /**
396
+ * Anchors the focused item to a fixed "focus position" at the start edge while the list scrolls
397
+ beneath it.
398
+ *
399
+ * When set to `'start'` , moving focus with 5-way keys keeps the focus indicator at a fixed slot
400
+ at the start of the list (top for vertical, leading edge for horizontal) and scrolls so the
401
+ newly focused item lands in that slot. At the end of the list, the list scrolls only to its
402
+ last position so the focused item stays visible.
403
+ *
404
+ * This is ignored when `snapToCenter` is set.
405
+ */
406
+ stickTo?: "start";
383
407
  /**
384
408
  * Specifies how to show vertical scrollbar.
385
409
  *
@@ -456,6 +456,21 @@ _VirtualList.propTypes = /** @lends limestone/VirtualList.VirtualList.prototype
456
456
  * @public
457
457
  */
458
458
  spotlightId: _propTypes["default"].string,
459
+ /**
460
+ * Anchors the focused item to a fixed "focus position" at the start edge while the list scrolls
461
+ * beneath it.
462
+ *
463
+ * When set to `'start'`, moving focus with 5-way keys keeps the focus indicator at a fixed slot
464
+ * at the start of the list (top for vertical, leading edge for horizontal) and scrolls so the
465
+ * newly focused item lands in that slot. At the end of the list, the list scrolls only to its
466
+ * last position so the focused item stays visible.
467
+ *
468
+ * This is ignored when `snapToCenter` is set.
469
+ *
470
+ * @type {('start')}
471
+ * @public
472
+ */
473
+ stickTo: _propTypes["default"].oneOf(['start']),
459
474
  /**
460
475
  * Specifies how to show vertical scrollbar.
461
476
  *
@@ -908,6 +923,21 @@ _VirtualGridList.propTypes = /** @lends limestone/VirtualList.VirtualGridList.pr
908
923
  * @public
909
924
  */
910
925
  spotlightId: _propTypes["default"].string,
926
+ /**
927
+ * Anchors the focused item to a fixed "focus position" at the start edge while the list scrolls
928
+ * beneath it.
929
+ *
930
+ * When set to `'start'`, moving focus with 5-way keys keeps the focus indicator at a fixed slot
931
+ * at the start of the list (top for vertical, leading edge for horizontal) and scrolls so the
932
+ * newly focused item lands in that slot. At the end of the list, the list scrolls only to its
933
+ * last position so the focused item stays visible.
934
+ *
935
+ * This is ignored when `snapToCenter` is set.
936
+ *
937
+ * @type {('start')}
938
+ * @public
939
+ */
940
+ stickTo: _propTypes["default"].oneOf(['start']),
911
941
  /**
912
942
  * Specifies how to show vertical scrollbar.
913
943
  *
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+
3
+ require("@testing-library/jest-dom");
4
+ var _spotlight = _interopRequireDefault(require("@enact/spotlight"));
5
+ var _react = require("@testing-library/react");
6
+ var _Item = _interopRequireDefault(require("../../Item"));
7
+ var _VirtualList = _interopRequireDefault(require("../VirtualList"));
8
+ var _jsxRuntime = require("react/jsx-runtime");
9
+ var _excluded = ["index"]; // These tests exercise the `stickTo="start"` scroll behavior added to `useThemeVirtualList`. They
10
+ // live in their own file because they depend on a clean Spotlight instance.
11
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
12
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
13
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
14
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
15
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
16
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
17
+ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
18
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
19
+ var focus = function focus(elm) {
20
+ return _react.fireEvent.focus(elm);
21
+ };
22
+ var keyDownUp = function keyDownUp(keyCode) {
23
+ return function (elm) {
24
+ _react.fireEvent.keyDown(elm, {
25
+ keyCode: keyCode
26
+ });
27
+ return _react.fireEvent.keyUp(elm, {
28
+ keyCode: keyCode
29
+ });
30
+ };
31
+ };
32
+ var pressDownKey = keyDownUp(40);
33
+ describe('VirtualList stickTo="start"', function () {
34
+ var clientSize, currentFocusIndex, dataSize, handlerOnFocus, items, itemSize, renderItem;
35
+ beforeEach(function () {
36
+ clientSize = {
37
+ clientWidth: 1280,
38
+ clientHeight: 720
39
+ };
40
+ currentFocusIndex = -1;
41
+ dataSize = 200;
42
+ items = [];
43
+ itemSize = 60;
44
+ handlerOnFocus = function handlerOnFocus(index) {
45
+ return function () {
46
+ currentFocusIndex = index;
47
+ };
48
+ };
49
+ renderItem = function renderItem(_ref) {
50
+ var index = _ref.index,
51
+ rest = _objectWithoutProperties(_ref, _excluded);
52
+ // eslint-disable-line enact/display-name
53
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Item["default"], _objectSpread(_objectSpread({}, rest), {}, {
54
+ onFocus: handlerOnFocus(index),
55
+ children: items[index].name
56
+ }));
57
+ };
58
+ for (var i = 0; i < dataSize; i++) {
59
+ items.push({
60
+ name: 'Account ' + i
61
+ });
62
+ }
63
+ });
64
+ afterEach(function () {
65
+ clientSize = null;
66
+ dataSize = null;
67
+ handlerOnFocus = null;
68
+ items = null;
69
+ itemSize = null;
70
+ renderItem = null;
71
+ });
72
+ test('should scroll to anchor the focused item at the start slot on 5-way navigation', function () {
73
+ var spy = jest.fn(function () {});
74
+ var scrollToFn = global.Element.prototype.scrollTo;
75
+ global.Element.prototype.scrollTo = spy;
76
+ (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_VirtualList["default"], {
77
+ clientSize: clientSize,
78
+ dataSize: dataSize,
79
+ itemRenderer: renderItem,
80
+ itemSize: itemSize,
81
+ stickTo: "start"
82
+ }));
83
+ var list = _react.screen.getByRole('list');
84
+ var item13 = list.children.item(13).children.item(0);
85
+ focus(item13);
86
+ expect(currentFocusIndex).toBe(13);
87
+ pressDownKey(item13);
88
+ expect(currentFocusIndex).toBe(14);
89
+ expect(spy).toHaveBeenCalled();
90
+ global.Element.prototype.scrollTo = scrollToFn;
91
+ });
92
+ test('should scroll a focused item to the start slot', function () {
93
+ var spy = jest.fn(function () {});
94
+ var scrollToFn = global.Element.prototype.scrollTo;
95
+ global.Element.prototype.scrollTo = spy;
96
+ var pointerSpy = jest.spyOn(_spotlight["default"], 'getPointerMode').mockReturnValue(false);
97
+ var currentSpy = jest.spyOn(_spotlight["default"], 'getCurrent');
98
+ (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_VirtualList["default"], {
99
+ clientSize: clientSize,
100
+ dataSize: dataSize,
101
+ direction: "horizontal",
102
+ itemRenderer: renderItem,
103
+ itemSize: itemSize,
104
+ stickTo: "start"
105
+ }));
106
+ var list = _react.screen.getByRole('list');
107
+ var node = list.querySelector('[data-index="13"]');
108
+ currentSpy.mockReturnValue(node);
109
+ _react.fireEvent.focusIn(node);
110
+ expect(spy).toHaveBeenCalled();
111
+ currentSpy.mockRestore();
112
+ pointerSpy.mockRestore();
113
+ global.Element.prototype.scrollTo = scrollToFn;
114
+ });
115
+ });
@@ -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;