pixel-react 1.2.8 → 1.2.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. package/.yarn/install-state.gz +0 -0
  2. package/lib/components/AddButton/AddButton.d.ts +5 -0
  3. package/lib/components/AddButton/AddButton.stories.d.ts +6 -0
  4. package/lib/components/AddButton/index.d.ts +1 -0
  5. package/lib/components/AddButton/types.d.ts +4 -0
  6. package/lib/components/Editor/Editor.d.ts +5 -0
  7. package/lib/components/Editor/Editor.stories.d.ts +6 -0
  8. package/lib/components/Editor/VariableDropdown.d.ts +5 -0
  9. package/lib/components/Editor/constants.d.ts +3 -0
  10. package/lib/components/Editor/index.d.ts +1 -0
  11. package/lib/components/Editor/types.d.ts +71 -0
  12. package/lib/components/ExcelFile/ChangeExcelStyles.d.ts +14 -0
  13. package/lib/components/ExcelFile/ColorBarselector/ColorBarSelector.d.ts +8 -0
  14. package/lib/components/ExcelFile/ContextMenu/ContextMenu.d.ts +4 -0
  15. package/lib/components/ExcelFile/ExcelFile/Excel/ActiveCell.d.ts +7 -0
  16. package/lib/components/ExcelFile/ExcelFile/Excel/Cell.d.ts +4 -0
  17. package/lib/components/ExcelFile/ExcelFile/Excel/ColumnIndicator.d.ts +5 -0
  18. package/lib/components/ExcelFile/ExcelFile/Excel/Copied.d.ts +3 -0
  19. package/lib/components/ExcelFile/ExcelFile/Excel/CornerIndicator.d.ts +5 -0
  20. package/lib/components/ExcelFile/ExcelFile/Excel/DataEditor.d.ts +5 -0
  21. package/lib/components/ExcelFile/ExcelFile/Excel/DataViewer.d.ts +8 -0
  22. package/lib/components/ExcelFile/ExcelFile/Excel/FloatingRect.d.ts +10 -0
  23. package/lib/components/ExcelFile/ExcelFile/Excel/HeaderRow.d.ts +3 -0
  24. package/lib/components/ExcelFile/ExcelFile/Excel/Row.d.ts +3 -0
  25. package/lib/components/ExcelFile/ExcelFile/Excel/RowIndicator.d.ts +5 -0
  26. package/lib/components/ExcelFile/ExcelFile/Excel/Selected.d.ts +3 -0
  27. package/lib/components/ExcelFile/ExcelFile/Excel/Spreadsheet.d.ts +81 -0
  28. package/lib/components/ExcelFile/ExcelFile/Excel/Table.d.ts +3 -0
  29. package/lib/components/ExcelFile/ExcelFile/Excel/actions.d.ts +130 -0
  30. package/lib/components/ExcelFile/ExcelFile/Excel/areModelsEqual.d.ts +1 -0
  31. package/lib/components/ExcelFile/ExcelFile/Excel/context.d.ts +8 -0
  32. package/lib/components/ExcelFile/ExcelFile/Excel/engine/engine.d.ts +22 -0
  33. package/lib/components/ExcelFile/ExcelFile/Excel/engine/formula.d.ts +17 -0
  34. package/lib/components/ExcelFile/ExcelFile/Excel/engine/index.d.ts +2 -0
  35. package/lib/components/ExcelFile/ExcelFile/Excel/engine/point-graph.d.ts +21 -0
  36. package/lib/components/ExcelFile/ExcelFile/Excel/engine/point-hash.d.ts +3 -0
  37. package/lib/components/ExcelFile/ExcelFile/Excel/engine/point-set.d.ts +24 -0
  38. package/lib/components/ExcelFile/ExcelFile/Excel/index.d.ts +13 -0
  39. package/lib/components/ExcelFile/ExcelFile/Excel/matrix.d.ts +67 -0
  40. package/lib/components/ExcelFile/ExcelFile/Excel/point-range.d.ts +22 -0
  41. package/lib/components/ExcelFile/ExcelFile/Excel/point.d.ts +11 -0
  42. package/lib/components/ExcelFile/ExcelFile/Excel/reducer.d.ts +27 -0
  43. package/lib/components/ExcelFile/ExcelFile/Excel/selection.d.ts +95 -0
  44. package/lib/components/ExcelFile/ExcelFile/Excel/types.d.ts +215 -0
  45. package/lib/components/ExcelFile/ExcelFile/Excel/use-dispatch.d.ts +3 -0
  46. package/lib/components/ExcelFile/ExcelFile/Excel/use-selector.d.ts +3 -0
  47. package/lib/components/ExcelFile/ExcelFile/Excel/util.d.ts +45 -0
  48. package/lib/components/ExcelFile/ExcelFile/ExcelFile.d.ts +3 -0
  49. package/lib/components/ExcelFile/ExcelFile.stories.d.ts +6 -0
  50. package/lib/components/ExcelFile/ExcelSheetBar/ExcelSheetBar.d.ts +15 -0
  51. package/lib/components/ExcelFile/ExcelToolBar/ExcelToolBar.d.ts +3 -0
  52. package/lib/components/ExcelFile/ImportExcelStyles.d.ts +24 -0
  53. package/lib/components/ExcelFile/Types.d.ts +176 -0
  54. package/lib/components/ExcelFile/index.d.ts +1 -0
  55. package/lib/components/InputWithDropdown/InputWithDropdown.d.ts +1 -1
  56. package/lib/components/InputWithDropdown/types.d.ts +3 -1
  57. package/lib/components/Select/Select.d.ts +3 -2
  58. package/lib/components/Select/components/Dropdown.d.ts +5 -0
  59. package/lib/components/Select/components/types.d.ts +18 -0
  60. package/lib/components/Select/types.d.ts +2 -42
  61. package/lib/index.d.ts +7 -12
  62. package/lib/index.esm.js +200 -330
  63. package/lib/index.esm.js.map +1 -1
  64. package/lib/index.js +199 -329
  65. package/lib/index.js.map +1 -1
  66. package/lib/tsconfig.tsbuildinfo +1 -1
  67. package/lib/utils/find/findAndInsert.d.ts +7 -0
  68. package/lib/utils/find/findAndInsert.stories.d.ts +7 -0
  69. package/package.json +3 -3
  70. package/src/assets/Themes/BaseTheme.scss +1 -0
  71. package/src/assets/Themes/DarkTheme.scss +2 -0
  72. package/src/components/Icon/Icons.scss +4 -0
  73. package/src/components/InputWithDropdown/InputWithDropdown.scss +30 -1
  74. package/src/components/InputWithDropdown/InputWithDropdown.tsx +45 -16
  75. package/src/components/InputWithDropdown/types.ts +5 -1
  76. package/src/components/Select/Select.scss +121 -188
  77. package/src/components/Select/Select.stories.tsx +4 -1
  78. package/src/components/Select/Select.tsx +140 -296
  79. package/src/components/Select/components/Dropdown.scss +50 -0
  80. package/src/components/Select/components/Dropdown.tsx +94 -0
  81. package/src/components/Select/components/types.ts +20 -0
  82. package/src/components/Select/types.ts +15 -39
  83. package/src/utils/getSelectOptionValue/getSelectOptionValue.ts +1 -1
@@ -1,109 +1,17 @@
1
- import { useReducer, useRef, useEffect, useMemo } from 'react';
2
- import { Option, SelectAction, SelectProps, SelectState } from './types';
3
- import { checkEmpty } from '../../utils/checkEmpty/checkEmpty';
4
- import { createPortal } from 'react-dom';
5
- import classNames from 'classnames';
6
- import Dropdown from './components/Dropdown/Dropdown';
7
- import Icon from '../Icon';
1
+ import { ChangeEvent, FC, useEffect, useRef, useState } from 'react';
8
2
  import './Select.scss';
9
- import usePortalPosition from '../../hooks/usePortalPosition';
3
+ import Icon from '../Icon';
10
4
  import Typography from '../Typography';
5
+ import { DrowdownPosition, Option, SelectProps } from './types';
6
+ import classNames from 'classnames';
7
+ import { createPortal } from 'react-dom';
8
+ import Dropdown from './components/Dropdown';
11
9
  import { getValue } from '../../utils/getSelectOptionValue/getSelectOptionValue';
10
+ import usePortalPosition from '../../hooks/usePortalPosition';
11
+ import { checkEmpty } from '../../utils/checkEmpty/checkEmpty';
12
12
 
13
- const selectReducer = (
14
- state: SelectState,
15
- action: SelectAction
16
- ): SelectState => {
17
- switch (action.type) {
18
- case 'FOCUS_INPUT':
19
- return {
20
- ...state,
21
- isInputFocused: true,
22
- iconColor: 'var(--ff-select-brand-color)',
23
- isIconClick: true,
24
- showOptions: true,
25
- };
26
- case 'BLUR_INPUT':
27
- return {
28
- ...state,
29
- isInputFocused: false,
30
- options: action.payload.optionsList,
31
- option: action.payload.option,
32
-
33
- // todo color need to be add in style guide
34
- iconColor: 'var(--ff-select-default-color)',
35
- isIconClick: false,
36
- showOptions: false,
37
- dropdownPosition: {
38
- positionX: 0,
39
- positionY: 0,
40
- width: 0,
41
- fromBottom: 0,
42
- },
43
- };
44
- case 'MOUSE_ENTER':
45
- return state.isInputFocused
46
- ? state
47
- : { ...state, iconColor: 'var(--ff-select-text-hover-color)' };
48
- case 'MOUSE_LEAVE':
49
- return state.isInputFocused
50
- ? state
51
- : // todo color need to be add in style guide
52
- {
53
- ...state,
54
- iconColor: 'var(--ff-select-default-color)',
55
- isIconClick: false,
56
- };
57
-
58
- case 'UPDATE_DROPDOWN_POSITION':
59
- const { positionX, positionY, width, fromBottom } = action.payload || {};
60
- return {
61
- ...state,
62
- dropdownPosition: {
63
- positionX,
64
- positionY,
65
- width,
66
- fromBottom,
67
- },
68
- };
69
-
70
- case 'UPDATE_OPTION':
71
- return {
72
- ...state,
73
- option: action.payload,
74
- };
75
-
76
- case 'UPDATE_OPTION_LIST':
77
- return {
78
- ...state,
79
- options: action.payload,
80
- };
81
- case 'SHOW_ERROR':
82
- return {
83
- ...state,
84
- isInputFocused: true,
85
- isIconClick: false,
86
- showOptions: false,
87
- options: action.payload.optionsList,
88
- option: action.payload.option,
89
-
90
- // todo color need to be add in style guide
91
- iconColor: 'var(--ff-select-default-color)',
92
- dropdownPosition: {
93
- positionX: 0,
94
- positionY: 0,
95
- width: 0,
96
- fromBottom: 0,
97
- },
98
- };
99
-
100
- default:
101
- return state;
102
- }
103
- };
104
-
105
- const Select = ({
106
- label = '',
13
+ const Select: FC<SelectProps> = ({
14
+ label = 'Default Label',
107
15
  showLabel = true,
108
16
  optionsList = [],
109
17
  selectedOption = { label: '', value: '' },
@@ -112,271 +20,207 @@ const Select = ({
112
20
  className = '',
113
21
  optionZIndex = 100,
114
22
  disabled = false,
115
- borderRadius = true,
116
23
  showBorder = true,
117
- required = false,
24
+ required = true,
118
25
  optionsRequired = true,
119
26
  selectedOptionColor = 'var(--ff-select-text-color)',
120
- labelAccessor,
121
- valueAccessor,
122
- }: SelectProps) => {
123
- const initialState: SelectState = useMemo(
124
- () => ({
125
- isInputFocused: false,
126
-
127
- // todo color need to be added in style guide
128
- iconColor: 'var(--ff-select-default-color)',
129
- isIconClick: false,
130
- showOptions: false,
131
- options: optionsList,
132
- option: checkEmpty(selectedOption) ? '' : selectedOption?.value,
133
- dropdownPosition: { positionX: 0, positionY: 0, width: 0, fromBottom: 0 },
134
- }),
135
- [optionsList, selectedOption]
136
- );
137
-
138
- const [selectControlState, dispatch] = useReducer(
139
- selectReducer,
140
- initialState
141
- );
142
-
143
- const DropDownRef = useRef<HTMLDivElement>(null);
144
- const InputRef = useRef<HTMLInputElement>(null);
145
-
146
- const {
147
- isInputFocused,
148
- iconColor,
149
- isIconClick,
150
- showOptions,
151
- dropdownPosition,
152
- options,
153
- option,
154
- } = selectControlState;
155
-
156
- const calculatePosition = usePortalPosition(DropDownRef, showOptions);
157
-
158
- const handleSelectAction = (
159
- actionType:
160
- | 'FOCUS_INPUT'
161
- | 'MOUSE_ENTER'
162
- | 'MOUSE_LEAVE'
163
- | 'SHOW_ERROR'
164
- | 'BLUR_INPUT'
165
- ) => {
166
- if (!disabled) {
167
- if (actionType === 'SHOW_ERROR' || actionType === 'BLUR_INPUT') {
168
- dispatch({
169
- type: actionType,
170
- payload: { optionsList, option: getValue(selectedOption) },
171
- });
172
- } else {
173
- dispatch({ type: actionType });
174
- }
175
- }
27
+ labelAccessor = '',
28
+ valueAccessor = '',
29
+ height = 32,
30
+ width = 300,
31
+ }) => {
32
+ const [showDropdownOptions, setShowDropdownOptions] = useState(false);
33
+ const [searchedOption, setSearchedOption] = useState('');
34
+ const [selectOptionList, setSelectOptionList] = useState(optionsList);
35
+ const [dropdownPosition, setDropdownPosition] = useState<DrowdownPosition>({
36
+ positionX: 0,
37
+ positionY: 0,
38
+ width: 0,
39
+ fromBottom: 0,
40
+ });
41
+
42
+ const DropdownRef = useRef<HTMLDivElement>(null);
43
+ const selectWrapperRef = useRef<HTMLDivElement>(null);
44
+ const inputRef = useRef<HTMLInputElement>(null);
45
+ const selectArrowRef = useRef<HTMLDivElement>(null);
46
+
47
+ const calculatePosition = usePortalPosition(DropdownRef, showDropdownOptions);
48
+
49
+ const handleIconClick = () => {
50
+ setShowDropdownOptions(!showDropdownOptions);
176
51
  };
177
52
 
178
- const onSelectInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
53
+ const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
179
54
  if (disabled) return;
180
- const { value } = e.target;
55
+ const { value } = event.target;
56
+
181
57
  const filteredOptions = optionsList.filter((option) => {
182
58
  const valueData = getValue(option, valueAccessor);
183
59
  return typeof valueData === 'string'
184
60
  ? valueData.toLowerCase().includes(value.toLowerCase().trim())
185
61
  : valueData === Number(value);
186
62
  });
187
- dispatch({ type: 'UPDATE_OPTION_LIST', payload: filteredOptions });
188
- dispatch({ type: 'UPDATE_OPTION', payload: value });
63
+
64
+ setSelectOptionList(filteredOptions);
65
+ setSearchedOption(value);
189
66
  };
190
67
 
191
- const onSelectBlur = () => {
192
- if (disabled) return;
68
+ const onSelectUpdatePosition = () => {
69
+ if (!showDropdownOptions || !DropdownRef?.current || disabled) return;
70
+ setDropdownPosition(calculatePosition(DropdownRef));
71
+ };
72
+
73
+ const onSelectToggleScroll = (isEnabled: boolean): void => {
74
+ const scrollWidth =
75
+ window.innerWidth - document.documentElement.clientWidth;
193
76
 
194
- if (errorMsg) {
195
- handleSelectAction('SHOW_ERROR');
77
+ if (isEnabled) {
78
+ document.body.style.paddingRight = '';
79
+ document.body.style.overflow = '';
196
80
  } else {
197
- handleSelectAction('BLUR_INPUT');
81
+ document.body.style.paddingRight = `${scrollWidth}px`;
82
+ document.body.style.overflow = 'hidden';
198
83
  }
199
84
  };
200
85
 
201
- const onSelectOptionSelector = (option: Option) => {
202
- if (!disabled) {
203
- onSelectBlur();
204
- dispatch({
205
- type: 'UPDATE_OPTION',
206
- payload: getValue(option, valueAccessor),
207
- });
208
- if (onChange) {
209
- onChange(option);
210
- }
211
- }
86
+ const handleFocus = () => {
87
+ if (disabled) return;
88
+ setShowDropdownOptions(true);
212
89
  };
213
90
 
214
- const onSelectUpdatePosition = () => {
215
- if (!showOptions || !DropDownRef?.current || disabled) return;
216
- const { positionX, positionY, width, fromBottom } =
217
- calculatePosition(DropDownRef);
218
- dispatch({
219
- type: 'UPDATE_DROPDOWN_POSITION',
220
- payload: { positionX, positionY, width, fromBottom },
91
+ const onSelectBlur = () => {
92
+ setShowDropdownOptions(false);
93
+ setDropdownPosition({
94
+ positionX: 0,
95
+ positionY: 0,
96
+ fromBottom: 0,
97
+ width: 0,
221
98
  });
99
+ setSearchedOption(getValue(selectedOption, valueAccessor));
100
+ setSelectOptionList(optionsList);
222
101
  };
223
102
 
224
- const onSelectToggleScroll = (isEnabled: boolean) => {
225
- const bodyScrollWidth = window.innerWidth - document.body.clientWidth;
226
- document.body.style.paddingRight = isEnabled ? '' : `${bodyScrollWidth}px`;
227
- document.body.style.overflow = isEnabled ? '' : 'hidden';
103
+ const onSelectOptionSelector = (option: Option): void => {
104
+ if (disabled) return;
105
+ onSelectBlur();
106
+ setSearchedOption(getValue(option, valueAccessor));
107
+ if (onChange) {
108
+ onChange(option);
109
+ }
228
110
  };
229
111
 
230
- useEffect(() => {
112
+ const handleResizeOrScroll = () => onSelectUpdatePosition();
113
+
114
+ const hideShowScrollbar = () => {
231
115
  if (disabled) return;
232
- if (showOptions) {
233
- onSelectToggleScroll(!showOptions);
116
+ if (showDropdownOptions && optionsRequired) {
117
+ onSelectToggleScroll(!showDropdownOptions);
234
118
  }
235
119
  onSelectUpdatePosition();
236
120
 
237
- const handleResizeOrScroll = () => onSelectUpdatePosition();
238
-
239
121
  window.addEventListener('resize', handleResizeOrScroll);
240
122
  window.addEventListener('scroll', handleResizeOrScroll);
123
+ };
124
+
125
+ useEffect(() => {
126
+ hideShowScrollbar();
241
127
  return () => {
242
128
  onSelectToggleScroll(true);
243
129
  window.removeEventListener('resize', handleResizeOrScroll);
244
130
  window.removeEventListener('scroll', handleResizeOrScroll);
245
131
  };
246
- }, [showOptions]);
132
+ }, [showDropdownOptions]);
247
133
 
248
134
  useEffect(() => {
249
- if (errorMsg) {
250
- handleSelectAction('SHOW_ERROR');
251
- }
252
- }, []);
253
-
254
- useEffect(() => {
255
- if (!checkEmpty(selectedOption.label)) {
256
- onSelectOptionSelector(selectedOption);
257
- }
135
+ if (checkEmpty(getValue(selectedOption, valueAccessor))) return;
136
+ setSearchedOption(getValue(selectedOption, valueAccessor));
258
137
  }, [selectedOption]);
259
138
 
260
- const applyActiveOptionClasses = !isInputFocused && Boolean(option);
261
-
262
139
  return (
263
- <div className={classNames(`ff-select-wrapper`)}>
264
- <div className={`ff-select ${className}`}>
140
+ <div
141
+ className={`ff-select-wrapper ${className}`}
142
+ ref={selectWrapperRef}
143
+ style={{ height: `${height}px`, width: `${width}px` }}
144
+ >
145
+ <div
146
+ className={classNames('ff-select', {
147
+ 'ff-select__focus': showDropdownOptions,
148
+ 'ff-select__disabled': disabled,
149
+ 'ff-select__error': !!errorMsg,
150
+ 'ff-select__error__focused': !!errorMsg && showDropdownOptions,
151
+ 'ff-select__no_border': !showBorder,
152
+ })}
153
+ >
265
154
  <input
266
155
  type="text"
156
+ ref={inputRef}
157
+ id="select-input-element"
267
158
  className={classNames('ff-select-input', {
268
- 'ff-select-input--default': !isInputFocused,
269
- 'ff-select-input--active': applyActiveOptionClasses,
270
- 'ff-select-input--no-label': !showLabel,
271
- 'ff-select-input--error':
272
- errorMsg && !isInputFocused && !Boolean(option),
273
- 'ff-select-input--border-radius': !borderRadius,
274
- 'ff-select-input--disable': disabled,
275
- 'ff-select-input--no-border': !showBorder,
159
+ 'ff-select-input__disabled': disabled,
276
160
  })}
277
- // inline css required due to multiple overlay scenarios are present
278
- style={{ zIndex: optionZIndex, color: selectedOptionColor }}
279
- onFocus={() => handleSelectAction('FOCUS_INPUT')}
280
- onMouseEnter={() => handleSelectAction('MOUSE_ENTER')}
281
- onMouseLeave={() => handleSelectAction('MOUSE_LEAVE')}
282
- onChange={onSelectInputChange}
283
- value={option}
284
- disabled={disabled}
161
+ onFocus={handleFocus}
162
+ value={searchedOption}
163
+ autoCorrect="off"
285
164
  autoComplete="off"
286
165
  spellCheck="false"
287
- ref={InputRef}
166
+ style={{ zIndex: optionZIndex, color: selectedOptionColor }}
167
+ disabled={disabled}
168
+ onChange={handleChange}
288
169
  />
289
-
290
- {showLabel && (
170
+ {optionsRequired && (
291
171
  <div
292
- className={classNames('ff-select-label', {
293
- 'ff-select-label--default': !isInputFocused,
294
- 'ff-select-label--active': isInputFocused || Boolean(option),
295
- 'ff-select-label--error': errorMsg,
172
+ ref={selectArrowRef}
173
+ className={classNames('ff-select-arrow-wrapper', {
174
+ 'ff-select-arrow-wrapper__disabled': disabled,
296
175
  })}
176
+ onClick={handleIconClick}
297
177
  >
298
- {required && (
299
- <Typography
300
- color="var(--error-light)"
301
- className="ff-select-label--required"
302
- >
303
- *
304
- </Typography>
305
- )}
306
- {label}
178
+ <Icon
179
+ name="arrow_down"
180
+ className="ff-select-arrow"
181
+ height={8}
182
+ width={12}
183
+ />
307
184
  </div>
308
185
  )}
309
- {optionsRequired && (
310
- <Icon
311
- name="arrow_up"
312
- height={7}
313
- width={12}
314
- className={classNames('ff-select-arrow', {
315
- 'ff-select-arrow--down': isIconClick,
316
- 'ff-select-arrow--no-label': !showLabel,
317
- })}
318
- color={iconColor}
319
- />
320
- )}
321
- {(!checkEmpty(option) || showOptions) && (
322
- <fieldset
323
- className={classNames('ff-select-fieldset', {
324
- 'ff-select-fieldset--no-label': !showLabel,
325
- 'ff-select-fieldset--default': !isInputFocused,
326
- 'ff-select-fieldset--active': isInputFocused,
327
- 'ff-select-fieldset--option': applyActiveOptionClasses,
328
- 'ff-select-fieldset--error': errorMsg,
329
- 'ff-select-fieldset--border-radius': !borderRadius,
330
- 'ff-select-fieldset--no-border': !showBorder,
186
+ {showLabel && (
187
+ <Typography
188
+ as="span"
189
+ className={classNames('ff-select-label', {
190
+ 'ff-select-label__active': searchedOption,
331
191
  })}
192
+ fontSize={searchedOption && 8}
193
+ required={required}
332
194
  >
333
- {showLabel && (
334
- <legend
335
- className={classNames('ff-select-legend', {
336
- 'ff-select-legend--default': !isInputFocused,
337
- 'ff-select-legend--active': isInputFocused,
338
- 'ff-select-legend--option': applyActiveOptionClasses,
339
- 'ff-select-legend--error': errorMsg,
340
- })}
341
- >
342
- {required && (
343
- <Typography
344
- fontSize={8}
345
- color={'var(--error-light)'}
346
- className="ff-select-legend--required"
347
- >
348
- *
349
- </Typography>
350
- )}
351
- {label}
352
- </legend>
353
- )}
354
- </fieldset>
195
+ {label}
196
+ </Typography>
355
197
  )}
356
198
  </div>
357
-
358
199
  {errorMsg && (
359
200
  <Typography
360
- className="ff-select-wrapper-error-text"
201
+ as="div"
202
+ lineHeight="12px"
361
203
  fontSize={8}
362
- color={'var(--error-light)'}
204
+ color="var(--error_light)"
205
+ className="ff-select-error-msg"
363
206
  >
364
207
  {errorMsg}
365
208
  </Typography>
366
209
  )}
367
210
 
368
211
  {optionsRequired && (
369
- <div ref={DropDownRef}>
370
- {showOptions &&
212
+ <div ref={DropdownRef}>
213
+ {showDropdownOptions &&
371
214
  createPortal(
372
215
  <Dropdown
373
- onSelectBlur={onSelectBlur}
374
- onSelectOptionSelector={onSelectOptionSelector}
216
+ options={selectOptionList}
375
217
  dropdownPosition={dropdownPosition}
376
- options={options}
377
- optionZIndex={optionZIndex}
378
- inputRef={InputRef}
379
218
  labelAccessor={labelAccessor}
219
+ optionZIndex={optionZIndex}
220
+ inputRef={inputRef}
221
+ selectArrowRef={selectArrowRef}
222
+ onSelectBlur={onSelectBlur}
223
+ onSelectOptionSelector={onSelectOptionSelector}
380
224
  />,
381
225
  document.body
382
226
  )}
@@ -0,0 +1,50 @@
1
+ .ff-select-dropdown-wrapper {
2
+ max-height: 160px;
3
+ z-index: 999999;
4
+ position: absolute;
5
+ min-width: 50px;
6
+ border-radius: 4px;
7
+ border: 1px solid var(--ff-select-option-border-color);
8
+ margin-top: 4px;
9
+ box-shadow: 0px 1px 4px 0px var(--ff-select-option-wrapper-box-shadow);
10
+ background-color: var(--ff-select-background-color);
11
+ overflow: hidden auto;
12
+
13
+ &::-webkit-scrollbar {
14
+ width: 4px;
15
+ height: 12px;
16
+ &-thumb {
17
+ background-color: var(--ff-select-scroll-thumb-color);
18
+ border-radius: 4px;
19
+ }
20
+
21
+ &-track {
22
+ background: var(--ff-select-scroll-track-bg);
23
+ border-radius: 4px;
24
+ }
25
+ }
26
+
27
+ .ff-select-dropdown-option {
28
+ box-sizing: border-box;
29
+ cursor: pointer;
30
+ padding: 0px 8px;
31
+ border-radius: 4px;
32
+ min-height: 32px;
33
+ white-space: nowrap;
34
+ text-overflow: ellipsis;
35
+ overflow: hidden;
36
+
37
+ &:hover {
38
+ background-color: var(--ff-select-option-hover-color);
39
+ }
40
+ }
41
+
42
+ .ff-select-no-option {
43
+ box-sizing: border-box;
44
+ padding: 0px 8px;
45
+ overflow: hidden;
46
+ white-space: nowrap;
47
+ text-overflow: ellipsis;
48
+ cursor: not-allowed;
49
+ }
50
+ }
@@ -0,0 +1,94 @@
1
+ import { useContext, useRef, type FC } from 'react';
2
+ import { dropdownDefaultCSSData, DropdownProps } from './types';
3
+ import './Dropdown.scss';
4
+ import { checkEmpty } from '../../../utils/checkEmpty/checkEmpty';
5
+ import Typography from '../../Typography';
6
+ import { ffid } from '../../../utils/ffID/ffid';
7
+ import { ThemeContext } from '../../ThemeProvider/ThemeProvider';
8
+ import classNames from 'classnames';
9
+ import { getLabel } from '../../../utils/getSelectOptionValue/getSelectOptionValue';
10
+ import useClickOutside from '../../../hooks/useClickOutside';
11
+
12
+ const Dropdown: FC<DropdownProps> = ({
13
+ options = [],
14
+ optionZIndex = 10000000,
15
+ dropdownPosition,
16
+ labelAccessor,
17
+ onSelectOptionSelector,
18
+ onSelectBlur,
19
+ inputRef,
20
+ selectArrowRef,
21
+ }) => {
22
+ const themeContext = useContext(ThemeContext);
23
+ const currentTheme = themeContext?.currentTheme;
24
+
25
+ const optionsWrapperRef = useRef<HTMLDivElement>(null);
26
+ useClickOutside(optionsWrapperRef, onSelectBlur, [inputRef, selectArrowRef]);
27
+
28
+ const { positionX, positionY, width, fromBottom } = dropdownPosition;
29
+ const { margin, optionHeight, selectInputHeight, dropDownWrapperPadding } =
30
+ dropdownDefaultCSSData;
31
+
32
+ const updateDropdownPosition = () => {
33
+ let dropdownContainerHeight;
34
+
35
+ if (checkEmpty(options)) {
36
+ dropdownContainerHeight = 32 + 2 * dropDownWrapperPadding;
37
+ } else if (options?.length > 5) {
38
+ dropdownContainerHeight = 160;
39
+ } else {
40
+ dropdownContainerHeight =
41
+ options.length * optionHeight + 2 * dropDownWrapperPadding;
42
+ }
43
+
44
+ if (fromBottom > dropdownContainerHeight + margin) {
45
+ return {
46
+ left: positionX,
47
+ top: positionY,
48
+ width: width,
49
+ zIndex: optionZIndex,
50
+ };
51
+ }
52
+ return {
53
+ zIndex: optionZIndex,
54
+ left: positionX,
55
+ width: width,
56
+ top: positionY - selectInputHeight - dropdownContainerHeight - margin,
57
+ };
58
+ };
59
+
60
+ return (
61
+ <div
62
+ className={classNames('ff-select-dropdown-wrapper', currentTheme)}
63
+ ref={optionsWrapperRef}
64
+ style={updateDropdownPosition()}
65
+ >
66
+ {!checkEmpty(options) ? (
67
+ options.map((option) => (
68
+ <Typography
69
+ key={ffid()}
70
+ as="div"
71
+ lineHeight="30px"
72
+ className={classNames('ff-select-dropdown-option', currentTheme)}
73
+ color="var(--ff-select-text-color)"
74
+ onClick={() => onSelectOptionSelector(option)}
75
+ >
76
+ {getLabel(option, labelAccessor)}
77
+ </Typography>
78
+ ))
79
+ ) : (
80
+ <Typography
81
+ textAlign="center"
82
+ as="div"
83
+ lineHeight="32px"
84
+ color="var(--ff-select-text-color)"
85
+ className={classNames('ff-select-no-option', currentTheme)}
86
+ >
87
+ No Results found
88
+ </Typography>
89
+ )}
90
+ </div>
91
+ );
92
+ };
93
+
94
+ export default Dropdown;
@@ -0,0 +1,20 @@
1
+ import { DrowdownPosition, Option } from '../types';
2
+
3
+ export interface DropdownProps {
4
+ options: Option[];
5
+ dropdownPosition: DrowdownPosition;
6
+ optionZIndex: number;
7
+ labelAccessor?: string;
8
+ valueAccessor?: string;
9
+ onSelectBlur: () => void;
10
+ onSelectOptionSelector: (option: Option) => void;
11
+ inputRef?: React.RefObject<HTMLInputElement>;
12
+ selectArrowRef?: React.RefObject<HTMLDivElement>;
13
+ }
14
+
15
+ export const dropdownDefaultCSSData = {
16
+ margin: 6,
17
+ optionHeight: 32,
18
+ selectInputHeight: 38,
19
+ dropDownWrapperPadding: 0,
20
+ };