@spaced-out/ui-design-system 0.1.93 → 0.1.94-beta.1

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 (41) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/lib/components/ChartWrapper/ChartWrapper.js +8 -2
  3. package/lib/components/ChartWrapper/ChartWrapper.js.flow +31 -15
  4. package/lib/components/ChartWrapper/ChartWrapper.module.css +8 -1
  5. package/lib/components/Charts/index.js +11 -0
  6. package/lib/components/Charts/index.js.flow +1 -0
  7. package/lib/components/ColumnChart/ColumnChart.js +2 -0
  8. package/lib/components/ColumnChart/ColumnChart.js.flow +9 -6
  9. package/lib/components/DateRangePicker/Calendar.js +7 -3
  10. package/lib/components/DateRangePicker/Calendar.js.flow +5 -3
  11. package/lib/components/DateRangePicker/DateRangePicker.js +23 -37
  12. package/lib/components/DateRangePicker/DateRangePicker.js.flow +53 -55
  13. package/lib/components/DateRangePicker/DateRangeWrapper.js +15 -10
  14. package/lib/components/DateRangePicker/DateRangeWrapper.js.flow +20 -16
  15. package/lib/components/DateRangePicker/Day.js +5 -7
  16. package/lib/components/DateRangePicker/Day.js.flow +4 -10
  17. package/lib/components/DateRangePicker/Day.module.css +7 -20
  18. package/lib/components/DateRangePicker/index.js.flow +1 -0
  19. package/lib/components/DateRangePicker/utils.js +87 -72
  20. package/lib/components/DateRangePicker/utils.js.flow +111 -103
  21. package/lib/components/DonutChart/DonutChart.js +5 -3
  22. package/lib/components/DonutChart/DonutChart.js.flow +6 -6
  23. package/lib/components/Dropdown/Dropdown.js +6 -0
  24. package/lib/components/Dropdown/Dropdown.js.flow +6 -0
  25. package/lib/components/Dropdown/SimpleDropdown.js +2 -0
  26. package/lib/components/Dropdown/SimpleDropdown.js.flow +4 -1
  27. package/lib/components/LineChart/LineChart.js +2 -0
  28. package/lib/components/LineChart/LineChart.js.flow +7 -4
  29. package/lib/components/Menu/Menu.js +48 -4
  30. package/lib/components/Menu/Menu.js.flow +79 -13
  31. package/lib/components/Menu/MenuOptionButton.js +3 -1
  32. package/lib/components/Menu/MenuOptionButton.js.flow +3 -0
  33. package/lib/components/SpiderChart/SpiderChart.js +2 -0
  34. package/lib/components/SpiderChart/SpiderChart.js.flow +5 -14
  35. package/lib/components/StickyBar/StickyBar.module.css +2 -2
  36. package/lib/types/charts.js.flow +47 -2
  37. package/lib/utils/charts/charts.js +8 -3
  38. package/lib/utils/charts/charts.js.flow +8 -3
  39. package/lib/utils/charts/donutChart.js +2 -7
  40. package/lib/utils/charts/donutChart.js.flow +2 -21
  41. package/package.json +3 -2
@@ -14,32 +14,29 @@ import {TIMEZONES} from './timezones';
14
14
 
15
15
 
16
16
  export type TimeUnit = 'years' | 'months' | 'days' | 'd' | 'M' | 'y';
17
-
18
- export type DateRange = {
19
- startDate?: string,
20
- endDate?: string,
21
- };
22
-
23
- export type DatePickerSelectedRange = {
24
- startDate?: string,
25
- endDate?: string,
17
+ export type DateRange = {startDate?: string, endDate?: string};
18
+ export type DateRangeWithTimezone = {|
19
+ ...DateRange,
26
20
  startDateUTC?: string,
27
21
  endDateUTC?: string,
28
22
  timeZone?: string,
23
+ |};
24
+
25
+ type MonthRange = {rangeStartMonth: string, rangeEndMonth: string};
26
+ type InitialDateRanges = {
27
+ dateRange: DateRange,
28
+ monthRange: MonthRange,
29
29
  };
30
30
 
31
31
  export const NAVIGATION_ACTION = Object.freeze({
32
32
  NEXT: 'next',
33
33
  PREV: 'prev',
34
34
  });
35
-
36
35
  export const MARKERS = Object.freeze({
37
36
  DATE_RANGE_START: 'FIRST',
38
37
  DATE_RANGE_END: 'SECOND',
39
38
  });
40
-
41
39
  export const WEEKDAYS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
42
-
43
40
  export const MONTHS = [
44
41
  {key: '0', label: 'Jan'},
45
42
  {key: '1', label: 'Feb'},
@@ -55,6 +52,54 @@ export const MONTHS = [
55
52
  {key: '11', label: 'Dec'},
56
53
  ];
57
54
 
55
+ export const wrangleMoment = (date?: string | Date): Date => {
56
+ if (date instanceof Date) {
57
+ return date;
58
+ } else if (!date) {
59
+ return new Date();
60
+ }
61
+ return date instanceof moment ? date.toDate() : parseISO(date);
62
+ };
63
+
64
+ export const formatIsoDate = (date?: string | Date): string =>
65
+ formatISO(wrangleMoment(date), {
66
+ representation: 'date',
67
+ });
68
+
69
+ export const isStartOfRange = ({startDate}: DateRange, date: string): boolean =>
70
+ Boolean(startDate) && moment(date).isSame(moment(startDate), 'd');
71
+
72
+ export const isEndOfRange = ({endDate}: DateRange, date: string): boolean =>
73
+ Boolean(endDate) && moment(date).isSame(moment(endDate), 'd');
74
+
75
+ export const inDateRange = (
76
+ {startDate, endDate}: DateRange,
77
+ date: string,
78
+ ): boolean => {
79
+ if (startDate && endDate) {
80
+ const momentDay = moment(date);
81
+ const momentStartDate = moment(startDate);
82
+ const momentEndDate = moment(endDate);
83
+ return momentDay.isBetween(momentStartDate, momentEndDate, null, '[]');
84
+ }
85
+ return false;
86
+ };
87
+
88
+ export const isStartDateEndDateSame = ({
89
+ startDate,
90
+ endDate,
91
+ }: DateRange): boolean => {
92
+ if (startDate && endDate) {
93
+ return moment(startDate).isSame(moment(endDate), 'd');
94
+ }
95
+ return false;
96
+ };
97
+
98
+ const getMonthAndYear = (date) => {
99
+ const momentDate = date ? moment(date) : moment();
100
+ return [momentDate.month(), momentDate.year()];
101
+ };
102
+
58
103
  export const getDaysInMonth = (date: string): Array<Array<string>> => {
59
104
  const startWeek = moment(date).startOf('month').startOf('week');
60
105
  const endWeek = moment(date).endOf('month').endOf('week');
@@ -81,38 +126,32 @@ export const getDaysInMonth = (date: string): Array<Array<string>> => {
81
126
  return daysInChunks;
82
127
  };
83
128
 
84
- export const isStartOfRange = ({startDate}: DateRange, date: string): boolean =>
85
- !!startDate && moment(date).isSame(startDate, 'd');
86
-
87
- export const isEndOfRange = ({endDate}: DateRange, date: string): boolean =>
88
- !!endDate && moment(date).isSame(endDate, 'd');
129
+ export const getAddedDate = (
130
+ date: string,
131
+ addCount: number,
132
+ timeUnit: TimeUnit,
133
+ ): string => formatIsoDate(moment(date).add(addCount, timeUnit));
89
134
 
90
- export const inDateRange = (
91
- {startDate, endDate}: DateRange,
135
+ export const getSubtractedDate = (
92
136
  date: string,
93
- ): boolean => {
94
- if (startDate && endDate) {
95
- const momentDay = moment(date);
96
- const momentStartDate = moment(startDate);
97
- const momentEndDate = moment(endDate);
98
- return (
99
- momentDay.isBetween(momentStartDate, momentEndDate) ||
100
- momentDay.isSame(momentStartDate, 'd') ||
101
- momentDay.isSame(momentEndDate, 'd')
102
- );
103
- }
104
- return false;
105
- };
137
+ subtractCount: number,
138
+ timeUnit: TimeUnit,
139
+ ): string => formatIsoDate(moment(date).subtract(subtractCount, timeUnit));
106
140
 
107
- export const isStartDateEndDateSame = ({
108
- startDate,
109
- endDate,
110
- }: DateRange): boolean => {
111
- if (startDate && endDate) {
112
- return moment(startDate).isSame(moment(endDate), 'd');
113
- }
114
- return false;
115
- };
141
+ export const getMonthStartDate = (date: string): string =>
142
+ formatIsoDate(moment(date).startOf('M'));
143
+
144
+ export const addTimeZone = (date: string, timeZone: string): string =>
145
+ moment.tz(date, timeZone).startOf('d').utc().toISOString();
146
+
147
+ export const getTimeZones = (): Array<MenuOption> =>
148
+ Object.keys(TIMEZONES).reduce((menuOptions, key) => {
149
+ menuOptions.push({
150
+ key,
151
+ label: TIMEZONES[key],
152
+ });
153
+ return menuOptions;
154
+ }, []);
116
155
 
117
156
  export const generateAvailableYears = (
118
157
  count: number,
@@ -121,8 +160,8 @@ export const generateAvailableYears = (
121
160
  marker: $Values<typeof MARKERS>,
122
161
  ): Array<MenuOption> => {
123
162
  const startYear = moment().year() - count + 1;
124
- const firstCalendarYear = moment(firstCalendarDate).year();
125
- const secondCalendarYear = moment(secondCalendarDate).year();
163
+ const firstCalendarYear = moment(firstCalendarDate).add(1, 'M').year();
164
+ const secondCalendarYear = moment(secondCalendarDate).subtract(1, 'M').year();
126
165
 
127
166
  const isWithinRange = (year: number) =>
128
167
  marker === MARKERS.DATE_RANGE_START
@@ -139,11 +178,6 @@ export const generateAvailableYears = (
139
178
  }).filter(({disabled}) => !disabled);
140
179
  };
141
180
 
142
- const getMonthAndYear = (date) => {
143
- const momentDate = date ? moment(date) : moment();
144
- return [momentDate.month(), momentDate.year()];
145
- };
146
-
147
181
  export const getAvailableMonths = (
148
182
  Months: Array<MenuOption>,
149
183
  first: string,
@@ -171,61 +205,35 @@ export const getAvailableMonths = (
171
205
  });
172
206
  };
173
207
 
174
- export const addTimeZone = (date: string, timeZone: string): string =>
175
- moment.tz(date, timeZone).startOf('d').utc().toISOString();
176
-
177
- export const getSubtractedDate = (
178
- date: string,
179
- subtractCount: number,
180
- timeUnit: TimeUnit,
181
- ): string => formatIsoDate(moment(date).subtract(subtractCount, timeUnit));
182
-
183
- export const getAddedDate = (
184
- date: string,
185
- addCount: number,
186
- timeUnit: TimeUnit,
187
- ): string => formatIsoDate(moment(date).add(addCount, timeUnit));
188
-
189
- export function formatIsoDate(date?: string | Date): string {
190
- return formatISO(wrangleMoment(date), {
191
- representation: 'date',
192
- });
193
- }
194
-
195
- export function wrangleMoment(date?: string | Date): Date {
196
- if (date instanceof Date) {
197
- return date;
198
- } else if (!date) {
199
- return new Date();
208
+ export const getInitialDates = (
209
+ initialDateRange: DateRange,
210
+ ): InitialDateRanges => {
211
+ const today = formatIsoDate();
212
+ const {startDate, endDate} = initialDateRange;
213
+
214
+ const isStartDateValid = moment(startDate).isSameOrBefore(today);
215
+ const isEndDateValid = moment(endDate).isSameOrBefore(today);
216
+
217
+ const dateRange =
218
+ startDate &&
219
+ endDate &&
220
+ isStartDateValid &&
221
+ isEndDateValid &&
222
+ moment(endDate).isSameOrAfter(startDate)
223
+ ? {startDate, endDate}
224
+ : {startDate: undefined, endDate: undefined};
225
+
226
+ let startMonth = dateRange.startDate
227
+ ? getMonthStartDate(dateRange.startDate)
228
+ : getMonthStartDate(getSubtractedDate(today, 1, 'M'));
229
+ const endMonth = dateRange.endDate
230
+ ? getMonthStartDate(dateRange.endDate)
231
+ : getMonthStartDate(today);
232
+
233
+ if (moment(startMonth).isSame(moment(endMonth), 'M')) {
234
+ startMonth = getSubtractedDate(endMonth, 1, 'M');
200
235
  }
201
- return date instanceof moment ? date.toDate() : parseISO(date);
202
- }
203
236
 
204
- export const getValidatedMonths = (
205
- {startDate, endDate}: DateRange,
206
- minDate: string,
207
- maxDate: string,
208
- ): Array<?string> => {
209
- if (startDate && endDate) {
210
- const newStart = moment.max(moment(startDate), moment(minDate)); // TODO Figure out the validated date
211
- const newEnd = moment.min(moment(endDate), moment(maxDate));
212
-
213
- return [
214
- formatIsoDate(newStart),
215
- newStart.isSame(newEnd, 'M')
216
- ? getAddedDate(newEnd, 1, 'M')
217
- : formatIsoDate(newEnd),
218
- ];
219
- } else {
220
- return [startDate, endDate];
221
- }
237
+ const monthRange = {rangeStartMonth: startMonth, rangeEndMonth: endMonth};
238
+ return {dateRange, monthRange};
222
239
  };
223
-
224
- export const getTimeZones = (): Array<MenuOption> =>
225
- Object.keys(TIMEZONES).reduce((menuOptions, key) => {
226
- menuOptions.push({
227
- key,
228
- label: TIMEZONES[key],
229
- });
230
- return menuOptions;
231
- }, []);
@@ -22,6 +22,7 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
22
22
 
23
23
  const DonutChart = _ref => {
24
24
  let {
25
+ isLoading,
25
26
  classNames,
26
27
  cardTitle,
27
28
  customExportOptions,
@@ -72,15 +73,16 @@ const DonutChart = _ref => {
72
73
  legend,
73
74
  defaultCenterHTML
74
75
  });
76
+
77
+ //$FlowFixMe[cannot-spread-inexact]
75
78
  const chartOptions = (0, _charts.mergeChartUserOptions)(defaultLineChartOptions, {
76
79
  series: donutChartSeries,
77
80
  drilldown: donutDrilldown,
78
81
  ...userOptions
79
82
  });
80
83
  return /*#__PURE__*/React.createElement(_ChartWrapper.ChartWrapper, {
81
- title: cardTitle
82
- //$FlowFixMe[incompatible-type]
83
- ,
84
+ isLoading: isLoading,
85
+ title: cardTitle,
84
86
  ref: chartRef,
85
87
  customExportOptions: customExportOptions,
86
88
  headerActions: headerActions,
@@ -29,10 +29,6 @@ type ClassNames = $ReadOnly<{
29
29
  highChart?: string,
30
30
  subtitleClassNames?: SubtitleClassNames,
31
31
  }>;
32
- type DonutChartData = {
33
- name: string,
34
- value: number,
35
- };
36
32
 
37
33
  export type SubtitleClassNames = {
38
34
  wrapper?: string,
@@ -41,6 +37,7 @@ export type SubtitleClassNames = {
41
37
  };
42
38
 
43
39
  export type DonutChartProps = {
40
+ isLoading?: boolean,
44
41
  classNames?: ClassNames,
45
42
  cardTitle?: React.Node,
46
43
  customExportOptions?: Array<ExportOptionType> | null,
@@ -48,11 +45,13 @@ export type DonutChartProps = {
48
45
  centerText?: string,
49
46
  centerSubtext?: string,
50
47
  series: Array<SeriesOptionsType>,
51
- drilldown: Drilldown,
48
+ drilldown?: Drilldown,
52
49
  legend?: LegendOptionsType,
50
+ ...
53
51
  };
54
52
 
55
53
  export const DonutChart = ({
54
+ isLoading,
56
55
  classNames,
57
56
  cardTitle,
58
57
  customExportOptions,
@@ -119,6 +118,7 @@ export const DonutChart = ({
119
118
  defaultCenterHTML,
120
119
  });
121
120
 
121
+ //$FlowFixMe[cannot-spread-inexact]
122
122
  const chartOptions = mergeChartUserOptions(defaultLineChartOptions, {
123
123
  series: donutChartSeries,
124
124
  drilldown: donutDrilldown,
@@ -127,8 +127,8 @@ export const DonutChart = ({
127
127
 
128
128
  return (
129
129
  <ChartWrapper
130
+ isLoading={isLoading}
130
131
  title={cardTitle}
131
- //$FlowFixMe[incompatible-type]
132
132
  ref={chartRef}
133
133
  customExportOptions={customExportOptions}
134
134
  headerActions={headerActions}
@@ -64,6 +64,12 @@ const Dropdown = /*#__PURE__*/React.forwardRef((_ref, ref) => {
64
64
  className: (0, _classify.classify)(_DropdownModule.default.dropdownContainer, classNames?.wrapper),
65
65
  ref: dropdownRef
66
66
  }, /*#__PURE__*/React.createElement(_Input.Input, _extends({}, inputProps, {
67
+ onKeyDown: e => {
68
+ if (e.keyCode === 32) {
69
+ e.preventDefault();
70
+ onOpen();
71
+ }
72
+ },
67
73
  boxRef: refs.setReference,
68
74
  size: size,
69
75
  placeholder: placeholder,
@@ -84,6 +84,12 @@ export const Dropdown: React$AbstractComponent<
84
84
  >
85
85
  <Input
86
86
  {...inputProps}
87
+ onKeyDown={(e) => {
88
+ if (e.keyCode === 32) {
89
+ e.preventDefault();
90
+ onOpen();
91
+ }
92
+ }}
87
93
  boxRef={refs.setReference}
88
94
  size={size}
89
95
  placeholder={placeholder}
@@ -23,6 +23,7 @@ const SimpleDropdownBase = (props, ref) => {
23
23
  onMenuOpen,
24
24
  onMenuClose,
25
25
  resolveLabel,
26
+ menuVirtualization,
26
27
  resolveSecondaryLabel,
27
28
  isMenuFluid = true,
28
29
  ...inputProps
@@ -67,6 +68,7 @@ const SimpleDropdownBase = (props, ref) => {
67
68
  allowSearch,
68
69
  resolveLabel,
69
70
  resolveSecondaryLabel,
71
+ virtualization: menuVirtualization,
70
72
  size,
71
73
  isFluid: isMenuFluid
72
74
  }
@@ -7,7 +7,7 @@ import {
7
7
  getTextLabelFromSelectedKeys,
8
8
  } from '../../utils/menu';
9
9
  import type {InputProps} from '../Input';
10
- import type {MenuOption, MenuOptionsVariant} from '../Menu';
10
+ import type {MenuOption, MenuOptionsVariant, Virtualization} from '../Menu';
11
11
 
12
12
  import {Dropdown} from './Dropdown';
13
13
 
@@ -34,6 +34,7 @@ export type SimpleDropdownProps = {
34
34
  allowSearch?: boolean,
35
35
  selectedKeys?: Array<string>,
36
36
  isMenuFluid?: boolean,
37
+ menuVirtualization?: Virtualization,
37
38
 
38
39
  // events
39
40
  onChange?: (option: MenuOption, ?SyntheticEvent<HTMLElement>) => mixed,
@@ -59,6 +60,7 @@ const SimpleDropdownBase = (props: SimpleDropdownProps, ref) => {
59
60
  onMenuOpen,
60
61
  onMenuClose,
61
62
  resolveLabel,
63
+ menuVirtualization,
62
64
  resolveSecondaryLabel,
63
65
  isMenuFluid = true,
64
66
  ...inputProps
@@ -122,6 +124,7 @@ const SimpleDropdownBase = (props: SimpleDropdownProps, ref) => {
122
124
  allowSearch,
123
125
  resolveLabel,
124
126
  resolveSecondaryLabel,
127
+ virtualization: menuVirtualization,
125
128
  size,
126
129
  isFluid: isMenuFluid,
127
130
  }}
@@ -21,6 +21,7 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
21
21
 
22
22
  const LineChart = _ref => {
23
23
  let {
24
+ isLoading,
24
25
  classNames,
25
26
  cardTitle,
26
27
  customExportOptions,
@@ -55,6 +56,7 @@ const LineChart = _ref => {
55
56
  ...wrapperClassNames
56
57
  } = classNames || {};
57
58
  return /*#__PURE__*/React.createElement(_ChartWrapper.ChartWrapper, {
59
+ isLoading: isLoading,
58
60
  title: cardTitle,
59
61
  ref: chartRef,
60
62
  classNames: wrapperClassNames,
@@ -6,7 +6,7 @@ import Highcharts from 'highcharts';
6
6
  //$FlowFixMe[untyped-import]
7
7
  import HighchartsReact from 'highcharts-react-official';
8
8
 
9
- import type {Drilldown} from '../../types/charts';
9
+ import type {DataOptionsType, Drilldown} from '../../types/charts';
10
10
  import {
11
11
  getDataVizColor,
12
12
  getLineChartOptions,
@@ -26,20 +26,22 @@ type ClassNames = $ReadOnly<{
26
26
 
27
27
  type LineSeriesItem = {
28
28
  name: string,
29
- data: [],
29
+ data: DataOptionsType[],
30
30
  };
31
31
 
32
32
  export type LineChartProps = {
33
+ isLoading?: boolean,
33
34
  classNames?: ClassNames,
34
- cardTitle?: string,
35
+ cardTitle?: React.Node,
35
36
  customExportOptions?: Array<ExportOptionType> | null,
36
37
  series: Array<LineSeriesItem>,
37
38
  headerActions?: React.Node,
38
- drilldown: Drilldown,
39
+ drilldown?: Drilldown,
39
40
  ...
40
41
  };
41
42
 
42
43
  export const LineChart = ({
44
+ isLoading,
43
45
  classNames,
44
46
  cardTitle,
45
47
  customExportOptions,
@@ -77,6 +79,7 @@ export const LineChart = ({
77
79
 
78
80
  return (
79
81
  <ChartWrapper
82
+ isLoading={isLoading}
80
83
  title={cardTitle}
81
84
  ref={chartRef}
82
85
  classNames={wrapperClassNames}
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.Menu = void 0;
7
7
  var React = _interopRequireWildcard(require("react"));
8
+ var _reactWindow = require("react-window");
8
9
  var _classify = require("../../utils/classify");
9
10
  var _menu = require("../../utils/menu");
10
11
  var _SearchInput = require("../SearchInput");
@@ -15,6 +16,10 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
15
16
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
16
17
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
17
18
  function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
19
+ const menuSizeMedium = 276,
20
+ menuSizeSmall = 228;
21
+ const buttonSizeMedium = 40,
22
+ buttonSizeSmall = 32;
18
23
  const RenderOption = _ref => {
19
24
  let {
20
25
  options,
@@ -25,15 +30,45 @@ const RenderOption = _ref => {
25
30
  ...restProps
26
31
  } = _ref;
27
32
  const {
28
- allowSearch
33
+ allowSearch,
34
+ size,
35
+ virtualization = {
36
+ enable: false,
37
+ menuHeight: null,
38
+ itemHeight: null
39
+ }
29
40
  } = restProps;
30
41
  if (options && Array.isArray(options) && options.length) {
31
42
  const optionsFiltered = !allowSearch ? options : (0, _menu.getFilteredOptionsFromSearchText)(options, searchText);
32
43
  const resultText = !allowSearch ? '' : (0, _menu.getFilteredOptionsResultText)(optionsFiltered);
44
+ const {
45
+ enable: isVirtualizationEnabled,
46
+ menuHeight,
47
+ itemHeight
48
+ } = virtualization;
33
49
  return /*#__PURE__*/React.createElement(React.Fragment, null, allowSearch && /*#__PURE__*/React.createElement(_Text.FormLabelSmall, {
34
50
  className: _MenuModule.default.filterOptionsResultText,
35
51
  color: "tertiary"
36
- }, resultText), optionsFiltered.map((option, idx) => /*#__PURE__*/React.createElement(React.Fragment, {
52
+ }, resultText), virtualization && isVirtualizationEnabled ? /*#__PURE__*/React.createElement(_reactWindow.FixedSizeList, {
53
+ height: menuHeight || (size === 'medium' ? menuSizeMedium : menuSizeSmall),
54
+ itemSize: itemHeight || (size === 'medium' ? buttonSizeMedium : buttonSizeSmall),
55
+ itemCount: optionsFiltered.length
56
+ }, _ref2 => {
57
+ let {
58
+ index: idx,
59
+ style
60
+ } = _ref2;
61
+ const buttonOption = optionsFiltered[idx];
62
+ return /*#__PURE__*/React.createElement(React.Fragment, {
63
+ key: buttonOption.key
64
+ }, /*#__PURE__*/React.createElement(_MenuOptionButton.MenuOptionButton, _extends({
65
+ option: buttonOption,
66
+ classNames: classNames,
67
+ style: style
68
+ }, restProps, {
69
+ isLastItem: idx === optionsFiltered.length - 1
70
+ })));
71
+ }) : optionsFiltered.map((option, idx) => /*#__PURE__*/React.createElement(React.Fragment, {
37
72
  key: option.key
38
73
  }, /*#__PURE__*/React.createElement(_MenuOptionButton.MenuOptionButton, _extends({
39
74
  option: option,
@@ -93,9 +128,17 @@ const Menu = /*#__PURE__*/React.forwardRef((props, ref) => {
93
128
  size = 'medium',
94
129
  width,
95
130
  isFluid = true,
96
- allowSearch
131
+ allowSearch,
132
+ virtualization = {
133
+ enable: false,
134
+ menuHeight: null,
135
+ itemHeight: null
136
+ }
97
137
  } = props;
98
138
  const [searchText, setSearchText] = React.useState('');
139
+ const {
140
+ menuHeight
141
+ } = virtualization;
99
142
  return /*#__PURE__*/React.createElement("div", {
100
143
  className: (0, _classify.classify)(_MenuModule.default.menuCard, {
101
144
  [_MenuModule.default.fluid]: isFluid,
@@ -103,7 +146,8 @@ const Menu = /*#__PURE__*/React.forwardRef((props, ref) => {
103
146
  [_MenuModule.default.small]: size === 'small'
104
147
  }, classNames?.wrapper),
105
148
  style: {
106
- width
149
+ width,
150
+ maxHeight: menuHeight ? menuHeight + 'px' : ''
107
151
  },
108
152
  ref: ref
109
153
  }, allowSearch && /*#__PURE__*/React.createElement(_SearchInput.SearchInput, {