@pingux/astro 1.9.0 → 1.10.0-alpha.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.
@@ -14,7 +14,7 @@ _Object$defineProperty(exports, "__esModule", {
14
14
  value: true
15
15
  });
16
16
 
17
- exports["default"] = exports.Default = exports.Controlled = void 0;
17
+ exports["default"] = exports.Default = exports.Controlled = exports.AccordionWithInputs = void 0;
18
18
 
19
19
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/slicedToArray"));
20
20
 
@@ -295,6 +295,59 @@ var Controlled = function Controlled() {
295
295
  }) : null);
296
296
  }))
297
297
  );
298
+ }; // const items = [
299
+ // { id: 1, name: "Aardvark", key: "Aardvark" },
300
+ // { id: 2, name: "Kangaroo", key: "Kangaroo" },
301
+ // { id: 3, name: "Snake", key: "Snake" },
302
+ // { id: 4, name: "Frog", key: "Frog" },
303
+ // { id: 5, name: "Seal", key: "Seal" },
304
+ // { id: 6, name: "Orangutan", key: "Orangutan" },
305
+ // { id: 7, name: "Shark", key: "Shark" }
306
+ // ];
307
+ // const data = [
308
+ // {
309
+ // name: "Client Application Developer",
310
+ // key: "Client"
311
+ // },
312
+ // {
313
+ // name: "Environment Admin",
314
+ // key: "Environment"
315
+ // },
316
+ // {
317
+ // name: "Organization Admin",
318
+ // key: "Organization"
319
+ // }
320
+ // ];
321
+
322
+
323
+ exports.Controlled = Controlled;
324
+
325
+ var AccordionWithInputs = function AccordionWithInputs() {
326
+ return (0, _react2.jsx)(_AccordionGridGroup["default"], {
327
+ items: data
328
+ }, function (item) {
329
+ return (0, _react2.jsx)(_collections.Item, {
330
+ key: item.key,
331
+ textValue: item.name
332
+ }, (0, _react2.jsx)(_index.Text, {
333
+ sx: {
334
+ fontWeight: 3,
335
+ textOverflow: 'ellipsis',
336
+ whiteSpace: 'nowrap',
337
+ overflow: 'hidden'
338
+ },
339
+ variant: "itemTitle",
340
+ alignSelf: "center"
341
+ }, item.name), (0, _react2.jsx)(_index.Box, {
342
+ gap: "md"
343
+ }, (0, _react2.jsx)(_index.TextField, {
344
+ label: "label 1"
345
+ }), (0, _react2.jsx)(_index.TextField, {
346
+ label: "label 2"
347
+ }), (0, _react2.jsx)(_index.TextField, {
348
+ label: "label 3"
349
+ })));
350
+ });
298
351
  };
299
352
 
300
- exports.Controlled = Controlled;
353
+ exports.AccordionWithInputs = AccordionWithInputs;
@@ -59,6 +59,18 @@ var getComponentInOverlayPanel = function getComponentInOverlayPanel() {
59
59
  }, (0, _react2.jsx)(_index.Box, null, (0, _react2.jsx)(_index.Link, null, "Header Button"), (0, _react2.jsx)(_index.Link, null, "Second Header Button")), (0, _react2.jsx)(_index.Box, null, (0, _react2.jsx)(_index.Link, null, "Body Button"), (0, _react2.jsx)(_index.Link, null, "Second Body Button"))))));
60
60
  };
61
61
 
62
+ var getComponentWithTextFields = function getComponentWithTextFields() {
63
+ var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
64
+ return (0, _testWrapper.render)((0, _react2.jsx)(_AccordionGridGroup["default"], (0, _extends2["default"])({}, defaultProps, props), (0, _react2.jsx)(_collections.Item, {
65
+ key: "first",
66
+ textValue: "Duplicate"
67
+ }, (0, _react2.jsx)(_index.Text, null, "Header"), (0, _react2.jsx)(_index.Box, null, (0, _react2.jsx)(_index.TextField, {
68
+ label: "label 1"
69
+ }), (0, _react2.jsx)(_index.TextField, {
70
+ label: "label 2"
71
+ })))));
72
+ };
73
+
62
74
  (0, _testAxe["default"])(getComponent, {
63
75
  // landmark-unique rule conflicts with react-aria role definition
64
76
  rules: {
@@ -249,4 +261,24 @@ test('items do not automatically expand if wrapped in an open OverlayPanel', fun
249
261
 
250
262
  var selectedRow = row[0];
251
263
  expect(selectedRow).not.toHaveAttribute('aria-selected', 'true');
264
+ });
265
+ test('adds focus to inputs', function () {
266
+ getComponentWithTextFields();
267
+
268
+ var firstInput = _testWrapper.screen.getAllByRole('gridcell')[0];
269
+
270
+ var secondInput = _testWrapper.screen.getAllByRole('gridcell')[1];
271
+
272
+ expect(firstInput).not.toHaveFocus();
273
+ expect(secondInput).not.toHaveFocus();
274
+
275
+ _userEvent["default"].click(firstInput);
276
+
277
+ expect(firstInput).toHaveFocus();
278
+ expect(secondInput).not.toHaveFocus();
279
+
280
+ _userEvent["default"].click(secondInput);
281
+
282
+ expect(firstInput).not.toHaveFocus();
283
+ expect(secondInput).toHaveFocus();
252
284
  });
@@ -105,6 +105,7 @@ var AccordionGridItem = function AccordionGridItem(props) {
105
105
  }, (0, _utils.mergeProps)(rowProps, others), {
106
106
  "aria-selected": isSelected,
107
107
  className: classNames,
108
+ variant: "accordion.accordionGridItem",
108
109
  ref: rowRef
109
110
  }), (0, _react2.jsx)(_AccordionGridItemHeader["default"], (0, _extends2["default"])({
110
111
  item: item,
@@ -62,10 +62,16 @@ var AccordionGridItemBody = /*#__PURE__*/(0, _react.forwardRef)(function (props,
62
62
 
63
63
  var _useGridCell = (0, _grid.useGridCell)({
64
64
  node: cellNode,
65
- focusMode: 'child',
65
+ focusMode: 'cell',
66
66
  shouldSelectOnPressUp: true
67
67
  }, state, ref),
68
- gridCellProps = _useGridCell.gridCellProps; // Add the cell's key to the disabled keys array,
68
+ gridCellProps = _useGridCell.gridCellProps;
69
+ /* istanbul ignore next */
70
+
71
+
72
+ gridCellProps.onClick = function (e) {
73
+ e.target.focus();
74
+ }; // Add the cell's key to the disabled keys array,
69
75
  // so that clicking this cell does not close the accordion.
70
76
 
71
77
 
@@ -58,9 +58,11 @@ var _Text = _interopRequireDefault(require("../Text"));
58
58
 
59
59
  var _statuses = _interopRequireDefault(require("../../utils/devUtils/constants/statuses"));
60
60
 
61
+ var _isValidPositiveInt = _interopRequireDefault(require("../../utils/devUtils/props/isValidPositiveInt"));
62
+
61
63
  var _react2 = require("@emotion/react");
62
64
 
63
- var _excluded = ["addButtonLabel", "defaultValue", "value", "label", "helperText", "status", "onAdd", "onChange", "onDelete", "renderField"],
65
+ var _excluded = ["addButtonLabel", "defaultValue", "value", "label", "helperText", "status", "onAdd", "onChange", "onDelete", "renderField", "maxSize", "maxSizeText"],
64
66
  _excluded2 = ["id", "onComponentRender", "fieldValue"];
65
67
 
66
68
  function _getRequireWildcardCache(nodeInterop) { if (typeof _WeakMap !== "function") return null; var cacheBabelInterop = new _WeakMap(); var cacheNodeInterop = new _WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
@@ -84,6 +86,8 @@ var ArrayField = function ArrayField(_ref) {
84
86
  onChange = _ref.onChange,
85
87
  onDelete = _ref.onDelete,
86
88
  renderField = _ref.renderField,
89
+ maxSize = _ref.maxSize,
90
+ maxSizeText = _ref.maxSizeText,
87
91
  others = (0, _objectWithoutProperties2["default"])(_ref, _excluded);
88
92
  var isControlled = value !== undefined;
89
93
  var createEmptyField = (0, _react.useCallback)(function () {
@@ -147,6 +151,7 @@ var ArrayField = function ArrayField(_ref) {
147
151
  return (0, _concat["default"])(_context = []).call(_context, oldValues, [createEmptyField()]);
148
152
  });
149
153
  }, [createEmptyField, onAdd]);
154
+ var isLimitReached = !!maxSize && (value || fieldValues).length >= maxSize;
150
155
  return (0, _react2.jsx)(_Box["default"], others, (0, _react2.jsx)(_Text["default"], {
151
156
  variant: "label"
152
157
  }, label), (0, _react2.jsx)(_Box["default"], {
@@ -165,7 +170,9 @@ var ArrayField = function ArrayField(_ref) {
165
170
  }, onComponentRender ? onComponentRender(id, fieldValue, onFieldValueChange, onFieldDelete, isDisabled, otherFieldProps) : renderField(id, fieldValue, onFieldValueChange, onFieldDelete, isDisabled, otherFieldProps));
166
171
  })), helperText && (0, _react2.jsx)(_FieldHelperText["default"], {
167
172
  status: status
168
- }, helperText), (0, _react2.jsx)(_Button["default"], {
173
+ }, helperText), isLimitReached && (0, _react2.jsx)(_FieldHelperText["default"], {
174
+ status: _statuses["default"].DEFAULT
175
+ }, maxSizeText || "Maximum ".concat(maxSize, " items.")), !isLimitReached && (0, _react2.jsx)(_Button["default"], {
169
176
  "aria-label": "Add field",
170
177
  variant: "text",
171
178
  onPress: onFieldAdd,
@@ -213,7 +220,13 @@ ArrayField.propTypes = {
213
220
  renderField: _propTypes["default"].func,
214
221
 
215
222
  /** Determines the helper text styling. */
216
- status: _propTypes["default"].oneOf((0, _values["default"])(_statuses["default"]))
223
+ status: _propTypes["default"].oneOf((0, _values["default"])(_statuses["default"])),
224
+
225
+ /** Determines the maximum number of items */
226
+ maxSize: _isValidPositiveInt["default"],
227
+
228
+ /** Text to display when the maximum number of items is reached */
229
+ maxSizeText: _propTypes["default"].node
217
230
  };
218
231
  ArrayField.defaultProps = {
219
232
  addButtonLabel: '+ Add'
@@ -8,7 +8,7 @@ _Object$defineProperty(exports, "__esModule", {
8
8
  value: true
9
9
  });
10
10
 
11
- exports["default"] = exports.Uncontrolled = exports.Controlled = void 0;
11
+ exports["default"] = exports.WithLimitedItemsNumber = exports.Uncontrolled = exports.Controlled = void 0;
12
12
 
13
13
  var _filter = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/filter"));
14
14
 
@@ -58,6 +58,16 @@ var _default = {
58
58
  control: {
59
59
  type: 'text'
60
60
  }
61
+ },
62
+ maxSize: {
63
+ control: {
64
+ type: 'number'
65
+ }
66
+ },
67
+ maxSizeText: {
68
+ control: {
69
+ type: 'text'
70
+ }
61
71
  }
62
72
  }
63
73
  };
@@ -220,4 +230,35 @@ var Controlled = function Controlled() {
220
230
  });
221
231
  };
222
232
 
223
- exports.Controlled = Controlled;
233
+ exports.Controlled = Controlled;
234
+
235
+ var WithLimitedItemsNumber = function WithLimitedItemsNumber(_ref3) {
236
+ var args = (0, _extends2["default"])({}, _ref3);
237
+ return (0, _react2.jsx)(_index.ArrayField, (0, _extends2["default"])({
238
+ defaultValue: defaultData,
239
+ renderField: function renderField(id, fieldValue, onFieldValueChange, onFieldDelete, isDisabled, otherFieldProps) {
240
+ return (0, _react2.jsx)(_index.TextField, (0, _extends2["default"])({
241
+ "aria-label": "Text field",
242
+ value: fieldValue,
243
+ onChange: function onChange(e) {
244
+ return onFieldValueChange(e, id);
245
+ },
246
+ mr: "xs",
247
+ slots: {
248
+ inContainer: (0, _react2.jsx)(_index.ArrayFieldDeleteButton, {
249
+ isDisabled: isDisabled,
250
+ onDelete: function onDelete() {
251
+ return onFieldDelete(id);
252
+ }
253
+ })
254
+ }
255
+ }, otherFieldProps));
256
+ },
257
+ sx: {
258
+ width: '400px'
259
+ },
260
+ maxSize: 3
261
+ }, args));
262
+ };
263
+
264
+ exports.WithLimitedItemsNumber = WithLimitedItemsNumber;
@@ -218,4 +218,27 @@ test('check if tooltip on delete button renders on hover', function () {
218
218
  _testWrapper.fireEvent.mouseEnter(button);
219
219
 
220
220
  expect(_testWrapper.screen.queryByRole('tooltip')).not.toBeInTheDocument();
221
+ });
222
+ test('removes add button if max number of fields is reached', function () {
223
+ getComponent({
224
+ renderField: renderField,
225
+ maxSize: 3
226
+ });
227
+ expect(_testWrapper.screen.getAllByLabelText('Text field')).toHaveLength(2);
228
+
229
+ _testWrapper.fireEvent.click(_testWrapper.screen.getByText('+ Add'));
230
+
231
+ expect(_testWrapper.screen.getAllByLabelText('Text field')).toHaveLength(3);
232
+ expect(_testWrapper.screen.queryByText('+ Add')).not.toBeInTheDocument();
233
+ expect(_testWrapper.screen.getByText('Maximum 3 items.')).toBeInTheDocument();
234
+ });
235
+ test('displays max size label if provided', function () {
236
+ var maxSizeText = 'Too many fields';
237
+ getComponent({
238
+ renderField: renderField,
239
+ maxSize: 1,
240
+ maxSizeText: maxSizeText
241
+ });
242
+ expect(_testWrapper.screen.queryByText('+ Add')).not.toBeInTheDocument();
243
+ expect(_testWrapper.screen.getByText(maxSizeText)).toBeInTheDocument();
221
244
  });
@@ -96,7 +96,7 @@ OverlayPanel.propTypes = {
96
96
  /** Sets the open state of the menu. */
97
97
  isOpen: _propTypes["default"].bool,
98
98
 
99
- /** Sets the open state of the menu. */
99
+ /** Sets the size of the overlay panel. */
100
100
  size: _propTypes["default"].oneOf((0, _values["default"])(_panelSizes.panelSizes)),
101
101
 
102
102
  /** JSX styling that is passed into the component. */
@@ -67,7 +67,14 @@ var _default = {
67
67
  fontWeights: _text.fontWeights,
68
68
  sizes: {
69
69
  buttonHeight: 36,
70
- column: 400
70
+ column: 400,
71
+ container: {
72
+ xs: '400px',
73
+ sm: '550px',
74
+ md: '800px',
75
+ lg: '1200px',
76
+ full: '100%'
77
+ }
71
78
  },
72
79
  shadows: {
73
80
  standard: "0 1px 3px ".concat(_colors.shadow),
@@ -130,6 +130,14 @@ var accordionGridBody = {
130
130
  width: '100%',
131
131
  '&.is-selected': {
132
132
  display: 'flex !important'
133
+ },
134
+ ':focus': {
135
+ outline: 'none'
136
+ }
137
+ };
138
+ var accordionGridItem = {
139
+ ':focus': {
140
+ outline: 'none'
133
141
  }
134
142
  };
135
143
  var _default = {
@@ -139,6 +147,7 @@ var _default = {
139
147
  accordion: accordion,
140
148
  accordionBody: accordionBody,
141
149
  accordionGridHeaderNav: accordionGridHeaderNav,
142
- accordionGridNavItem: accordionGridNavItem
150
+ accordionGridNavItem: accordionGridNavItem,
151
+ accordionGridItem: accordionGridItem
143
152
  };
144
153
  exports["default"] = _default;
@@ -33,7 +33,7 @@ var overlayPanel = {
33
33
  width: '800px'
34
34
  },
35
35
  '&.is-full': {
36
- width: '100%'
36
+ width: 'container.full'
37
37
  },
38
38
  '&.is-open': {
39
39
  display: 'flex !important',
@@ -4,7 +4,7 @@ import React, { useState } from 'react';
4
4
  import { Item } from '@react-stately/collections';
5
5
  import CreateIcon from 'mdi-react/CreateIcon';
6
6
  import MoreVertIcon from 'mdi-react/MoreVertIcon';
7
- import { Box, IconButton, Text, Separator, Link } from '../../index';
7
+ import { Box, IconButton, Text, Separator, Link, TextField } from '../../index';
8
8
  import AccordionGridGroup from './AccordionGridGroup';
9
9
  import { jsx as ___EmotionJSX } from "@emotion/react";
10
10
  var data = [{
@@ -260,4 +260,54 @@ export var Controlled = function Controlled() {
260
260
  }) : null);
261
261
  }))
262
262
  );
263
+ }; // const items = [
264
+ // { id: 1, name: "Aardvark", key: "Aardvark" },
265
+ // { id: 2, name: "Kangaroo", key: "Kangaroo" },
266
+ // { id: 3, name: "Snake", key: "Snake" },
267
+ // { id: 4, name: "Frog", key: "Frog" },
268
+ // { id: 5, name: "Seal", key: "Seal" },
269
+ // { id: 6, name: "Orangutan", key: "Orangutan" },
270
+ // { id: 7, name: "Shark", key: "Shark" }
271
+ // ];
272
+ // const data = [
273
+ // {
274
+ // name: "Client Application Developer",
275
+ // key: "Client"
276
+ // },
277
+ // {
278
+ // name: "Environment Admin",
279
+ // key: "Environment"
280
+ // },
281
+ // {
282
+ // name: "Organization Admin",
283
+ // key: "Organization"
284
+ // }
285
+ // ];
286
+
287
+ export var AccordionWithInputs = function AccordionWithInputs() {
288
+ return ___EmotionJSX(AccordionGridGroup, {
289
+ items: data
290
+ }, function (item) {
291
+ return ___EmotionJSX(Item, {
292
+ key: item.key,
293
+ textValue: item.name
294
+ }, ___EmotionJSX(Text, {
295
+ sx: {
296
+ fontWeight: 3,
297
+ textOverflow: 'ellipsis',
298
+ whiteSpace: 'nowrap',
299
+ overflow: 'hidden'
300
+ },
301
+ variant: "itemTitle",
302
+ alignSelf: "center"
303
+ }, item.name), ___EmotionJSX(Box, {
304
+ gap: "md"
305
+ }, ___EmotionJSX(TextField, {
306
+ label: "label 1"
307
+ }), ___EmotionJSX(TextField, {
308
+ label: "label 2"
309
+ }), ___EmotionJSX(TextField, {
310
+ label: "label 3"
311
+ })));
312
+ });
263
313
  };
@@ -6,7 +6,7 @@ import { Item } from '@react-stately/collections';
6
6
  import userEvent from '@testing-library/user-event';
7
7
  import axeTest from '../../utils/testUtils/testAxe';
8
8
  import { act, fireEvent, render, screen, waitFor } from '../../utils/testUtils/testWrapper';
9
- import { Link, Box, OverlayPanel } from '../../index';
9
+ import { Link, Box, OverlayPanel, TextField, Text } from '../../index';
10
10
  import AccordionGridGroup from '../AccordionGridGroup';
11
11
  import { jsx as ___EmotionJSX } from "@emotion/react";
12
12
  var testId = 'test-accordion';
@@ -44,6 +44,18 @@ var getComponentInOverlayPanel = function getComponentInOverlayPanel() {
44
44
  }, ___EmotionJSX(Box, null, ___EmotionJSX(Link, null, "Header Button"), ___EmotionJSX(Link, null, "Second Header Button")), ___EmotionJSX(Box, null, ___EmotionJSX(Link, null, "Body Button"), ___EmotionJSX(Link, null, "Second Body Button"))))));
45
45
  };
46
46
 
47
+ var getComponentWithTextFields = function getComponentWithTextFields() {
48
+ var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
49
+ return render(___EmotionJSX(AccordionGridGroup, _extends({}, defaultProps, props), ___EmotionJSX(Item, {
50
+ key: "first",
51
+ textValue: "Duplicate"
52
+ }, ___EmotionJSX(Text, null, "Header"), ___EmotionJSX(Box, null, ___EmotionJSX(TextField, {
53
+ label: "label 1"
54
+ }), ___EmotionJSX(TextField, {
55
+ label: "label 2"
56
+ })))));
57
+ };
58
+
47
59
  axeTest(getComponent, {
48
60
  // landmark-unique rule conflicts with react-aria role definition
49
61
  rules: {
@@ -187,4 +199,17 @@ test('items do not automatically expand if wrapped in an open OverlayPanel', fun
187
199
  var row = screen.getAllByRole('row');
188
200
  var selectedRow = row[0];
189
201
  expect(selectedRow).not.toHaveAttribute('aria-selected', 'true');
202
+ });
203
+ test('adds focus to inputs', function () {
204
+ getComponentWithTextFields();
205
+ var firstInput = screen.getAllByRole('gridcell')[0];
206
+ var secondInput = screen.getAllByRole('gridcell')[1];
207
+ expect(firstInput).not.toHaveFocus();
208
+ expect(secondInput).not.toHaveFocus();
209
+ userEvent.click(firstInput);
210
+ expect(firstInput).toHaveFocus();
211
+ expect(secondInput).not.toHaveFocus();
212
+ userEvent.click(secondInput);
213
+ expect(firstInput).not.toHaveFocus();
214
+ expect(secondInput).toHaveFocus();
190
215
  });
@@ -68,6 +68,7 @@ var AccordionGridItem = function AccordionGridItem(props) {
68
68
  }, mergeProps(rowProps, others), {
69
69
  "aria-selected": isSelected,
70
70
  className: classNames,
71
+ variant: "accordion.accordionGridItem",
71
72
  ref: rowRef
72
73
  }), ___EmotionJSX(AccordionGridItemHeader, _extends({
73
74
  item: item,
@@ -27,10 +27,16 @@ var AccordionGridItemBody = /*#__PURE__*/forwardRef(function (props, ref) {
27
27
 
28
28
  var _useGridCell = useGridCell({
29
29
  node: cellNode,
30
- focusMode: 'child',
30
+ focusMode: 'cell',
31
31
  shouldSelectOnPressUp: true
32
32
  }, state, ref),
33
- gridCellProps = _useGridCell.gridCellProps; // Add the cell's key to the disabled keys array,
33
+ gridCellProps = _useGridCell.gridCellProps;
34
+ /* istanbul ignore next */
35
+
36
+
37
+ gridCellProps.onClick = function (e) {
38
+ e.target.focus();
39
+ }; // Add the cell's key to the disabled keys array,
34
40
  // so that clicking this cell does not close the accordion.
35
41
 
36
42
 
@@ -12,7 +12,7 @@ import _defineProperty from "@babel/runtime-corejs3/helpers/esm/defineProperty";
12
12
  import _mapInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/map";
13
13
  import _slicedToArray from "@babel/runtime-corejs3/helpers/esm/slicedToArray";
14
14
  import _objectWithoutProperties from "@babel/runtime-corejs3/helpers/esm/objectWithoutProperties";
15
- var _excluded = ["addButtonLabel", "defaultValue", "value", "label", "helperText", "status", "onAdd", "onChange", "onDelete", "renderField"],
15
+ var _excluded = ["addButtonLabel", "defaultValue", "value", "label", "helperText", "status", "onAdd", "onChange", "onDelete", "renderField", "maxSize", "maxSizeText"],
16
16
  _excluded2 = ["id", "onComponentRender", "fieldValue"];
17
17
 
18
18
  function ownKeys(object, enumerableOnly) { var keys = _Object$keys(object); if (_Object$getOwnPropertySymbols) { var symbols = _Object$getOwnPropertySymbols(object); enumerableOnly && (symbols = _filterInstanceProperty(symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
@@ -27,6 +27,7 @@ import Button from '../Button';
27
27
  import FieldHelperText from '../FieldHelperText';
28
28
  import Text from '../Text';
29
29
  import statuses from '../../utils/devUtils/constants/statuses';
30
+ import isValidPositiveInt from '../../utils/devUtils/props/isValidPositiveInt';
30
31
  import { jsx as ___EmotionJSX } from "@emotion/react";
31
32
 
32
33
  var ArrayField = function ArrayField(_ref) {
@@ -42,6 +43,8 @@ var ArrayField = function ArrayField(_ref) {
42
43
  onChange = _ref.onChange,
43
44
  onDelete = _ref.onDelete,
44
45
  renderField = _ref.renderField,
46
+ maxSize = _ref.maxSize,
47
+ maxSizeText = _ref.maxSizeText,
45
48
  others = _objectWithoutProperties(_ref, _excluded);
46
49
 
47
50
  var isControlled = value !== undefined;
@@ -106,6 +109,7 @@ var ArrayField = function ArrayField(_ref) {
106
109
  return _concatInstanceProperty(_context = []).call(_context, oldValues, [createEmptyField()]);
107
110
  });
108
111
  }, [createEmptyField, onAdd]);
112
+ var isLimitReached = !!maxSize && (value || fieldValues).length >= maxSize;
109
113
  return ___EmotionJSX(Box, others, ___EmotionJSX(Text, {
110
114
  variant: "label"
111
115
  }, label), ___EmotionJSX(Box, {
@@ -125,7 +129,9 @@ var ArrayField = function ArrayField(_ref) {
125
129
  }, onComponentRender ? onComponentRender(id, fieldValue, onFieldValueChange, onFieldDelete, isDisabled, otherFieldProps) : renderField(id, fieldValue, onFieldValueChange, onFieldDelete, isDisabled, otherFieldProps));
126
130
  })), helperText && ___EmotionJSX(FieldHelperText, {
127
131
  status: status
128
- }, helperText), ___EmotionJSX(Button, {
132
+ }, helperText), isLimitReached && ___EmotionJSX(FieldHelperText, {
133
+ status: statuses.DEFAULT
134
+ }, maxSizeText || "Maximum ".concat(maxSize, " items.")), !isLimitReached && ___EmotionJSX(Button, {
129
135
  "aria-label": "Add field",
130
136
  variant: "text",
131
137
  onPress: onFieldAdd,
@@ -173,7 +179,13 @@ ArrayField.propTypes = {
173
179
  renderField: PropTypes.func,
174
180
 
175
181
  /** Determines the helper text styling. */
176
- status: PropTypes.oneOf(_Object$values(statuses))
182
+ status: PropTypes.oneOf(_Object$values(statuses)),
183
+
184
+ /** Determines the maximum number of items */
185
+ maxSize: isValidPositiveInt,
186
+
187
+ /** Text to display when the maximum number of items is reached */
188
+ maxSizeText: PropTypes.node
177
189
  };
178
190
  ArrayField.defaultProps = {
179
191
  addButtonLabel: '+ Add'
@@ -37,6 +37,16 @@ export default {
37
37
  control: {
38
38
  type: 'text'
39
39
  }
40
+ },
41
+ maxSize: {
42
+ control: {
43
+ type: 'number'
44
+ }
45
+ },
46
+ maxSizeText: {
47
+ control: {
48
+ type: 'text'
49
+ }
40
50
  }
41
51
  }
42
52
  };
@@ -193,4 +203,33 @@ export var Controlled = function Controlled() {
193
203
  width: '400px'
194
204
  }
195
205
  });
206
+ };
207
+ export var WithLimitedItemsNumber = function WithLimitedItemsNumber(_ref3) {
208
+ var args = _extends({}, _ref3);
209
+
210
+ return ___EmotionJSX(ArrayField, _extends({
211
+ defaultValue: defaultData,
212
+ renderField: function renderField(id, fieldValue, onFieldValueChange, onFieldDelete, isDisabled, otherFieldProps) {
213
+ return ___EmotionJSX(TextField, _extends({
214
+ "aria-label": "Text field",
215
+ value: fieldValue,
216
+ onChange: function onChange(e) {
217
+ return onFieldValueChange(e, id);
218
+ },
219
+ mr: "xs",
220
+ slots: {
221
+ inContainer: ___EmotionJSX(ArrayFieldDeleteButton, {
222
+ isDisabled: isDisabled,
223
+ onDelete: function onDelete() {
224
+ return onFieldDelete(id);
225
+ }
226
+ })
227
+ }
228
+ }, otherFieldProps));
229
+ },
230
+ sx: {
231
+ width: '400px'
232
+ },
233
+ maxSize: 3
234
+ }, args));
196
235
  };
@@ -191,4 +191,25 @@ test('check if tooltip on delete button renders on hover', function () {
191
191
  fireEvent.mouseMove(button);
192
192
  fireEvent.mouseEnter(button);
193
193
  expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
194
+ });
195
+ test('removes add button if max number of fields is reached', function () {
196
+ getComponent({
197
+ renderField: renderField,
198
+ maxSize: 3
199
+ });
200
+ expect(screen.getAllByLabelText('Text field')).toHaveLength(2);
201
+ fireEvent.click(screen.getByText('+ Add'));
202
+ expect(screen.getAllByLabelText('Text field')).toHaveLength(3);
203
+ expect(screen.queryByText('+ Add')).not.toBeInTheDocument();
204
+ expect(screen.getByText('Maximum 3 items.')).toBeInTheDocument();
205
+ });
206
+ test('displays max size label if provided', function () {
207
+ var maxSizeText = 'Too many fields';
208
+ getComponent({
209
+ renderField: renderField,
210
+ maxSize: 1,
211
+ maxSizeText: maxSizeText
212
+ });
213
+ expect(screen.queryByText('+ Add')).not.toBeInTheDocument();
214
+ expect(screen.getByText(maxSizeText)).toBeInTheDocument();
194
215
  });
@@ -62,7 +62,7 @@ OverlayPanel.propTypes = {
62
62
  /** Sets the open state of the menu. */
63
63
  isOpen: PropTypes.bool,
64
64
 
65
- /** Sets the open state of the menu. */
65
+ /** Sets the size of the overlay panel. */
66
66
  size: PropTypes.oneOf(_Object$values(panelSizes)),
67
67
 
68
68
  /** JSX styling that is passed into the component. */
@@ -35,7 +35,14 @@ export default {
35
35
  fontWeights: fontWeights,
36
36
  sizes: {
37
37
  buttonHeight: 36,
38
- column: 400
38
+ column: 400,
39
+ container: {
40
+ xs: '400px',
41
+ sm: '550px',
42
+ md: '800px',
43
+ lg: '1200px',
44
+ full: '100%'
45
+ }
39
46
  },
40
47
  shadows: {
41
48
  standard: "0 1px 3px ".concat(shadow),
@@ -112,6 +112,14 @@ var accordionGridBody = {
112
112
  width: '100%',
113
113
  '&.is-selected': {
114
114
  display: 'flex !important'
115
+ },
116
+ ':focus': {
117
+ outline: 'none'
118
+ }
119
+ };
120
+ var accordionGridItem = {
121
+ ':focus': {
122
+ outline: 'none'
115
123
  }
116
124
  };
117
125
  export default {
@@ -121,5 +129,6 @@ export default {
121
129
  accordion: accordion,
122
130
  accordionBody: accordionBody,
123
131
  accordionGridHeaderNav: accordionGridHeaderNav,
124
- accordionGridNavItem: accordionGridNavItem
132
+ accordionGridNavItem: accordionGridNavItem,
133
+ accordionGridItem: accordionGridItem
125
134
  };
@@ -24,7 +24,7 @@ var overlayPanel = {
24
24
  width: '800px'
25
25
  },
26
26
  '&.is-full': {
27
- width: '100%'
27
+ width: 'container.full'
28
28
  },
29
29
  '&.is-open': {
30
30
  display: 'flex !important',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pingux/astro",
3
- "version": "1.9.0",
3
+ "version": "1.10.0-alpha.2",
4
4
  "description": "PingUX themeable React component library",
5
5
  "author": "ux-development@pingidentity.com",
6
6
  "license": "Apache-2.0",