@inceptionbg/iui 2.0.8 → 2.0.11

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 (143) hide show
  1. package/dist/icons/index.d.ts +2 -2
  2. package/dist/icons/index.js +1 -1
  3. package/dist/index.d.ts +305 -265
  4. package/dist/index.js +1 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/iui.css +1 -1
  7. package/idea/GridTable/GridTable.tsx +119 -0
  8. package/idea/GridTable/gridTable.scss +42 -0
  9. package/{src/components → idea}/Table/Components/Print/CustomTablePrint.tsx +2 -2
  10. package/{src/components → idea}/Table/Components/Print/TablePrint.tsx +2 -2
  11. package/{src/components → idea}/Table/Components/SetTableFilter.tsx +1 -1
  12. package/{src/components → idea}/Table/Components/TableOptions.tsx +4 -4
  13. package/idea/{Table2 → Table}/Table.tsx +151 -281
  14. package/idea/Table/hooks/useDefaultTemplate.ts +20 -0
  15. package/{src/components → idea}/Table/hooks/useTableKeyboard.ts +1 -2
  16. package/idea/Table/hooks/useTableSelect.ts +11 -0
  17. package/package.json +1 -1
  18. package/src/assets/icons/index.ts +1 -1
  19. package/src/assets/icons/light/faClipboardCheck.ts +15 -0
  20. package/src/assets/icons/light/faHouse.ts +15 -15
  21. package/src/assets/icons/light/faIdBadge.ts +15 -15
  22. package/src/assets/icons/light/faPen.ts +15 -0
  23. package/src/components/Button/IconButton.tsx +3 -1
  24. package/src/components/Dialog/Dialog.tsx +57 -123
  25. package/src/components/Dialog/components/DialogFooter.tsx +92 -0
  26. package/src/components/Dialog/hooks/useDialogKeyboard.ts +6 -5
  27. package/src/components/Header/Components/UserMenu.tsx +2 -4
  28. package/src/components/Header/Header.tsx +1 -1
  29. package/src/components/Inputs/DateInput/DateInput.tsx +107 -102
  30. package/src/components/Inputs/DateInput/components/DatePartInput.tsx +7 -3
  31. package/src/components/Inputs/InputWrapper.tsx +6 -1
  32. package/src/components/Inputs/PasswordInput.tsx +2 -1
  33. package/src/components/Inputs/SearchInput.tsx +9 -4
  34. package/src/components/Inputs/Select2/Select.tsx +64 -30
  35. package/src/components/Inputs/Select2/select.scss +13 -14
  36. package/src/components/Inputs/Selects/components/SelectWrapper.tsx +4 -2
  37. package/src/components/Inputs/Selects/utils/selectStyles.ts +9 -12
  38. package/src/components/Menu/Menu.tsx +10 -2
  39. package/src/components/Menu/MenuItem.tsx +11 -10
  40. package/src/components/Menu/hooks/useMenuPosition.tsx +49 -14
  41. package/src/components/Pullover/Pullover.tsx +138 -59
  42. package/src/components/Table/Table.tsx +78 -342
  43. package/src/components/Table/components/edit/TableEditRow.tsx +69 -0
  44. package/src/components/Table/components/filters/FilterItem.tsx +15 -0
  45. package/src/components/Table/components/filters/TableFilters.tsx +125 -0
  46. package/src/components/Table/components/footer/TableFooter.tsx +128 -0
  47. package/src/components/Table/components/header/TableHeader.tsx +42 -0
  48. package/src/components/Table/components/header/TableHeaderRow.tsx +47 -0
  49. package/src/components/Table/components/items/TableItemActions.tsx +66 -0
  50. package/src/components/Table/components/select/TableSelect.tsx +49 -0
  51. package/src/components/Table/components/sort/TableSort.tsx +52 -0
  52. package/src/components/Table/contexts/TableContext.tsx +123 -0
  53. package/src/components/Table/hooks/localHooks/useLocalTableColumns.tsx +73 -0
  54. package/src/components/Table/hooks/localHooks/useLocalTableData.tsx +78 -0
  55. package/src/components/Table/hooks/localHooks/useLocalTableKeyboard.ts +173 -0
  56. package/src/components/Table/hooks/localHooks/useLocalTablePagination.ts +12 -0
  57. package/src/components/Table/hooks/useTableEdit.tsx +111 -0
  58. package/src/components/Table/hooks/useTableFilterFields.tsx +150 -0
  59. package/src/components/Table/hooks/useTablePagination.ts +16 -0
  60. package/src/components/Table/hooks/useTableSearch.ts +29 -0
  61. package/src/components/Table/hooks/useTableSort.ts +8 -0
  62. package/src/components/Tooltip/Tooltip.tsx +1 -1
  63. package/src/components/Wrappers/PageLayout.tsx +9 -12
  64. package/src/hooks/useGetFocusableElements.ts +42 -0
  65. package/src/hooks/useLocalPopoverControl.ts +32 -0
  66. package/src/hooks/usePopupControl.ts +17 -0
  67. package/src/index.ts +56 -39
  68. package/src/styles/common/_typography.scss +1 -1
  69. package/src/styles/components/_accordions.scss +1 -1
  70. package/src/styles/components/_badge.scss +4 -3
  71. package/src/styles/components/_card.scss +1 -1
  72. package/src/styles/components/_dialog.scss +8 -8
  73. package/src/styles/components/_input.scss +1 -1
  74. package/src/styles/components/_inputCheckbox.scss +1 -1
  75. package/src/styles/components/_inputDateTime.scss +2 -2
  76. package/src/styles/components/_inputRadio.scss +1 -1
  77. package/src/styles/components/_inputSelect.scss +6 -4
  78. package/src/styles/components/_menu-v2.scss +1 -1
  79. package/src/styles/components/_menu.scss +23 -15
  80. package/src/styles/components/_pullover.scss +74 -18
  81. package/src/styles/components/_table.scss +151 -142
  82. package/src/styles/components/_widget.scss +1 -1
  83. package/src/styles/variables/_bp.scss +1 -0
  84. package/src/styles/variables/_variables.scss +4 -2
  85. package/src/types/IHeader.ts +13 -7
  86. package/src/types/IKeyboard.ts +2 -1
  87. package/src/types/IMenu.ts +1 -0
  88. package/src/types/IPopup.ts +17 -0
  89. package/src/types/ISelect.ts +1 -0
  90. package/src/types/ITable.ts +87 -80
  91. package/src/utils/fileUtils.ts +3 -3
  92. package/src/utils/i18n/i18nIUICyrilic.ts +4 -0
  93. package/src/utils/i18n/i18nIUILatin.ts +3 -1
  94. package/src/utils/i18n/i18nIUIMe.ts +4 -0
  95. package/src/utils/{ObjectUtils.ts → objectUtils.ts} +8 -8
  96. package/src/utils/popupUtils.ts +82 -0
  97. package/src/utils/{TableUtils.ts → tableUtils.ts} +5 -5
  98. package/src/utils/{Toasts.ts → toasts.ts} +6 -6
  99. package/src/utils/{UrlUtils.ts → urlUtils.ts} +4 -4
  100. package/idea/Table2/Components/Columns/ColumnsList.tsx +0 -56
  101. package/idea/Table2/Components/Columns/SetColumnsList.tsx +0 -107
  102. package/idea/Table2/Components/Edit/ItemActionsMenu.tsx +0 -87
  103. package/idea/Table2/Components/Edit/ItemEditOptionsButtons.tsx +0 -32
  104. package/idea/Table2/Components/Edit/TableEditRow.tsx +0 -56
  105. package/idea/Table2/Components/FilterItem.tsx +0 -20
  106. package/idea/Table2/Components/Header/TableHeader.tsx +0 -35
  107. package/idea/Table2/Components/Header/TableHeaderRow.tsx +0 -37
  108. package/idea/Table2/Components/Print/CustomTablePrint.tsx +0 -119
  109. package/idea/Table2/Components/Print/TablePrint.tsx +0 -208
  110. package/idea/Table2/Components/SetSortList.tsx +0 -33
  111. package/idea/Table2/Components/SetTableFilter.tsx +0 -90
  112. package/idea/Table2/Components/TableFooter.tsx +0 -107
  113. package/idea/Table2/Components/TableOptions.tsx +0 -211
  114. package/idea/Table2/Components/Templates/TemplateCreate.tsx +0 -75
  115. package/idea/Table2/Components/Templates/TemplateCreateDefault.tsx +0 -45
  116. package/idea/Table2/Components/Templates/TemplateList.tsx +0 -167
  117. package/idea/Table2/Components/Templates/repo/TemplateRepo.ts +0 -51
  118. package/idea/Table2/_table.scss +0 -300
  119. package/idea/Table2/hooks/useDefaultTemplate.ts +0 -22
  120. package/idea/Table2/hooks/useTableKeyboard.ts +0 -115
  121. package/src/assets/icons/light/faPenField.ts +0 -15
  122. package/src/assets/icons/solid/faMagnifyingGlass.ts +0 -15
  123. package/src/components/Dialog/DeleteItemDialog.tsx +0 -52
  124. package/src/components/Dialog/hooks/useDialogObserver.ts +0 -21
  125. /package/{src/components → idea}/Table/Components/Columns/ColumnsList.tsx +0 -0
  126. /package/{src/components → idea}/Table/Components/Columns/SetColumnsList.tsx +0 -0
  127. /package/{src/components → idea}/Table/Components/Edit/ItemActionsMenu.tsx +0 -0
  128. /package/{src/components → idea}/Table/Components/Edit/ItemEditOptionsButtons.tsx +0 -0
  129. /package/{src/components → idea}/Table/Components/Edit/TableEditRow.tsx +0 -0
  130. /package/{src/components → idea}/Table/Components/FilterItem.tsx +0 -0
  131. /package/{src/components → idea}/Table/Components/Header/TableHeader.tsx +0 -0
  132. /package/{src/components → idea}/Table/Components/Header/TableHeaderRow.tsx +0 -0
  133. /package/{src/components → idea}/Table/Components/SetSortList.tsx +0 -0
  134. /package/{src/components → idea}/Table/Components/TableFooter.tsx +0 -0
  135. /package/{src/components → idea}/Table/Components/Templates/TemplateCreate.tsx +0 -0
  136. /package/{src/components → idea}/Table/Components/Templates/TemplateCreateDefault.tsx +0 -0
  137. /package/{src/components → idea}/Table/Components/Templates/TemplateList.tsx +0 -0
  138. /package/{src/components → idea}/Table/Components/Templates/repo/TemplateRepo.ts +0 -0
  139. /package/src/utils/{DateUtils.ts → dateUtils.ts} +0 -0
  140. /package/src/utils/{LocalStorageHelper.ts → localStorageHelper.ts} +0 -0
  141. /package/src/utils/{NumberUtils.ts → numberUtils.ts} +0 -0
  142. /package/src/utils/{RootDir.ts → rootDir.ts} +0 -0
  143. /package/src/utils/{StringUtils.ts → stringUtils.ts} +0 -0
@@ -7,7 +7,7 @@ import { DatePartInput } from './components/DatePartInput';
7
7
  import { faCalendarPlus } from '../../../assets/icons/light/faCalendarPlus';
8
8
  import dayjs from 'dayjs';
9
9
  import { IMenuPlacement } from '../../../types/IMenu';
10
- import { formatDateYMD } from '../../../utils/DateUtils';
10
+ import { formatDateYMD } from '../../../utils/dateUtils';
11
11
  import { useTranslation } from 'react-i18next';
12
12
 
13
13
  export interface IDateInputProps {
@@ -21,6 +21,7 @@ export interface IDateInputProps {
21
21
  helperText?: string;
22
22
  errorText?: string;
23
23
  isClearable?: boolean;
24
+ onClear?: () => void;
24
25
  className?: string;
25
26
  calendarPlacement?: IMenuPlacement;
26
27
  }
@@ -36,6 +37,7 @@ export const DateInput: FC<IDateInputProps> = ({
36
37
  helperText,
37
38
  errorText,
38
39
  isClearable = true,
40
+ onClear,
39
41
  className,
40
42
  calendarPlacement,
41
43
  }) => {
@@ -69,110 +71,113 @@ export const DateInput: FC<IDateInputProps> = ({
69
71
  }
70
72
  }, [date]);
71
73
 
72
- console.log(i18n.language);
73
74
  return (
74
- <InputWrapper
75
- label={label}
76
- focus={isCalendarOpen}
77
- required={required}
78
- className={className}
79
- disabled={disabled}
80
- onClearInput={
81
- isClearable && (day || month || year) && !disabled
82
- ? () => {
83
- setDay('');
84
- setMonth('');
85
- setYear('');
86
- setDate('');
75
+ <Menu
76
+ isOpen={isCalendarOpen}
77
+ onClose={() => setIsCalendarOpen(false)}
78
+ placement={calendarPlacement}
79
+ renderButton={ref => (
80
+ <div ref={ref} className="full-width">
81
+ <InputWrapper
82
+ label={label}
83
+ focus={isCalendarOpen}
84
+ required={required}
85
+ className={className}
86
+ disabled={disabled}
87
+ onClearInput={
88
+ isClearable && (day || month || year) && !disabled
89
+ ? () => {
90
+ setDay('');
91
+ setMonth('');
92
+ setYear('');
93
+ setDate('');
94
+ onClear?.();
95
+ }
96
+ : undefined
87
97
  }
88
- : undefined
89
- }
90
- helperText={helperText}
91
- error={error}
92
- errorText={errorText}
93
- >
94
- <div className="date-input">
95
- <Menu
96
- isOpen={isCalendarOpen}
97
- onClose={() => setIsCalendarOpen(false)}
98
- placement={calendarPlacement ?? 'bottom-left'}
99
- renderButton={ref => (
100
- <div
101
- ref={ref}
102
- className="calendar-btn"
103
- onClick={() => !disabled && setIsCalendarOpen(!isCalendarOpen)}
104
- >
105
- <FontAwesomeIcon icon={faCalendarPlus} className="icon" />
98
+ helperText={helperText}
99
+ error={error}
100
+ errorText={errorText}
101
+ >
102
+ <div className="date-input">
103
+ <div
104
+ className="calendar-btn"
105
+ onClick={() => !disabled && setIsCalendarOpen(!isCalendarOpen)}
106
+ >
107
+ <FontAwesomeIcon icon={faCalendarPlus} className="icon" />
108
+ </div>
109
+ <div
110
+ ref={inputsRef}
111
+ className="inputs"
112
+ onClick={() => dayRef.current?.focus()}
113
+ >
114
+ <DatePartInput
115
+ ref={dayRef}
116
+ value={day}
117
+ setValue={setDay}
118
+ setDate={setDate}
119
+ values={{ day, month, year }}
120
+ required={required || !!month || !!year}
121
+ disabled={disabled}
122
+ autoFocus={autoFocus}
123
+ max={maxDay}
124
+ part="day"
125
+ nextInput={monthRef.current}
126
+ />
127
+ <span>.</span>
128
+ <DatePartInput
129
+ ref={monthRef}
130
+ value={month}
131
+ setValue={setMonth}
132
+ setDate={setDate}
133
+ values={{ day, month, year }}
134
+ required={required || !!day || !!year}
135
+ disabled={disabled}
136
+ max={12}
137
+ part="month"
138
+ previousInput={dayRef.current}
139
+ nextInput={yearRef.current}
140
+ />
141
+ <span>.</span>
142
+ <DatePartInput
143
+ ref={yearRef}
144
+ value={year}
145
+ setValue={setYear}
146
+ setDate={setDate}
147
+ values={{ day, month, year }}
148
+ required={required || !!day || !!month}
149
+ disabled={disabled}
150
+ min={1500}
151
+ max={2500}
152
+ part="year"
153
+ previousInput={monthRef.current}
154
+ />
155
+ </div>
106
156
  </div>
107
- )}
108
- >
109
- <Calendar
110
- value={
111
- date && dayjs(date, 'YYYY-MM-DD', true).isValid()
112
- ? new Date(date)
113
- : new Date()
114
- }
115
- onChange={e => {
116
- const newDate = formatDateYMD(e as Date);
117
- setDate(newDate);
118
- setIsCalendarOpen(false);
119
- }}
120
- locale={
121
- i18n.language === 'sr_RS_Latn'
122
- ? 'sr-Latn-RS'
123
- : i18n.language === 'sr_RS_Cyrl'
124
- ? 'sr-RS'
125
- : i18n.language
126
- }
127
- formatShortWeekday={(locale, date) =>
128
- new Intl.DateTimeFormat(locale, { weekday: 'short' }).format(date)
129
- }
130
- />
131
- </Menu>
132
- <div ref={inputsRef} className="inputs" onClick={() => dayRef.current?.focus()}>
133
- <DatePartInput
134
- ref={dayRef}
135
- value={day}
136
- setValue={setDay}
137
- setDate={setDate}
138
- values={{ day, month, year }}
139
- required={required || !!month || !!year}
140
- disabled={disabled}
141
- autoFocus={autoFocus}
142
- max={maxDay}
143
- part="day"
144
- nextInput={monthRef.current}
145
- />
146
- <span>.</span>
147
- <DatePartInput
148
- ref={monthRef}
149
- value={month}
150
- setValue={setMonth}
151
- setDate={setDate}
152
- values={{ day, month, year }}
153
- required={required || !!day || !!year}
154
- disabled={disabled}
155
- max={12}
156
- part="month"
157
- previousInput={dayRef.current}
158
- nextInput={yearRef.current}
159
- />
160
- <span>.</span>
161
- <DatePartInput
162
- ref={yearRef}
163
- value={year}
164
- setValue={setYear}
165
- setDate={setDate}
166
- values={{ day, month, year }}
167
- required={required || !!day || !!month}
168
- disabled={disabled}
169
- min={1500}
170
- max={2500}
171
- part="year"
172
- previousInput={monthRef.current}
173
- />
157
+ </InputWrapper>
174
158
  </div>
175
- </div>
176
- </InputWrapper>
159
+ )}
160
+ >
161
+ <Calendar
162
+ value={
163
+ date && dayjs(date, 'YYYY-MM-DD', true).isValid() ? new Date(date) : new Date()
164
+ }
165
+ onChange={e => {
166
+ const newDate = formatDateYMD(e as Date);
167
+ setDate(newDate);
168
+ setIsCalendarOpen(false);
169
+ }}
170
+ locale={
171
+ i18n.language === 'sr_RS_Latn'
172
+ ? 'sr-Latn-RS'
173
+ : i18n.language === 'sr_RS_Cyrl'
174
+ ? 'sr-RS'
175
+ : i18n.language
176
+ }
177
+ formatShortWeekday={(locale, date) =>
178
+ new Intl.DateTimeFormat(locale, { weekday: 'short' }).format(date)
179
+ }
180
+ />
181
+ </Menu>
177
182
  );
178
183
  };
@@ -19,15 +19,15 @@ interface Props {
19
19
 
20
20
  const options = {
21
21
  day: {
22
- placeholder: 'dd',
22
+ placeholder: '31',
23
23
  regex: `^[0-9]{2}`,
24
24
  },
25
25
  month: {
26
- placeholder: 'mm',
26
+ placeholder: '12',
27
27
  regex: `^[0-9]{2}`,
28
28
  },
29
29
  year: {
30
- placeholder: 'yyyy',
30
+ placeholder: '2000',
31
31
  regex: `^[0-9]{4}`,
32
32
  },
33
33
  };
@@ -115,15 +115,19 @@ export const DatePartInput: FC<Props> = ({
115
115
  onKeyDown={e => {
116
116
  if (e.key === 'ArrowLeft') {
117
117
  e.preventDefault();
118
+ e.stopPropagation();
118
119
  previousInput?.select();
119
120
  } else if (e.key === 'ArrowRight') {
120
121
  e.preventDefault();
122
+ e.stopPropagation();
121
123
  nextInput?.select();
122
124
  } else if (e.key === 'ArrowUp') {
123
125
  e.preventDefault();
126
+ e.stopPropagation();
124
127
  +value < max && setValueHandler(`${value ? +value + 1 : min}`);
125
128
  } else if (e.key === 'ArrowDown') {
126
129
  e.preventDefault();
130
+ e.stopPropagation();
127
131
  +value > min && setValueHandler(`${value ? +value - 1 : min}`);
128
132
  }
129
133
  }}
@@ -1,7 +1,7 @@
1
1
  import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
2
2
  import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
3
3
  import clsx from 'clsx';
4
- import { FC, ReactNode } from 'react';
4
+ import { FC, ReactNode, Ref } from 'react';
5
5
  import { faCircleXmark } from '../../assets/icons';
6
6
 
7
7
  interface Props {
@@ -22,6 +22,7 @@ interface Props {
22
22
  error?: boolean;
23
23
  focus?: boolean;
24
24
  heightAuto?: boolean;
25
+ inputFieldRef?: Ref<HTMLDivElement>;
25
26
  children: ReactNode;
26
27
  }
27
28
  export const InputWrapper: FC<Props> = ({
@@ -38,6 +39,7 @@ export const InputWrapper: FC<Props> = ({
38
39
  error,
39
40
  focus,
40
41
  heightAuto,
42
+ inputFieldRef,
41
43
  children,
42
44
  }) => {
43
45
  const withEndSection = !!(endText || endButton || onClearInput);
@@ -53,6 +55,7 @@ export const InputWrapper: FC<Props> = ({
53
55
  >
54
56
  {label && <p className={clsx('input-label', { required })}>{label}</p>}
55
57
  <div
58
+ ref={inputFieldRef}
56
59
  className={clsx('iui-input-wrapper-field', {
57
60
  'with-end-section': withEndSection,
58
61
  'height-auto': heightAuto,
@@ -74,6 +77,8 @@ export const InputWrapper: FC<Props> = ({
74
77
  className={clsx('icon', { disabled: endButton.disabled })}
75
78
  icon={endButton.icon}
76
79
  onClick={!endButton.disabled ? endButton.onClick : undefined}
80
+ role="button"
81
+ type="button"
77
82
  />
78
83
  )}
79
84
  </div>
@@ -1,4 +1,4 @@
1
- import { FC, InputHTMLAttributes, useState } from 'react';
1
+ import { FC, InputHTMLAttributes, Ref, useState } from 'react';
2
2
  import { faEye } from '../../assets/icons/light/faEye';
3
3
  import { faEyeSlash } from '../../assets/icons/light/faEyeSlash';
4
4
  import { TextInput } from './TextInput';
@@ -16,6 +16,7 @@ export interface IPasswordInputProps {
16
16
  error?: boolean;
17
17
  inputProps?: InputHTMLAttributes<HTMLInputElement>;
18
18
  newPassword?: boolean;
19
+ ref?: Ref<HTMLInputElement>;
19
20
  }
20
21
 
21
22
  export const PasswordInput: FC<IPasswordInputProps> = props => {
@@ -1,4 +1,4 @@
1
- import { FC, useState } from 'react';
1
+ import { FC, Ref, useState } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import { TextInput } from './TextInput';
4
4
  import { faMagnifyingGlass } from '../../assets/icons';
@@ -6,15 +6,16 @@ import { faMagnifyingGlass } from '../../assets/icons';
6
6
  interface IProps {
7
7
  label?: string;
8
8
  onSearch: (searchText: string) => void;
9
- onClear?: () => void;
10
9
  className?: string;
10
+ ref?: Ref<HTMLInputElement>;
11
11
  }
12
- export const SearchInput: FC<IProps> = ({ label, onSearch, onClear, className }) => {
12
+ export const SearchInput: FC<IProps> = ({ label, onSearch, className, ref }) => {
13
13
  const [text, setText] = useState('');
14
14
  const { t } = useTranslation();
15
15
 
16
16
  return (
17
17
  <TextInput
18
+ ref={ref}
18
19
  className={className}
19
20
  inputProps={{
20
21
  'aria-label': 'search',
@@ -23,6 +24,10 @@ export const SearchInput: FC<IProps> = ({ label, onSearch, onClear, className })
23
24
  e.stopPropagation();
24
25
  e.preventDefault();
25
26
  onSearch(e.target.value);
27
+ } else if (e.key === 'Escape') {
28
+ !!text && e.stopPropagation();
29
+ setText('');
30
+ onSearch('');
26
31
  }
27
32
  },
28
33
  }}
@@ -30,7 +35,7 @@ export const SearchInput: FC<IProps> = ({ label, onSearch, onClear, className })
30
35
  placeholder={t('Search')}
31
36
  value={text}
32
37
  setValue={setText}
33
- onClear={onClear}
38
+ onClear={() => onSearch('')}
34
39
  endButton={{
35
40
  icon: faMagnifyingGlass,
36
41
  onClick: () => onSearch(text),
@@ -3,6 +3,10 @@ import './select.scss';
3
3
  import { useState, useRef, useEffect, ChangeEvent, FC, UIEvent } from 'react';
4
4
  import clsx from 'clsx';
5
5
  import { InputWrapper } from '../InputWrapper';
6
+ import { createPortal } from 'react-dom';
7
+ import { rootDir } from '../../../utils/rootDir';
8
+ import { useMenuPosition } from '../../Menu/hooks/useMenuPosition';
9
+ import { IMenuPlacement } from '../../../types/IMenu';
6
10
 
7
11
  export interface OptionType {
8
12
  label: string;
@@ -26,18 +30,24 @@ interface CustomSelectProps {
26
30
  setValue: (option: OptionType | null) => void;
27
31
  required?: boolean;
28
32
  disabled?: boolean;
29
- // isMulti?: boolean;
33
+ isMulti?: boolean;
30
34
  isAsync?: boolean;
31
35
  isCreatable?: boolean;
32
36
  options?: OptionType[];
37
+ placeholder?: string;
33
38
  loadOptions?: (
34
39
  inputValue: string,
35
40
  loadedOptions: OptionType[],
36
41
  params: { page: number }
37
42
  ) => Promise<LoadOptionsResponse>;
38
43
  onCreateOption?: (inputValue: string) => Promise<OptionType>;
39
- placeholder?: string;
40
44
  isClearable: boolean;
45
+ onClearInput?: () => void;
46
+ helperText?: string;
47
+ errorText?: string;
48
+ error?: boolean;
49
+ menuPlacement?: IMenuPlacement;
50
+ className?: string;
41
51
  // minWidth?: number;
42
52
  }
43
53
 
@@ -50,12 +60,18 @@ export const Select: FC<CustomSelectProps> = ({
50
60
  disabled,
51
61
  options = [],
52
62
  loadOptions,
63
+ placeholder = 'Select...',
64
+ isMulti,
53
65
  isAsync = false,
54
66
  isCreatable = false,
55
67
  isClearable = true,
56
- // isMulti,
68
+ onClearInput,
69
+ helperText,
70
+ errorText,
71
+ error,
72
+ menuPlacement = 'bottom-left',
73
+ className,
57
74
  // minWidth,
58
- placeholder = 'Select...',
59
75
  }) => {
60
76
  const [inputValue, setInputValue] = useState<string | null>(null);
61
77
  const [dropdownVisible, setDropdownVisible] = useState(false);
@@ -64,8 +80,17 @@ export const Select: FC<CustomSelectProps> = ({
64
80
  const [index, setIndex] = useState<number | null>(null);
65
81
  const [hasMore, setHasMore] = useState(true);
66
82
 
83
+ const containerRef = useRef<HTMLDivElement>(null);
67
84
  const dropdownRef = useRef<HTMLDivElement>(null);
68
85
 
86
+ const menuStyle = useMenuPosition({
87
+ isOpen: dropdownVisible,
88
+ placement: menuPlacement,
89
+ containerRef,
90
+ menuRef: dropdownRef,
91
+ withMinWidth: true,
92
+ });
93
+
69
94
  useEffect(() => {
70
95
  if (!isAsync) {
71
96
  const filtered = inputValue
@@ -94,7 +119,7 @@ export const Select: FC<CustomSelectProps> = ({
94
119
  setInputValue(null);
95
120
  setTimeout(() => {
96
121
  setIndex(null);
97
- setDropdownVisible(false);
122
+ // setDropdownVisible(false);
98
123
  });
99
124
  };
100
125
 
@@ -103,7 +128,7 @@ export const Select: FC<CustomSelectProps> = ({
103
128
  setInputValue(
104
129
  e.target.defaultValue === value?.label
105
130
  ? // @ts-ignore
106
- e.nativeEvent?.data ?? ''
131
+ (e.nativeEvent?.data ?? '')
107
132
  : inputValue
108
133
  );
109
134
  // setFilteredOptions([]);
@@ -157,10 +182,11 @@ export const Select: FC<CustomSelectProps> = ({
157
182
  }
158
183
  : undefined
159
184
  }
160
- // helperText={helperText}
161
- // errorText={errorText}
162
- // error={error}
163
- // className={className}
185
+ helperText={helperText}
186
+ errorText={errorText}
187
+ error={error}
188
+ inputFieldRef={containerRef}
189
+ className={className}
164
190
  >
165
191
  <input
166
192
  value={inputValue ?? value?.label ?? ''}
@@ -189,7 +215,7 @@ export const Select: FC<CustomSelectProps> = ({
189
215
  } else if (e.key === 'Enter' && index !== null) {
190
216
  e.preventDefault();
191
217
  e.currentTarget.blur();
192
- handleOptionClick(options[index]);
218
+ handleOptionClick(filteredOptions[index]);
193
219
  } else if (e.key === 'Escape') {
194
220
  e.preventDefault();
195
221
  e.currentTarget.blur();
@@ -198,27 +224,35 @@ export const Select: FC<CustomSelectProps> = ({
198
224
  />
199
225
  </InputWrapper>
200
226
 
201
- {dropdownVisible && (
202
- <div ref={dropdownRef} className="dropdown" onScroll={handleScroll}>
203
- {filteredOptions.map((option, i) => (
227
+ {dropdownVisible
228
+ ? createPortal(
204
229
  <div
205
- key={i}
206
- className={clsx('option', { hover: index === i })}
207
- onMouseDown={() => handleOptionClick(option)}
230
+ ref={dropdownRef}
231
+ className="select-dropdown"
232
+ onScroll={handleScroll}
233
+ style={menuStyle}
208
234
  >
209
- {option.label}
210
- </div>
211
- ))}
212
- {!filteredOptions.length && <div className="option">No options</div>}
213
- {isCreatable &&
214
- inputValue &&
215
- !filteredOptions.some(opt => opt.label === inputValue) && (
216
- <div className="option createOption" onClick={handleCreate}>
217
- {`Create ${inputValue}`}
218
- </div>
219
- )}
220
- </div>
221
- )}
235
+ {filteredOptions.map((option, i) => (
236
+ <div
237
+ key={i}
238
+ className={clsx('option', { hover: index === i })}
239
+ onMouseDown={() => handleOptionClick(option)}
240
+ >
241
+ {option.label}
242
+ </div>
243
+ ))}
244
+ {!filteredOptions.length && <div className="option">No options</div>}
245
+ {isCreatable &&
246
+ inputValue &&
247
+ !filteredOptions.some(opt => opt.label === inputValue) && (
248
+ <div className="option createOption" onClick={handleCreate}>
249
+ {`Create ${inputValue}`}
250
+ </div>
251
+ )}
252
+ </div>,
253
+ rootDir
254
+ )
255
+ : null}
222
256
  </div>
223
257
  );
224
258
  };
@@ -12,20 +12,20 @@
12
12
  font-size: 14px;
13
13
  }
14
14
  }
15
+ }
15
16
 
16
- .dropdown {
17
- position: absolute;
18
- z-index: 1000;
19
- width: 100%;
20
- max-height: 200px;
21
- overflow-y: auto;
22
- background: #fff;
23
- border: var(--border);
24
- border-radius: 8px;
25
- // border-radius: 0 0 8px 8px;
26
- margin-top: 2px;
27
- }
28
-
17
+ .select-dropdown {
18
+ position: absolute;
19
+ z-index: 1000;
20
+ // width: 100%;
21
+ min-width: 200px;
22
+ max-height: 200px;
23
+ overflow-y: auto;
24
+ background: #fff;
25
+ border: var(--border);
26
+ border-radius: 8px;
27
+ // border-radius: 0 0 8px 8px;
28
+ margin-top: 2px;
29
29
  .option {
30
30
  padding: 8px 12px;
31
31
  cursor: pointer;
@@ -35,7 +35,6 @@
35
35
  background-color: #f5f5f5;
36
36
  }
37
37
  }
38
-
39
38
  .createOption {
40
39
  font-weight: bold;
41
40
  color: #007bff;
@@ -11,6 +11,7 @@ import type {
11
11
  BasicSelectProps,
12
12
  CreatableSelectProps,
13
13
  } from '../../../../types/ISelect';
14
+ import clsx from 'clsx';
14
15
 
15
16
  export type ISelectProps = BasicSelectProps | AsyncSelectProps | CreatableSelectProps;
16
17
 
@@ -42,6 +43,7 @@ export const SelectWrapper = forwardRef<any, ISelectProps>((props, forwardedRef)
42
43
  autoFocus,
43
44
  closeMenuOnSelect,
44
45
  noOptionsMessage,
46
+ size,
45
47
  } = props;
46
48
 
47
49
  const commonProps = {
@@ -49,7 +51,7 @@ export const SelectWrapper = forwardRef<any, ISelectProps>((props, forwardedRef)
49
51
  components: CustomSelectComponents,
50
52
  onChange,
51
53
  placeholder,
52
- styles: createSelectStyles({ menuWidth }),
54
+ styles: createSelectStyles({ menuWidth, fontSize: size === 's' ? 12 : 16, size }),
53
55
  isDisabled: disabled,
54
56
  isOptionDisabled: (option: any) => option.disabled,
55
57
  isClearable,
@@ -103,7 +105,7 @@ export const SelectWrapper = forwardRef<any, ISelectProps>((props, forwardedRef)
103
105
  helperText={helperText}
104
106
  error={error}
105
107
  errorText={errorText}
106
- className={className}
108
+ className={clsx('select-wrapper', size, className)}
107
109
  minWidth={minWidth}
108
110
  heightAuto
109
111
  >