@enact/limestone 1.9.3 → 1.10.0

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 (90) hide show
  1. package/.github/workflows/ci-reusable.yml +2 -2
  2. package/Alert/Alert.d.ts +9 -0
  3. package/Alert/Alert.js +35 -4
  4. package/Alert/Alert.module.css +12 -1
  5. package/Alert/tests/Alert-specs.js +91 -0
  6. package/Button/tests/Button-specs.js +26 -0
  7. package/CHANGELOG.md +34 -0
  8. package/Card/Card.d.ts +4 -4
  9. package/Card/Card.js +7 -8
  10. package/Card/tests/Card-specs.js +39 -5
  11. package/CheckboxItem/CheckboxItem.js +6 -4
  12. package/Chips/Chip.js +12 -6
  13. package/Chips/Chips.js +12 -6
  14. package/Chips/tests/Chip-specs.js +25 -5
  15. package/Chips/tests/Chips-specs.js +12 -2
  16. package/ColorPicker/ColorPicker.js +27 -25
  17. package/ContextualPopupDecorator/ContextualPopupDecorator.js +32 -22
  18. package/DayPicker/DaySelectorDecorator.js +12 -7
  19. package/Dropdown/Dropdown.module.css +4 -0
  20. package/Dropdown/DropdownList.js +74 -53
  21. package/FlexiblePopupPanels/useNavButtonFocus.js +7 -10
  22. package/Heading/Heading.d.ts +1 -1
  23. package/Heading/Heading.js +2 -2
  24. package/Icon/Icon.d.ts +1 -0
  25. package/Icon/Icon.js +1 -0
  26. package/Icon/IconList.js +2 -0
  27. package/IconItem/IconItem.module.css +3 -3
  28. package/IconItem/tests/IconItem-specs.js +30 -1
  29. package/Image/Image.js +6 -4
  30. package/Input/Input.js +12 -1
  31. package/Input/InputField.js +75 -24
  32. package/Input/InputField.module.css +262 -45
  33. package/Input/InputFieldDecoratorIcon.js +1 -0
  34. package/Input/InputFieldSpotlightDecorator.js +53 -8
  35. package/Input/index.d.ts +105 -93
  36. package/Input/tests/Input-specs.js +26 -0
  37. package/Input/tests/InputField-specs.js +149 -3
  38. package/Input/tests/InputPopup-specs.js +1 -1
  39. package/KeyGuide/KeyGuide.js +29 -27
  40. package/MediaOverlay/tests/MediaOverlay-specs.js +29 -0
  41. package/MediaPlayer/tests/util-specs.js +4 -1
  42. package/PageViews/PageViews.js +134 -69
  43. package/PageViews/PageViews.module.css +3 -0
  44. package/PageViews/PageViewsRouter.js +91 -42
  45. package/PageViews/tests/PageViews-specs.js +87 -0
  46. package/Panels/Header.js +6 -4
  47. package/Popup/Popup.js +5 -4
  48. package/PopupTabLayout/PopupTabLayout.js +11 -9
  49. package/RadioItem/RadioItem.js +7 -5
  50. package/Scroller/EditableWrapper.js +17 -14
  51. package/Scroller/Scroller.js +11 -10
  52. package/Scroller/useThemeScroller.js +3 -3
  53. package/Slider/Slider.d.ts +4 -0
  54. package/Slider/Slider.js +40 -16
  55. package/Slider/Slider.module.css +150 -0
  56. package/Slider/SliderBehaviorDecorator.js +16 -14
  57. package/Slider/tests/Slider-specs.js +51 -0
  58. package/Slider/utils.js +23 -7
  59. package/Spinner/Spinner.js +10 -8
  60. package/TabLayout/RefocusDecorator.js +14 -12
  61. package/TabLayout/tests/TabGroup-specs.js +1 -1
  62. package/ThemeDecorator/AccessibilityDecorator.js +12 -11
  63. package/ThemeDecorator/I18nFontDecorator.js +6 -4
  64. package/ThemeDecorator/ThemeDecorator.d.ts +7 -0
  65. package/ThemeDecorator/ThemeDecorator.js +24 -9
  66. package/TimePicker/TimePickerBase.js +5 -3
  67. package/TooltipDecorator/TooltipDecorator.js +12 -7
  68. package/TooltipDecorator/tests/useTooltip-specs.js +5 -2
  69. package/VideoPlayer/VideoPlayer.js +25 -24
  70. package/VirtualList/VirtualList.js +20 -18
  71. package/VirtualList/useSpotlight.js +1 -1
  72. package/fonts/Limestone_Icons.ttf +0 -0
  73. package/internal/AsyncRenderChildren/AsyncRenderChildren.js +9 -5
  74. package/internal/AsyncRenderChildren/tests/AsyncRenderChildren-specs.js +4 -1
  75. package/internal/DateTime/DateTimeDecorator.js +5 -4
  76. package/internal/Panels/PanelsRouter.js +35 -29
  77. package/internal/Panels/useAutoFocus.js +10 -6
  78. package/internal/Panels/useFocusOnTransition.js +4 -3
  79. package/internal/Picker/Picker.js +7 -5
  80. package/internal/Picker/SpottablePicker.js +15 -13
  81. package/internal/SharedStateDecorator/SharedStateDecorator.js +6 -4
  82. package/package.json +14 -11
  83. package/styles/colors.less +1 -0
  84. package/styles/variables.less +1 -1
  85. package/useScroll/HoverToScroll.js +15 -12
  86. package/useScroll/Scrollbar.js +14 -10
  87. package/useScroll/ScrollbarPlaceholder.js +3 -5
  88. package/useScroll/ScrollbarTrack.js +7 -5
  89. package/useScroll/useEvent.js +7 -2
  90. package/useScroll/useScroll.js +10 -2
@@ -35,7 +35,7 @@ jobs:
35
35
 
36
36
  - name: Clone and setup Enact CLI
37
37
  run: |
38
- git clone --branch=7.2.1 --depth 1 https://github.com/enactjs/cli ../cli
38
+ git clone --branch=develop --depth 1 https://github.com/enactjs/cli ../cli
39
39
  pushd ../cli
40
40
  npm install
41
41
  npm link
@@ -43,7 +43,7 @@ jobs:
43
43
 
44
44
  - name: Clone and setup Enact framework
45
45
  run: |
46
- git clone --branch=release/5.4.x.develop --depth 1 https://github.com/enactjs/enact ../enact
46
+ git clone --branch=develop --depth 1 https://github.com/enactjs/enact ../enact
47
47
  pushd ../enact
48
48
  npm install
49
49
  npm run lerna exec -- --ignore enact-sampler --concurrency 1 -- npm --no-package-lock install
package/Alert/Alert.d.ts CHANGED
@@ -32,6 +32,15 @@ export class AlertImage extends React.Component<
32
32
  > {}
33
33
 
34
34
  export interface AlertBaseProps {
35
+ /**
36
+ * Sets the buttons layout direction.
37
+ *
38
+ * In `auto` mode, button direction follows UX defaults:
39
+ * * `overlay` - horizontal when there are exactly 2 buttons
40
+ * * `fullscreen` - horizontal when there are less than 3 buttons
41
+ * * otherwise vertical
42
+ */
43
+ buttonDirection?: "auto" | "horizontal" | "vertical";
35
44
  /**
36
45
  * Buttons to be included under the component.
37
46
  *
package/Alert/Alert.js CHANGED
@@ -24,7 +24,7 @@ var _Popup = _interopRequireDefault(require("../Popup"));
24
24
  var _AlertImage = _interopRequireDefault(require("./AlertImage"));
25
25
  var _AlertModule = _interopRequireDefault(require("./Alert.module.css"));
26
26
  var _jsxRuntime = require("react/jsx-runtime");
27
- var _excluded = ["buttons", "contentComponent", "children", "css", "id", "image", "overlayPosition", "title", "type"];
27
+ var _excluded = ["buttonDirection", "buttons", "contentComponent", "children", "css", "id", "image", "overlayPosition", "title", "type", "style"];
28
28
  /**
29
29
  * Limestone styled modal Alert components.
30
30
  *
@@ -56,6 +56,19 @@ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t =
56
56
  var AlertBase = exports.AlertBase = (0, _kind["default"])({
57
57
  name: 'Alert',
58
58
  propTypes: /** @lends limestone/Alert.AlertBase.prototype */{
59
+ /**
60
+ * Sets the buttons layout direction.
61
+ *
62
+ * In `auto` mode, button direction follows UX defaults:
63
+ * * `overlay` - horizontal when there are exactly 2 buttons
64
+ * * `fullscreen` - horizontal when there are less than 3 buttons
65
+ * * otherwise vertical
66
+ *
67
+ * @type {('auto'|'horizontal'|'vertical')}
68
+ * @default 'auto'
69
+ * @public
70
+ */
71
+ buttonDirection: _propTypes["default"].oneOf(['auto', 'horizontal', 'vertical']),
59
72
  /**
60
73
  * Buttons to be included under the component.
61
74
  *
@@ -171,6 +184,7 @@ var AlertBase = exports.AlertBase = (0, _kind["default"])({
171
184
  type: _propTypes["default"].oneOf(['fullscreen', 'overlay'])
172
185
  },
173
186
  defaultProps: {
187
+ buttonDirection: 'auto',
174
188
  open: false,
175
189
  overlayPosition: 'center',
176
190
  type: 'fullscreen'
@@ -212,7 +226,8 @@ var AlertBase = exports.AlertBase = (0, _kind["default"])({
212
226
  }
213
227
  },
214
228
  render: function render(_ref4) {
215
- var buttons = _ref4.buttons,
229
+ var buttonDirection = _ref4.buttonDirection,
230
+ buttons = _ref4.buttons,
216
231
  contentComponent = _ref4.contentComponent,
217
232
  children = _ref4.children,
218
233
  css = _ref4.css,
@@ -221,10 +236,25 @@ var AlertBase = exports.AlertBase = (0, _kind["default"])({
221
236
  overlayPosition = _ref4.overlayPosition,
222
237
  title = _ref4.title,
223
238
  type = _ref4.type,
239
+ style = _ref4.style,
224
240
  rest = _objectWithoutProperties(_ref4, _excluded);
225
241
  var fullscreen = type === 'fullscreen';
226
242
  var position = type === 'overlay' ? overlayPosition : type;
227
243
  var showTitle = fullscreen && title;
244
+ var buttonCount = _react.Children.toArray(buttons).filter(Boolean).length;
245
+ var resolvedButtonDirection = buttonDirection;
246
+ if (buttonDirection === 'auto') {
247
+ var useHorizontal = type === 'overlay' && buttonCount === 2 || type === 'fullscreen' && buttonCount < 3;
248
+ resolvedButtonDirection = useHorizontal ? 'horizontal' : 'vertical';
249
+ }
250
+ var overlayHorizontalButtons = type === 'overlay' && resolvedButtonDirection === 'horizontal';
251
+ var popupStyle = style;
252
+ if (overlayHorizontalButtons) {
253
+ var overlayHorizontalButtonCount = Math.max(1, Math.min(buttonCount, 4));
254
+ popupStyle = _objectSpread(_objectSpread({}, style), {}, {
255
+ '--alert-overlay-horizontal-button-count': overlayHorizontalButtonCount
256
+ });
257
+ }
228
258
  var ariaLabelledBy = (showTitle ? "".concat(id, "_title ") : '') + "".concat(id, "_content ").concat(id, "_buttons");
229
259
  return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
230
260
  "aria-owns": id,
@@ -235,6 +265,7 @@ var AlertBase = exports.AlertBase = (0, _kind["default"])({
235
265
  "aria-labelledby": ariaLabelledBy,
236
266
  css: css,
237
267
  position: position,
268
+ style: popupStyle,
238
269
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Layout["default"], {
239
270
  align: "center center",
240
271
  orientation: "vertical",
@@ -262,8 +293,8 @@ var AlertBase = exports.AlertBase = (0, _kind["default"])({
262
293
  shrink: true,
263
294
  className: css.buttonContainer,
264
295
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Layout["default"], {
265
- align: "center",
266
- orientation: "vertical",
296
+ align: "center center",
297
+ orientation: resolvedButtonDirection,
267
298
  id: "".concat(id, "_buttons"),
268
299
  children: buttons
269
300
  })
@@ -40,6 +40,7 @@
40
40
  .alert.overlay .buttonContainer {
41
41
  box-sizing: border-box;
42
42
  margin-top: var(--primitive-spacing-36);
43
+ padding: 0 var(--primitive-spacing-84);
43
44
  }
44
45
  .alert.overlay .content {
45
46
  align-self: stretch;
@@ -52,6 +53,7 @@
52
53
  word-break: keep-all;
53
54
  padding: 0 var(--primitive-spacing-84);
54
55
  margin: 0;
56
+ max-width: var(--alert-overlay-content-max-width, 23.5rem);
55
57
  }
56
58
  :global(.enact-locale-non-latin) .alert.overlay .content {
57
59
  font-family: "Limestone";
@@ -77,7 +79,16 @@
77
79
  word-break: normal;
78
80
  }
79
81
  .popup.overlay {
80
- width: 23.5rem;
82
+ box-sizing: border-box;
83
+ --alert-overlay-horizontal-button-count: 1;
84
+ --alert-overlay-horizontal-button-width: NaNrem + (2 * var(--primitive-spacing-36)));
85
+ --alert-overlay-horizontal-buttons-total-width: calc(var(--alert-overlay-horizontal-button-width) * var(--alert-overlay-horizontal-button-count));
86
+ --alert-overlay-width: max(1128px, var(--alert-overlay-horizontal-buttons-total-width));
87
+ --alert-overlay-content-horizontal-padding: var(--primitive-spacing-84);
88
+ --alert-overlay-content-max-width: calc(var(--alert-overlay-width) - (2 * var(--alert-overlay-content-horizontal-padding)));
89
+ width: var(--alert-overlay-width);
90
+ min-width: 23.5rem;
91
+ max-width: calc(100vw - 2 * var(--primitive-spacing-60));
81
92
  margin-left: auto;
82
93
  margin-right: auto;
83
94
  }
@@ -102,6 +102,60 @@ describe('Alert', function () {
102
102
  var expectedClass = 'thumbnail';
103
103
  expect(image).toHaveClass(expectedClass);
104
104
  });
105
+ test('should align buttons horizontally by default in fullscreen when button count is less than 3', function () {
106
+ (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(FloatingLayerController, {
107
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Alert.Alert, {
108
+ open: true,
109
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("buttons", {
110
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Button["default"], {
111
+ children: "yes"
112
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button["default"], {
113
+ children: "no"
114
+ })]
115
+ })
116
+ })
117
+ }));
118
+ var alert = _react.screen.getByRole('alert');
119
+ var buttonsLayout = alert.querySelector('[id$="_buttons"]');
120
+ expect(buttonsLayout).toHaveClass('horizontal');
121
+ });
122
+ test('should align buttons vertically by default in fullscreen when button count is 3', function () {
123
+ (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(FloatingLayerController, {
124
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Alert.Alert, {
125
+ open: true,
126
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("buttons", {
127
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Button["default"], {
128
+ children: "yes"
129
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button["default"], {
130
+ children: "no"
131
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button["default"], {
132
+ children: "later"
133
+ })]
134
+ })
135
+ })
136
+ }));
137
+ var alert = _react.screen.getByRole('alert');
138
+ var buttonsLayout = alert.querySelector('[id$="_buttons"]');
139
+ expect(buttonsLayout).toHaveClass('vertical');
140
+ });
141
+ test('should allow overriding button direction to vertical', function () {
142
+ (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(FloatingLayerController, {
143
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Alert.Alert, {
144
+ open: true,
145
+ buttonDirection: "vertical",
146
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("buttons", {
147
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Button["default"], {
148
+ children: "yes"
149
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button["default"], {
150
+ children: "no"
151
+ })]
152
+ })
153
+ })
154
+ }));
155
+ var alert = _react.screen.getByRole('alert');
156
+ var buttonsLayout = alert.querySelector('[id$="_buttons"]');
157
+ expect(buttonsLayout).toHaveClass('vertical');
158
+ });
105
159
  });
106
160
  describe('AlertOverlay specs', function () {
107
161
  test('should be rendered opened if open is set to true', function () {
@@ -201,4 +255,41 @@ describe('AlertOverlay specs', function () {
201
255
  var expectedClass = 'thumbnail';
202
256
  expect(image).toHaveClass(expectedClass);
203
257
  });
258
+ test('should align buttons horizontally by default in overlay when button count is 2', function () {
259
+ (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(FloatingLayerController, {
260
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Alert.Alert, {
261
+ open: true,
262
+ type: "overlay",
263
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("buttons", {
264
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Button["default"], {
265
+ size: "small",
266
+ children: "yes"
267
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button["default"], {
268
+ size: "small",
269
+ children: "no"
270
+ })]
271
+ })
272
+ })
273
+ }));
274
+ var alert = _react.screen.getByRole('alert');
275
+ var buttonsLayout = alert.querySelector('[id$="_buttons"]');
276
+ expect(buttonsLayout).toHaveClass('horizontal');
277
+ });
278
+ test('should align buttons vertically by default in overlay when button count is not 2', function () {
279
+ (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(FloatingLayerController, {
280
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Alert.Alert, {
281
+ open: true,
282
+ type: "overlay",
283
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("buttons", {
284
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button["default"], {
285
+ size: "small",
286
+ children: "yes"
287
+ })
288
+ })
289
+ })
290
+ }));
291
+ var alert = _react.screen.getByRole('alert');
292
+ var buttonsLayout = alert.querySelector('[id$="_buttons"]');
293
+ expect(buttonsLayout).toHaveClass('vertical');
294
+ });
204
295
  });
@@ -30,6 +30,32 @@ describe('Button', function () {
30
30
  var expected = 'focusExpand';
31
31
  expect(button).toHaveClass(expected);
32
32
  });
33
+ test('should be pressed when selected', function () {
34
+ (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_Button["default"], {}));
35
+ var button = _react.screen.getByRole('button');
36
+
37
+ // Select by key
38
+ _react.fireEvent.keyDown(button, {
39
+ key: 'Enter',
40
+ code: 'Enter',
41
+ keyCode: 13,
42
+ which: 13
43
+ });
44
+ expect(button).toHaveClass('pressed');
45
+ _react.fireEvent.keyUp(button, {
46
+ key: 'Enter',
47
+ code: 'Enter',
48
+ keyCode: 13,
49
+ which: 13
50
+ });
51
+ expect(button).not.toHaveClass('pressed');
52
+
53
+ // Select by pointer
54
+ _react.fireEvent.mouseDown(button);
55
+ expect(button).toHaveClass('pressed');
56
+ _react.fireEvent.mouseUp(button);
57
+ expect(button).not.toHaveClass('pressed');
58
+ });
33
59
  test('should be able to disable the expand focus effect', function () {
34
60
  (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.ButtonBase, {
35
61
  focusEffect: "static"
package/CHANGELOG.md CHANGED
@@ -2,6 +2,40 @@
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.10.0] - 2026-05-08
6
+
7
+ ### Added
8
+
9
+ - `limestone/Alert` `buttonDirection` prop to control button layout direction (`auto`, `horizontal`, `vertical`)
10
+ - `limestone/Icon` supported icon list, adding new icon `f1`
11
+ - `limestone/Input` props `marqueeInputField` to marquee inputField text on focus
12
+ - `limestone/Inputfield` prop `caretToEndOnFocus` to move caret to the end of the input field on input activation via 5-way
13
+ - `limestone/Inputfield` prop `marqueeContent` to marquee text on focus
14
+ - `limestone/PageViews` `showFooterButtons` prop to show optional Close/Next buttons
15
+ - `limestone/PageViews` `footerCloseLabel` prop to custom the Close button label
16
+ - `limestone/PageViews` `onFooterCloseClick` prop to custom the Close button behavior when it is clicked
17
+ - `limestone/Slider` `colorPicker` prop to change slider functionality
18
+ - `limestone/ThemeDecorator` config `focusEffectClass` to support customization for spottable components
19
+
20
+ ### Changed
21
+
22
+ - `limestone/Slider` styling to match the latest GUI
23
+ - `@storybook/addon-docs` version to `^10.3.4`.
24
+ - `@storybook/react-webpack5` version to `^10.3.4`.
25
+ - `storybook` version to `^10.3.4`.
26
+
27
+ ### Fixed
28
+
29
+ - `limestone/Card` `captionOverlayOnFocus` prop to work in `focusRing` mode
30
+ - `limestone/Card` press motion to work with key press
31
+ - `limestone/Dropdown` button to match `DropdownList` items size when `size` is `small`
32
+ - `limestone/IconItem` press motion to work with key press
33
+ - `limestone/MediaOverlay` press motion to work with key press
34
+ - `limestone/Popup` to not flicker on transition
35
+ - `limestone/Popup` to not delay when closed with pointer
36
+ - `limestone/Slider` press motion to work with key press
37
+ - `limestone/useScroll` to not scroll on hover right after scroll by wheel
38
+
5
39
  ## [1.9.3] - 2026-04-20
6
40
 
7
41
  ### Fixed
package/Card/Card.d.ts CHANGED
@@ -10,10 +10,6 @@ type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
10
10
  type Merge<M, N> = Omit<M, Extract<keyof M, keyof N>> & N;
11
11
 
12
12
  export interface CardBaseProps extends ui_Card_CardProps {
13
- /**
14
- * The primary caption displayed with the image.
15
- */
16
- children: string;
17
13
  /**
18
14
  * Source for the image.
19
15
  String value or Object of values used to determine which image will appear on
@@ -38,6 +34,10 @@ It only applies when `orientation` is `'vertical'` .
38
34
  * Centers the captions when `imageIconSrc` is not provided.
39
35
  */
40
36
  centered?: boolean;
37
+ /**
38
+ * The primary caption displayed with the image.
39
+ */
40
+ children?: string;
41
41
  /**
42
42
  * Customizes the component by mapping the supplied collection of CSS class names to the
43
43
  corresponding internal elements and states of this component.
package/Card/Card.js CHANGED
@@ -72,14 +72,6 @@ var getDefaultImageSize = function getDefaultImageSize(orientation) {
72
72
  var CardBase = exports.CardBase = (0, _kind["default"])({
73
73
  name: 'Card',
74
74
  propTypes: /** @lends limestone/Card.CardBase.prototype */{
75
- /**
76
- * The primary caption displayed with the image.
77
- *
78
- * @type {String}
79
- * @required
80
- * @public
81
- */
82
- children: _propTypes["default"].string.isRequired,
83
75
  /**
84
76
  * Source for the image.
85
77
  * String value or Object of values used to determine which image will appear on
@@ -120,6 +112,13 @@ var CardBase = exports.CardBase = (0, _kind["default"])({
120
112
  * @public
121
113
  */
122
114
  centered: _propTypes["default"].bool,
115
+ /**
116
+ * The primary caption displayed with the image.
117
+ *
118
+ * @type {String}
119
+ * @public
120
+ */
121
+ children: _propTypes["default"].string,
123
122
  /**
124
123
  * Customizes the component by mapping the supplied collection of CSS class names to the
125
124
  * corresponding internal elements and states of this component.
@@ -2,8 +2,9 @@
2
2
 
3
3
  require("@testing-library/jest-dom");
4
4
  var _react = require("@testing-library/react");
5
- var _Card = require("../Card");
5
+ var _Card = _interopRequireWildcard(require("../Card"));
6
6
  var _jsxRuntime = require("react/jsx-runtime");
7
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
7
8
  var src = {
8
9
  'hd': 'https://placehold.co/200x200/000000/ffffff/png',
9
10
  'fhd': 'https://placehold.co/300x300/000000/ffffff/png',
@@ -46,7 +47,8 @@ describe('Card', function () {
46
47
  var imageIconSrc = 'imageIconSrc';
47
48
  (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_Card.CardBase, {
48
49
  imageIconSrc: imageIconSrc,
49
- orientation: "vertical"
50
+ orientation: "vertical",
51
+ src: src
50
52
  }));
51
53
  var expected = imageIconSrc;
52
54
  var actual = _react.screen.getAllByRole('img')[2].children.item(0);
@@ -56,7 +58,8 @@ describe('Card', function () {
56
58
  var imageIconSrc = 'imageIconSrc';
57
59
  (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_Card.CardBase, {
58
60
  imageIconSrc: imageIconSrc,
59
- orientation: "horizontal"
61
+ orientation: "horizontal",
62
+ src: src
60
63
  }));
61
64
  var expected = 2;
62
65
  var actual = _react.screen.getAllByRole('img').length;
@@ -67,7 +70,8 @@ describe('Card', function () {
67
70
  (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_Card.CardBase, {
68
71
  "data-testid": "card",
69
72
  fitImage: true,
70
- imageIconSrc: imageIconSrc
73
+ imageIconSrc: imageIconSrc,
74
+ src: src
71
75
  }));
72
76
  var expected = 'fitImage';
73
77
  var actual = _react.screen.getByTestId('card');
@@ -75,7 +79,8 @@ describe('Card', function () {
75
79
  });
76
80
  test('should have "Select" voice intent', function () {
77
81
  (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_Card.CardBase, {
78
- "data-testid": "card"
82
+ "data-testid": "card",
83
+ src: src
79
84
  }));
80
85
  var card = _react.screen.getByTestId('card');
81
86
  expect(card).toHaveAttribute('data-webos-voice-intent', 'Select');
@@ -92,4 +97,33 @@ describe('Card', function () {
92
97
  var actual = _react.screen.getByText('children');
93
98
  expect(actual).not.toHaveAttribute(expected);
94
99
  });
100
+ test('should be pressed when selected', function () {
101
+ (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_Card["default"], {
102
+ "data-testid": "card",
103
+ src: src
104
+ }));
105
+ var card = _react.screen.getByTestId('card');
106
+
107
+ // Select by key
108
+ _react.fireEvent.keyDown(card, {
109
+ key: 'Enter',
110
+ code: 'Enter',
111
+ keyCode: 13,
112
+ which: 13
113
+ });
114
+ expect(card).toHaveClass('pressed');
115
+ _react.fireEvent.keyUp(card, {
116
+ key: 'Enter',
117
+ code: 'Enter',
118
+ keyCode: 13,
119
+ which: 13
120
+ });
121
+ expect(card).not.toHaveClass('pressed');
122
+
123
+ // Select by pointer
124
+ _react.fireEvent.mouseDown(card);
125
+ expect(card).toHaveClass('pressed');
126
+ _react.fireEvent.mouseUp(card);
127
+ expect(card).not.toHaveClass('pressed');
128
+ });
95
129
  });
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports["default"] = exports.CheckboxItemGroup = exports.CheckboxItemDecorator = exports.CheckboxItemBase = exports.CheckboxItem = void 0;
7
7
  var _kind = _interopRequireDefault(require("@enact/core/kind"));
8
+ var _util = require("@enact/core/util");
8
9
  var _Group = _interopRequireDefault(require("@enact/ui/Group"));
9
10
  var _Pure = _interopRequireDefault(require("@enact/ui/internal/Pure"));
10
11
  var _Slottable = _interopRequireDefault(require("@enact/ui/Slottable"));
@@ -225,14 +226,11 @@ var CheckboxItem = exports.CheckboxItem = (0, _Pure["default"])(CheckboxItemDeco
225
226
  * @public
226
227
  */
227
228
  var _CheckboxItemGroup = exports.CheckboxItemGroup = function CheckboxItemGroup(props) {
229
+ (0, _util.checkPropTypes)(_CheckboxItemGroup, props);
228
230
  var children = props.children,
229
231
  groupId = props.groupId,
230
232
  itemProps = props.itemProps,
231
233
  rest = _objectWithoutProperties(props, _excluded2);
232
- _CheckboxItemGroup.propTypes = {
233
- groupId: _propTypes["default"].string,
234
- itemProps: _propTypes["default"].object
235
- };
236
234
  if (typeof children[0] === 'string') {
237
235
  // The case of multiple checkbox items are represented by string array instead of `CheckboxItem` components using `ui/Group`
238
236
  return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
@@ -272,4 +270,8 @@ var _CheckboxItemGroup = exports.CheckboxItemGroup = function CheckboxItemGroup(
272
270
  });
273
271
  }
274
272
  };
273
+ _CheckboxItemGroup.propTypes = {
274
+ groupId: _propTypes["default"].string,
275
+ itemProps: _propTypes["default"].object
276
+ };
275
277
  var _default = exports["default"] = CheckboxItem;
package/Chips/Chip.js CHANGED
@@ -61,6 +61,7 @@ var ChipDefaultProps = {
61
61
  * position: 'right'
62
62
  * }}
63
63
  * icon="check"
64
+ * id="chip"
64
65
  * >
65
66
  * Label
66
67
  * </Chip>
@@ -71,12 +72,13 @@ var ChipDefaultProps = {
71
72
  * @ui
72
73
  * @public
73
74
  */
74
- var ChipBase = exports.ChipBase = function ChipBase(props) {
75
+ var _ChipBase = exports.ChipBase = function ChipBase(props) {
75
76
  var _use = (0, _react.use)(_Chips.ChipsContext),
76
77
  handleChipDelete = _use.handleChipDelete,
77
78
  getNextTargetFromDeleteButton = _use.getNextTargetFromDeleteButton,
78
79
  registerChild = _use.registerChild;
79
80
  var chipProps = (0, _util.setDefaultProps)(props, ChipDefaultProps);
81
+ (0, _util.checkPropTypes)(_ChipBase, chipProps);
80
82
  var checked = chipProps.checked,
81
83
  children = chipProps.children,
82
84
  className = chipProps.className,
@@ -92,11 +94,15 @@ var ChipBase = exports.ChipBase = function ChipBase(props) {
92
94
  var ariaLabel = children + ' ' + (0, _$L["default"])('Chip') + ' ' + (0, _$L["default"])('button');
93
95
  var buttonClassName = (0, _classnames["default"])(_ChipModule["default"].deleteButtonContainer, _ChipModule["default"][(deleteButton === null || deleteButton === void 0 ? void 0 : deleteButton.position) || 'right']);
94
96
  var chipClassName = (0, _classnames["default"])(className, deleteButton === null || deleteButton === void 0 ? void 0 : deleteButton.position);
97
+ var chipRef = (0, _react.useRef)(null);
95
98
  var containerRef = (0, _react.useRef)(null);
96
- var clientRef = (0, _react.useRef)(null);
97
99
  var deleteButtonRef = (0, _react.useRef)(null);
98
- var chipRef = clientRef || ref;
99
100
  var isHovering = (0, _react.useRef)(false);
101
+ (0, _react.useEffect)(function () {
102
+ if (!chipRef.current) {
103
+ chipRef.current = ref.current;
104
+ }
105
+ }, [ref]);
100
106
  (0, _react.useEffect)(function () {
101
107
  if (chipRef.current && registerChild) {
102
108
  registerChild(chipRef, id);
@@ -228,8 +234,7 @@ var ChipBase = exports.ChipBase = function ChipBase(props) {
228
234
  })]
229
235
  }));
230
236
  };
231
- ChipBase.displayName = 'Chip';
232
- ChipBase.propTypes = /** @lends limestone/Chips.Chip.prototype */{
237
+ _ChipBase.propTypes = /** @lends limestone/Chips.Chip.prototype */{
233
238
  /**
234
239
  * A label displayed in the chip content.
235
240
  *
@@ -291,6 +296,7 @@ ChipBase.propTypes = /** @lends limestone/Chips.Chip.prototype */{
291
296
  */
292
297
  isImage: _propTypes["default"].bool
293
298
  };
299
+ _ChipBase.displayName = 'Chip';
294
300
 
295
301
  /**
296
302
  * Limestone-specific Chip behaviors to apply to {@link limestone/Chips.Chip|Chip}.
@@ -301,5 +307,5 @@ ChipBase.propTypes = /** @lends limestone/Chips.Chip.prototype */{
301
307
  * @public
302
308
  */
303
309
  var ChipDecorator = exports.ChipDecorator = (0, _compose["default"])(_Skinnable["default"]);
304
- var Chip = exports.Chip = ChipDecorator(ChipBase);
310
+ var Chip = exports.Chip = ChipDecorator(_ChipBase);
305
311
  var _default = exports["default"] = Chip;
package/Chips/Chips.js CHANGED
@@ -33,6 +33,9 @@ var ChipsContext = exports.ChipsContext = /*#__PURE__*/(0, _react.createContext)
33
33
  var ChipsDefaultProps = {
34
34
  orientation: 'vertical'
35
35
  };
36
+ var generateAriaId = function generateAriaId() {
37
+ return Math.random().toString(36).substring(2, 10);
38
+ };
36
39
 
37
40
  /**
38
41
  * A container that surrounds the chips.
@@ -42,7 +45,7 @@ var ChipsDefaultProps = {
42
45
  * <Chips>
43
46
  * {chips.map(({id, icon, children}) => {
44
47
  * return (
45
- * <Chip key={id} icon={icon} onClick={onClick}>
48
+ * <Chip key={id} id={id} icon={icon} onClick={onClick}>
46
49
  * {children}
47
50
  * </Chip>
48
51
  * );
@@ -55,8 +58,9 @@ var ChipsDefaultProps = {
55
58
  * @ui
56
59
  * @public
57
60
  */
58
- var ChipsBase = exports.ChipsBase = function ChipsBase(props) {
61
+ var _ChipsBase = exports.ChipsBase = function ChipsBase(props) {
59
62
  var chipsProps = (0, _util.setDefaultProps)(props, ChipsDefaultProps);
63
+ (0, _util.checkPropTypes)(_ChipsBase, chipsProps);
60
64
  var children = chipsProps.children,
61
65
  className = chipsProps.className,
62
66
  orientation = chipsProps.orientation,
@@ -67,7 +71,9 @@ var ChipsBase = exports.ChipsBase = function ChipsBase(props) {
67
71
  var ariaLabel = new _IString["default"]((0, _$L["default"])('{total} items in total')).format({
68
72
  total: children === null || children === void 0 ? void 0 : children.length
69
73
  });
70
- var ariaId = Math.random().toString(36).substring(2, 10);
74
+ var ariaId = (0, _react.useMemo)(function () {
75
+ return generateAriaId();
76
+ }, []);
71
77
  var getPreviousChip = (0, _react.useCallback)(function (id) {
72
78
  var currentIndex = childRefs.current.findIndex(function (child) {
73
79
  return child.id === id;
@@ -176,8 +182,7 @@ var ChipsBase = exports.ChipsBase = function ChipsBase(props) {
176
182
  }))
177
183
  });
178
184
  };
179
- ChipsBase.displayName = 'Chips';
180
- ChipsBase.propTypes = /** @lends limestone/Chips.Chips.prototype */{
185
+ _ChipsBase.propTypes = /** @lends limestone/Chips.Chips.prototype */{
181
186
  /**
182
187
  * {@link limestone/Chips.Chip|Chip} to be rendered
183
188
  *
@@ -194,6 +199,7 @@ ChipsBase.propTypes = /** @lends limestone/Chips.Chips.prototype */{
194
199
  */
195
200
  orientation: _propTypes["default"].oneOf(['horizontal', 'vertical'])
196
201
  };
202
+ _ChipsBase.displayName = 'Chips';
197
203
 
198
204
  /**
199
205
  * Applies Limestone specific behaviors to {@link limestone/Chips.Chips|Chips} components.
@@ -225,5 +231,5 @@ var ChipsDecorator = exports.ChipsDecorator = (0, _compose["default"])((0, _Spot
225
231
  * @ui
226
232
  * @public
227
233
  */
228
- var Chips = exports.Chips = ChipsDecorator(ChipsBase);
234
+ var Chips = exports.Chips = ChipsDecorator(_ChipsBase);
229
235
  var _default = exports["default"] = Chips;