@inceptionbg/iui 2.0.7 → 2.0.10

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 (148) hide show
  1. package/dist/NoAccessPage-DBq5IzIf.js +2 -0
  2. package/dist/{NoAccessPage-BozT_Suz.js.map → NoAccessPage-DBq5IzIf.js.map} +1 -1
  3. package/dist/NotFoundPage-DM-I96ar.js +2 -0
  4. package/dist/{NotFoundPage-WWiekDef.js.map → NotFoundPage-DM-I96ar.js.map} +1 -1
  5. package/dist/icons/index.d.ts +2 -2
  6. package/dist/icons/index.js +1 -1
  7. package/dist/index.d.ts +286 -259
  8. package/dist/index.js +1 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/iui.css +1 -1
  11. package/idea/GridTable/GridTable.tsx +119 -0
  12. package/idea/GridTable/gridTable.scss +42 -0
  13. package/{src/components → idea}/Table/Components/Print/CustomTablePrint.tsx +2 -2
  14. package/{src/components → idea}/Table/Components/Print/TablePrint.tsx +2 -2
  15. package/{src/components → idea}/Table/Components/SetTableFilter.tsx +1 -1
  16. package/{src/components → idea}/Table/Components/TableOptions.tsx +4 -4
  17. package/idea/{Table2 → Table}/Table.tsx +151 -281
  18. package/idea/Table/hooks/useDefaultTemplate.ts +20 -0
  19. package/{src/components → idea}/Table/hooks/useTableKeyboard.ts +1 -2
  20. package/idea/Table/hooks/useTableSelect.ts +11 -0
  21. package/package.json +3 -2
  22. package/src/assets/icons/index.ts +1 -1
  23. package/src/assets/icons/light/faClipboardCheck.ts +15 -0
  24. package/src/assets/icons/light/faHouse.ts +15 -15
  25. package/src/assets/icons/light/faIdBadge.ts +15 -15
  26. package/src/assets/icons/light/faPen.ts +15 -0
  27. package/src/components/Button/IconButton.tsx +3 -1
  28. package/src/components/Dialog/Dialog.tsx +60 -124
  29. package/src/components/Dialog/components/DialogFooter.tsx +92 -0
  30. package/src/components/Dialog/hooks/useDialogKeyboard.ts +6 -5
  31. package/src/components/Header/Components/ModuleSelect.tsx +1 -1
  32. package/src/components/Header/Header.tsx +1 -1
  33. package/src/components/Inputs/DateInput/DateInput.tsx +108 -101
  34. package/src/components/Inputs/DateInput/components/DatePartInput.tsx +7 -3
  35. package/src/components/Inputs/InputWrapper.tsx +6 -1
  36. package/src/components/Inputs/SearchInput.tsx +9 -4
  37. package/src/components/Inputs/Select2/Select.tsx +65 -30
  38. package/src/components/Inputs/Select2/select.scss +13 -14
  39. package/src/components/Inputs/Selects/components/SelectWrapper.tsx +4 -2
  40. package/src/components/Inputs/Selects/utils/selectStyles.ts +9 -12
  41. package/src/components/Menu/Menu.tsx +10 -2
  42. package/src/components/Menu/MenuItem.tsx +11 -10
  43. package/src/components/Menu/hooks/useMenuPosition.tsx +23 -6
  44. package/src/components/Pullover/Pullover.tsx +122 -59
  45. package/src/components/Table/Table.tsx +78 -342
  46. package/src/components/Table/components/edit/TableEditRow.tsx +69 -0
  47. package/src/components/Table/components/filters/FilterItem.tsx +15 -0
  48. package/src/components/Table/components/filters/TableFilters.tsx +125 -0
  49. package/src/components/Table/components/footer/TableFooter.tsx +128 -0
  50. package/src/components/Table/components/header/TableHeader.tsx +42 -0
  51. package/src/components/Table/components/header/TableHeaderRow.tsx +47 -0
  52. package/src/components/Table/components/items/TableItemActions.tsx +66 -0
  53. package/src/components/Table/components/select/TableSelect.tsx +49 -0
  54. package/src/components/Table/components/sort/TableSort.tsx +52 -0
  55. package/src/components/Table/contexts/TableContext.tsx +123 -0
  56. package/src/components/Table/hooks/localHooks/useLocalTableColumns.tsx +73 -0
  57. package/src/components/Table/hooks/localHooks/useLocalTableData.tsx +78 -0
  58. package/src/components/Table/hooks/localHooks/useLocalTableKeyboard.ts +173 -0
  59. package/src/components/Table/hooks/localHooks/useLocalTablePagination.ts +12 -0
  60. package/src/components/Table/hooks/useTableEdit.tsx +111 -0
  61. package/src/components/Table/hooks/useTableFilterFields.tsx +150 -0
  62. package/src/components/Table/hooks/useTablePagination.ts +16 -0
  63. package/src/components/Table/hooks/useTableSearch.ts +29 -0
  64. package/src/components/Table/hooks/useTableSort.ts +8 -0
  65. package/src/components/Tooltip/Tooltip.tsx +1 -1
  66. package/src/components/Wrappers/PageLayout.tsx +13 -18
  67. package/src/hooks/useGetFocusableElements.ts +42 -0
  68. package/src/hooks/useLocalPopoverControl.ts +38 -0
  69. package/src/hooks/usePopupControl.ts +13 -0
  70. package/src/index.ts +53 -39
  71. package/src/styles/common/_typography.scss +3 -0
  72. package/src/styles/common/helpers/_size.scss +1 -1
  73. package/src/styles/components/_accordions.scss +1 -1
  74. package/src/styles/components/_badge.scss +4 -3
  75. package/src/styles/components/_card.scss +1 -1
  76. package/src/styles/components/_dialog.scss +15 -13
  77. package/src/styles/components/_input.scss +1 -1
  78. package/src/styles/components/_inputCheckbox.scss +1 -1
  79. package/src/styles/components/_inputDateTime.scss +2 -2
  80. package/src/styles/components/_inputRadio.scss +1 -1
  81. package/src/styles/components/_inputSelect.scss +6 -4
  82. package/src/styles/components/_menu-v2.scss +1 -1
  83. package/src/styles/components/_menu.scss +23 -15
  84. package/src/styles/components/_page.scss +3 -2
  85. package/src/styles/components/_pullover.scss +74 -18
  86. package/src/styles/components/_table.scss +151 -142
  87. package/src/styles/components/_widget.scss +1 -1
  88. package/src/styles/variables/_bp.scss +1 -0
  89. package/src/styles/variables/_variables.scss +4 -2
  90. package/src/types/IKeyboard.ts +2 -1
  91. package/src/types/IMenu.ts +1 -0
  92. package/src/types/ISelect.ts +1 -0
  93. package/src/types/ITable.ts +87 -80
  94. package/src/utils/fileUtils.ts +7 -6
  95. package/src/utils/i18n/i18nIUICyrilic.ts +4 -0
  96. package/src/utils/i18n/i18nIUILatin.ts +3 -1
  97. package/src/utils/i18n/i18nIUIMe.ts +4 -0
  98. package/src/utils/{ObjectUtils.ts → objectUtils.ts} +8 -8
  99. package/src/utils/popupUtils.ts +82 -0
  100. package/src/utils/{TableUtils.ts → tableUtils.ts} +5 -5
  101. package/src/utils/{Toasts.ts → toasts.ts} +6 -6
  102. package/src/utils/{UrlUtils.ts → urlUtils.ts} +4 -4
  103. package/dist/NoAccessPage-BozT_Suz.js +0 -2
  104. package/dist/NotFoundPage-WWiekDef.js +0 -2
  105. package/idea/Table2/Components/Columns/ColumnsList.tsx +0 -56
  106. package/idea/Table2/Components/Columns/SetColumnsList.tsx +0 -107
  107. package/idea/Table2/Components/Edit/ItemActionsMenu.tsx +0 -87
  108. package/idea/Table2/Components/Edit/ItemEditOptionsButtons.tsx +0 -32
  109. package/idea/Table2/Components/Edit/TableEditRow.tsx +0 -56
  110. package/idea/Table2/Components/FilterItem.tsx +0 -20
  111. package/idea/Table2/Components/Header/TableHeader.tsx +0 -35
  112. package/idea/Table2/Components/Header/TableHeaderRow.tsx +0 -37
  113. package/idea/Table2/Components/Print/CustomTablePrint.tsx +0 -119
  114. package/idea/Table2/Components/Print/TablePrint.tsx +0 -208
  115. package/idea/Table2/Components/SetSortList.tsx +0 -33
  116. package/idea/Table2/Components/SetTableFilter.tsx +0 -90
  117. package/idea/Table2/Components/TableFooter.tsx +0 -107
  118. package/idea/Table2/Components/TableOptions.tsx +0 -211
  119. package/idea/Table2/Components/Templates/TemplateCreate.tsx +0 -75
  120. package/idea/Table2/Components/Templates/TemplateCreateDefault.tsx +0 -45
  121. package/idea/Table2/Components/Templates/TemplateList.tsx +0 -167
  122. package/idea/Table2/Components/Templates/repo/TemplateRepo.ts +0 -51
  123. package/idea/Table2/_table.scss +0 -300
  124. package/idea/Table2/hooks/useDefaultTemplate.ts +0 -22
  125. package/idea/Table2/hooks/useTableKeyboard.ts +0 -115
  126. package/src/assets/icons/light/faPenField.ts +0 -15
  127. package/src/assets/icons/solid/faMagnifyingGlass.ts +0 -15
  128. package/src/components/Dialog/DeleteItemDialog.tsx +0 -52
  129. package/src/components/Dialog/hooks/useDialogObserver.ts +0 -21
  130. /package/{src/components → idea}/Table/Components/Columns/ColumnsList.tsx +0 -0
  131. /package/{src/components → idea}/Table/Components/Columns/SetColumnsList.tsx +0 -0
  132. /package/{src/components → idea}/Table/Components/Edit/ItemActionsMenu.tsx +0 -0
  133. /package/{src/components → idea}/Table/Components/Edit/ItemEditOptionsButtons.tsx +0 -0
  134. /package/{src/components → idea}/Table/Components/Edit/TableEditRow.tsx +0 -0
  135. /package/{src/components → idea}/Table/Components/FilterItem.tsx +0 -0
  136. /package/{src/components → idea}/Table/Components/Header/TableHeader.tsx +0 -0
  137. /package/{src/components → idea}/Table/Components/Header/TableHeaderRow.tsx +0 -0
  138. /package/{src/components → idea}/Table/Components/SetSortList.tsx +0 -0
  139. /package/{src/components → idea}/Table/Components/TableFooter.tsx +0 -0
  140. /package/{src/components → idea}/Table/Components/Templates/TemplateCreate.tsx +0 -0
  141. /package/{src/components → idea}/Table/Components/Templates/TemplateCreateDefault.tsx +0 -0
  142. /package/{src/components → idea}/Table/Components/Templates/TemplateList.tsx +0 -0
  143. /package/{src/components → idea}/Table/Components/Templates/repo/TemplateRepo.ts +0 -0
  144. /package/src/utils/{DateUtils.ts → dateUtils.ts} +0 -0
  145. /package/src/utils/{LocalStorageHelper.ts → localStorageHelper.ts} +0 -0
  146. /package/src/utils/{NumberUtils.ts → numberUtils.ts} +0 -0
  147. /package/src/utils/{RootDir.ts → rootDir.ts} +0 -0
  148. /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
  }) => {
@@ -70,108 +72,113 @@ export const DateInput: FC<IDateInputProps> = ({
70
72
  }, [date]);
71
73
 
72
74
  return (
73
- <InputWrapper
74
- label={label}
75
- focus={isCalendarOpen}
76
- required={required}
77
- className={className}
78
- disabled={disabled}
79
- onClearInput={
80
- isClearable && (day || month || year) && !disabled
81
- ? () => {
82
- setDay('');
83
- setMonth('');
84
- setYear('');
85
- setDate('');
75
+ <Menu
76
+ isOpen={isCalendarOpen}
77
+ onClose={() => setIsCalendarOpen(false)}
78
+ placement={calendarPlacement ?? 'bottom-left'}
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
86
97
  }
87
- : undefined
88
- }
89
- helperText={helperText}
90
- error={error}
91
- errorText={errorText}
92
- >
93
- <div className="date-input">
94
- <Menu
95
- isOpen={isCalendarOpen}
96
- onClose={() => setIsCalendarOpen(false)}
97
- placement={calendarPlacement ?? 'bottom-left'}
98
- renderButton={ref => (
99
- <div
100
- ref={ref}
101
- className="calendar-btn"
102
- onClick={() => !disabled && setIsCalendarOpen(!isCalendarOpen)}
103
- >
104
- <FontAwesomeIcon icon={faCalendarPlus} className="icon" />
98
+ helperText={helperText}
99
+ error={error}
100
+ errorText={errorText}
101
+ >
102
+ <div className="date-input">
103
+ <div
104
+ // ref={ref}
105
+ className="calendar-btn"
106
+ onClick={() => !disabled && setIsCalendarOpen(!isCalendarOpen)}
107
+ >
108
+ <FontAwesomeIcon icon={faCalendarPlus} className="icon" />
109
+ </div>
110
+ <div
111
+ ref={inputsRef}
112
+ className="inputs"
113
+ onClick={() => dayRef.current?.focus()}
114
+ >
115
+ <DatePartInput
116
+ ref={dayRef}
117
+ value={day}
118
+ setValue={setDay}
119
+ setDate={setDate}
120
+ values={{ day, month, year }}
121
+ required={required || !!month || !!year}
122
+ disabled={disabled}
123
+ autoFocus={autoFocus}
124
+ max={maxDay}
125
+ part="day"
126
+ nextInput={monthRef.current}
127
+ />
128
+ <span>.</span>
129
+ <DatePartInput
130
+ ref={monthRef}
131
+ value={month}
132
+ setValue={setMonth}
133
+ setDate={setDate}
134
+ values={{ day, month, year }}
135
+ required={required || !!day || !!year}
136
+ disabled={disabled}
137
+ max={12}
138
+ part="month"
139
+ previousInput={dayRef.current}
140
+ nextInput={yearRef.current}
141
+ />
142
+ <span>.</span>
143
+ <DatePartInput
144
+ ref={yearRef}
145
+ value={year}
146
+ setValue={setYear}
147
+ setDate={setDate}
148
+ values={{ day, month, year }}
149
+ required={required || !!day || !!month}
150
+ disabled={disabled}
151
+ min={1500}
152
+ max={2500}
153
+ part="year"
154
+ previousInput={monthRef.current}
155
+ />
156
+ </div>
105
157
  </div>
106
- )}
107
- >
108
- <Calendar
109
- value={
110
- date && dayjs(date, 'YYYY-MM-DD', true).isValid()
111
- ? new Date(date)
112
- : new Date()
113
- }
114
- onChange={e => {
115
- const newDate = formatDateYMD(e as Date);
116
- setDate(newDate);
117
- setIsCalendarOpen(false);
118
- }}
119
- locale={
120
- i18n.language === 'sr_RS_Latn'
121
- ? 'sr-Latn-RS'
122
- : i18n.language === 'sr_RS_Cyrl'
123
- ? 'sr-RS'
124
- : i18n.language
125
- }
126
- formatShortWeekday={(locale, date) =>
127
- new Intl.DateTimeFormat(locale, { weekday: 'short' }).format(date)
128
- }
129
- />
130
- </Menu>
131
- <div ref={inputsRef} className="inputs" onClick={() => dayRef.current?.focus()}>
132
- <DatePartInput
133
- ref={dayRef}
134
- value={day}
135
- setValue={setDay}
136
- setDate={setDate}
137
- values={{ day, month, year }}
138
- required={required || !!month || !!year}
139
- disabled={disabled}
140
- autoFocus={autoFocus}
141
- max={maxDay}
142
- part="day"
143
- nextInput={monthRef.current}
144
- />
145
- <span>.</span>
146
- <DatePartInput
147
- ref={monthRef}
148
- value={month}
149
- setValue={setMonth}
150
- setDate={setDate}
151
- values={{ day, month, year }}
152
- required={required || !!day || !!year}
153
- disabled={disabled}
154
- max={12}
155
- part="month"
156
- previousInput={dayRef.current}
157
- nextInput={yearRef.current}
158
- />
159
- <span>.</span>
160
- <DatePartInput
161
- ref={yearRef}
162
- value={year}
163
- setValue={setYear}
164
- setDate={setDate}
165
- values={{ day, month, year }}
166
- required={required || !!day || !!month}
167
- disabled={disabled}
168
- min={1500}
169
- max={2500}
170
- part="year"
171
- previousInput={monthRef.current}
172
- />
158
+ </InputWrapper>
173
159
  </div>
174
- </div>
175
- </InputWrapper>
160
+ )}
161
+ >
162
+ <Calendar
163
+ value={
164
+ date && dayjs(date, 'YYYY-MM-DD', true).isValid() ? new Date(date) : new Date()
165
+ }
166
+ onChange={e => {
167
+ const newDate = formatDateYMD(e as Date);
168
+ setDate(newDate);
169
+ setIsCalendarOpen(false);
170
+ }}
171
+ locale={
172
+ i18n.language === 'sr_RS_Latn'
173
+ ? 'sr-Latn-RS'
174
+ : i18n.language === 'sr_RS_Cyrl'
175
+ ? 'sr-RS'
176
+ : i18n.language
177
+ }
178
+ formatShortWeekday={(locale, date) =>
179
+ new Intl.DateTimeFormat(locale, { weekday: 'short' }).format(date)
180
+ }
181
+ />
182
+ </Menu>
176
183
  );
177
184
  };
@@ -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, 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([]);
@@ -133,6 +158,7 @@ export const Select: FC<CustomSelectProps> = ({
133
158
  }
134
159
  };
135
160
 
161
+ console.log(menuStyle);
136
162
  return (
137
163
  <div
138
164
  className="customSelect"
@@ -157,10 +183,11 @@ export const Select: FC<CustomSelectProps> = ({
157
183
  }
158
184
  : undefined
159
185
  }
160
- // helperText={helperText}
161
- // errorText={errorText}
162
- // error={error}
163
- // className={className}
186
+ helperText={helperText}
187
+ errorText={errorText}
188
+ error={error}
189
+ inputFieldRef={containerRef}
190
+ className={className}
164
191
  >
165
192
  <input
166
193
  value={inputValue ?? value?.label ?? ''}
@@ -189,7 +216,7 @@ export const Select: FC<CustomSelectProps> = ({
189
216
  } else if (e.key === 'Enter' && index !== null) {
190
217
  e.preventDefault();
191
218
  e.currentTarget.blur();
192
- handleOptionClick(options[index]);
219
+ handleOptionClick(filteredOptions[index]);
193
220
  } else if (e.key === 'Escape') {
194
221
  e.preventDefault();
195
222
  e.currentTarget.blur();
@@ -198,27 +225,35 @@ export const Select: FC<CustomSelectProps> = ({
198
225
  />
199
226
  </InputWrapper>
200
227
 
201
- {dropdownVisible && (
202
- <div ref={dropdownRef} className="dropdown" onScroll={handleScroll}>
203
- {filteredOptions.map((option, i) => (
228
+ {dropdownVisible
229
+ ? createPortal(
204
230
  <div
205
- key={i}
206
- className={clsx('option', { hover: index === i })}
207
- onMouseDown={() => handleOptionClick(option)}
231
+ ref={dropdownRef}
232
+ className="select-dropdown"
233
+ onScroll={handleScroll}
234
+ style={menuStyle}
208
235
  >
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
- )}
236
+ {filteredOptions.map((option, i) => (
237
+ <div
238
+ key={i}
239
+ className={clsx('option', { hover: index === i })}
240
+ onMouseDown={() => handleOptionClick(option)}
241
+ >
242
+ {option.label}
243
+ </div>
244
+ ))}
245
+ {!filteredOptions.length && <div className="option">No options</div>}
246
+ {isCreatable &&
247
+ inputValue &&
248
+ !filteredOptions.some(opt => opt.label === inputValue) && (
249
+ <div className="option createOption" onClick={handleCreate}>
250
+ {`Create ${inputValue}`}
251
+ </div>
252
+ )}
253
+ </div>,
254
+ rootDir
255
+ )
256
+ : null}
222
257
  </div>
223
258
  );
224
259
  };
@@ -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
  >
@@ -3,8 +3,10 @@ import { StylesConfig } from 'react-select';
3
3
  export const createSelectStyles = ({
4
4
  fontSize = 16,
5
5
  menuWidth,
6
+ size,
6
7
  }: {
7
8
  fontSize?: number;
9
+ size?: 's' | 'm';
8
10
  menuWidth?: 'fit-content' | 'max-content' | number;
9
11
  }) =>
10
12
  ({
@@ -14,7 +16,7 @@ export const createSelectStyles = ({
14
16
  borderWidth: 0,
15
17
  boxShadow: 'none',
16
18
  width: '100%',
17
- // minHeight: size === 's' ? 12 : 36,
19
+ minHeight: size === 's' ? 12 : 36,
18
20
  }),
19
21
  container: provided => ({
20
22
  ...provided,
@@ -23,9 +25,7 @@ export const createSelectStyles = ({
23
25
  valueContainer: provided => ({
24
26
  ...provided,
25
27
  fontSize,
26
- padding: '6px 0 6px 12px',
27
- // fontSize: /*size === 's' ? 12 : */ 14,
28
- // padding: /*size === 's' ? '0 4px' : */ state.isMulti ? '8px 14px' : '10px 14px',
28
+ padding: size === 's' ? '0 4px 0 8px' : '6px 0 6px 12px',
29
29
  gap: 4,
30
30
  width: '100%',
31
31
  }),
@@ -64,23 +64,20 @@ export const createSelectStyles = ({
64
64
  ...provided,
65
65
  padding: 0,
66
66
  margin: 0,
67
- // height: size === 's' ? 24 : 36,
68
67
  }),
69
68
  option: (provided, state) => ({
70
69
  ...provided,
71
70
  fontSize,
72
- // fontSize: /*size === 's' ? 12 : */ 14,
73
- // padding: size === 's' ? 4 : provided.padding,
71
+ padding: size === 's' ? 4 : provided.padding,
74
72
  backgroundColor: state.isSelected
75
73
  ? 'var(--primary) !important'
76
74
  : state.isFocused
77
- ? '#eee !important'
78
- : 'inherit',
75
+ ? '#eee !important'
76
+ : 'inherit',
79
77
  }),
80
78
  noOptionsMessage: provided => ({
81
79
  ...provided,
82
80
  fontSize,
83
- // fontSize: /*size === 's' ? 12 : */ 14,
84
81
  fontStyle: 'italic',
85
82
  textAlign: 'left',
86
83
  cursor: 'default',
@@ -97,8 +94,8 @@ export const createSelectStyles = ({
97
94
  indicatorSeparator: () => ({ display: 'none' }),
98
95
  dropdownIndicator: (provided, state) => ({
99
96
  ...provided,
100
- // padding: size === 's' ? '4px' : provided.padding,
97
+ padding: size === 's' ? '4px' : provided.padding,
101
98
  transition: 'all .2s ease',
102
99
  transform: state.selectProps.menuIsOpen ? 'rotate(180deg)' : null,
103
100
  }),
104
- } as StylesConfig);
101
+ }) as StylesConfig;