@inceptionbg/iui 2.0.8 → 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 (138) 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 +286 -259
  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 +59 -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/Header.tsx +1 -1
  28. package/src/components/Inputs/DateInput/DateInput.tsx +108 -102
  29. package/src/components/Inputs/DateInput/components/DatePartInput.tsx +7 -3
  30. package/src/components/Inputs/InputWrapper.tsx +6 -1
  31. package/src/components/Inputs/SearchInput.tsx +9 -4
  32. package/src/components/Inputs/Select2/Select.tsx +65 -30
  33. package/src/components/Inputs/Select2/select.scss +13 -14
  34. package/src/components/Inputs/Selects/components/SelectWrapper.tsx +4 -2
  35. package/src/components/Inputs/Selects/utils/selectStyles.ts +9 -12
  36. package/src/components/Menu/Menu.tsx +10 -2
  37. package/src/components/Menu/MenuItem.tsx +11 -10
  38. package/src/components/Menu/hooks/useMenuPosition.tsx +23 -6
  39. package/src/components/Pullover/Pullover.tsx +122 -59
  40. package/src/components/Table/Table.tsx +78 -342
  41. package/src/components/Table/components/edit/TableEditRow.tsx +69 -0
  42. package/src/components/Table/components/filters/FilterItem.tsx +15 -0
  43. package/src/components/Table/components/filters/TableFilters.tsx +125 -0
  44. package/src/components/Table/components/footer/TableFooter.tsx +128 -0
  45. package/src/components/Table/components/header/TableHeader.tsx +42 -0
  46. package/src/components/Table/components/header/TableHeaderRow.tsx +47 -0
  47. package/src/components/Table/components/items/TableItemActions.tsx +66 -0
  48. package/src/components/Table/components/select/TableSelect.tsx +49 -0
  49. package/src/components/Table/components/sort/TableSort.tsx +52 -0
  50. package/src/components/Table/contexts/TableContext.tsx +123 -0
  51. package/src/components/Table/hooks/localHooks/useLocalTableColumns.tsx +73 -0
  52. package/src/components/Table/hooks/localHooks/useLocalTableData.tsx +78 -0
  53. package/src/components/Table/hooks/localHooks/useLocalTableKeyboard.ts +173 -0
  54. package/src/components/Table/hooks/localHooks/useLocalTablePagination.ts +12 -0
  55. package/src/components/Table/hooks/useTableEdit.tsx +111 -0
  56. package/src/components/Table/hooks/useTableFilterFields.tsx +150 -0
  57. package/src/components/Table/hooks/useTablePagination.ts +16 -0
  58. package/src/components/Table/hooks/useTableSearch.ts +29 -0
  59. package/src/components/Table/hooks/useTableSort.ts +8 -0
  60. package/src/components/Tooltip/Tooltip.tsx +1 -1
  61. package/src/components/Wrappers/PageLayout.tsx +9 -12
  62. package/src/hooks/useGetFocusableElements.ts +42 -0
  63. package/src/hooks/useLocalPopoverControl.ts +38 -0
  64. package/src/hooks/usePopupControl.ts +13 -0
  65. package/src/index.ts +53 -39
  66. package/src/styles/components/_accordions.scss +1 -1
  67. package/src/styles/components/_badge.scss +4 -3
  68. package/src/styles/components/_card.scss +1 -1
  69. package/src/styles/components/_dialog.scss +8 -8
  70. package/src/styles/components/_input.scss +1 -1
  71. package/src/styles/components/_inputCheckbox.scss +1 -1
  72. package/src/styles/components/_inputDateTime.scss +2 -2
  73. package/src/styles/components/_inputRadio.scss +1 -1
  74. package/src/styles/components/_inputSelect.scss +6 -4
  75. package/src/styles/components/_menu-v2.scss +1 -1
  76. package/src/styles/components/_menu.scss +23 -15
  77. package/src/styles/components/_pullover.scss +74 -18
  78. package/src/styles/components/_table.scss +151 -142
  79. package/src/styles/components/_widget.scss +1 -1
  80. package/src/styles/variables/_bp.scss +1 -0
  81. package/src/styles/variables/_variables.scss +4 -2
  82. package/src/types/IKeyboard.ts +2 -1
  83. package/src/types/IMenu.ts +1 -0
  84. package/src/types/ISelect.ts +1 -0
  85. package/src/types/ITable.ts +87 -80
  86. package/src/utils/fileUtils.ts +3 -3
  87. package/src/utils/i18n/i18nIUICyrilic.ts +4 -0
  88. package/src/utils/i18n/i18nIUILatin.ts +3 -1
  89. package/src/utils/i18n/i18nIUIMe.ts +4 -0
  90. package/src/utils/{ObjectUtils.ts → objectUtils.ts} +8 -8
  91. package/src/utils/popupUtils.ts +82 -0
  92. package/src/utils/{TableUtils.ts → tableUtils.ts} +5 -5
  93. package/src/utils/{Toasts.ts → toasts.ts} +6 -6
  94. package/src/utils/{UrlUtils.ts → urlUtils.ts} +4 -4
  95. package/idea/Table2/Components/Columns/ColumnsList.tsx +0 -56
  96. package/idea/Table2/Components/Columns/SetColumnsList.tsx +0 -107
  97. package/idea/Table2/Components/Edit/ItemActionsMenu.tsx +0 -87
  98. package/idea/Table2/Components/Edit/ItemEditOptionsButtons.tsx +0 -32
  99. package/idea/Table2/Components/Edit/TableEditRow.tsx +0 -56
  100. package/idea/Table2/Components/FilterItem.tsx +0 -20
  101. package/idea/Table2/Components/Header/TableHeader.tsx +0 -35
  102. package/idea/Table2/Components/Header/TableHeaderRow.tsx +0 -37
  103. package/idea/Table2/Components/Print/CustomTablePrint.tsx +0 -119
  104. package/idea/Table2/Components/Print/TablePrint.tsx +0 -208
  105. package/idea/Table2/Components/SetSortList.tsx +0 -33
  106. package/idea/Table2/Components/SetTableFilter.tsx +0 -90
  107. package/idea/Table2/Components/TableFooter.tsx +0 -107
  108. package/idea/Table2/Components/TableOptions.tsx +0 -211
  109. package/idea/Table2/Components/Templates/TemplateCreate.tsx +0 -75
  110. package/idea/Table2/Components/Templates/TemplateCreateDefault.tsx +0 -45
  111. package/idea/Table2/Components/Templates/TemplateList.tsx +0 -167
  112. package/idea/Table2/Components/Templates/repo/TemplateRepo.ts +0 -51
  113. package/idea/Table2/_table.scss +0 -300
  114. package/idea/Table2/hooks/useDefaultTemplate.ts +0 -22
  115. package/idea/Table2/hooks/useTableKeyboard.ts +0 -115
  116. package/src/assets/icons/light/faPenField.ts +0 -15
  117. package/src/assets/icons/solid/faMagnifyingGlass.ts +0 -15
  118. package/src/components/Dialog/DeleteItemDialog.tsx +0 -52
  119. package/src/components/Dialog/hooks/useDialogObserver.ts +0 -21
  120. /package/{src/components → idea}/Table/Components/Columns/ColumnsList.tsx +0 -0
  121. /package/{src/components → idea}/Table/Components/Columns/SetColumnsList.tsx +0 -0
  122. /package/{src/components → idea}/Table/Components/Edit/ItemActionsMenu.tsx +0 -0
  123. /package/{src/components → idea}/Table/Components/Edit/ItemEditOptionsButtons.tsx +0 -0
  124. /package/{src/components → idea}/Table/Components/Edit/TableEditRow.tsx +0 -0
  125. /package/{src/components → idea}/Table/Components/FilterItem.tsx +0 -0
  126. /package/{src/components → idea}/Table/Components/Header/TableHeader.tsx +0 -0
  127. /package/{src/components → idea}/Table/Components/Header/TableHeaderRow.tsx +0 -0
  128. /package/{src/components → idea}/Table/Components/SetSortList.tsx +0 -0
  129. /package/{src/components → idea}/Table/Components/TableFooter.tsx +0 -0
  130. /package/{src/components → idea}/Table/Components/Templates/TemplateCreate.tsx +0 -0
  131. /package/{src/components → idea}/Table/Components/Templates/TemplateCreateDefault.tsx +0 -0
  132. /package/{src/components → idea}/Table/Components/Templates/TemplateList.tsx +0 -0
  133. /package/{src/components → idea}/Table/Components/Templates/repo/TemplateRepo.ts +0 -0
  134. /package/src/utils/{DateUtils.ts → dateUtils.ts} +0 -0
  135. /package/src/utils/{LocalStorageHelper.ts → localStorageHelper.ts} +0 -0
  136. /package/src/utils/{NumberUtils.ts → numberUtils.ts} +0 -0
  137. /package/src/utils/{RootDir.ts → rootDir.ts} +0 -0
  138. /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,114 @@ 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 ?? '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
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
+ // 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>
106
157
  </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
- />
158
+ </InputWrapper>
174
159
  </div>
175
- </div>
176
- </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>
177
183
  );
178
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;