@true-engineering/true-react-common-ui-kit 1.1.0 → 1.2.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@true-engineering/true-react-common-ui-kit",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "True Engineering React UI Kit with theming support",
5
5
  "author": "True Engineering (https://trueengineering.ru)",
6
6
  "keywords": [
@@ -27,21 +27,19 @@ const genLetters = (qnt = 1): string =>
27
27
  .replace(/[^a-z]+/g, '')
28
28
  .substr(0, qnt);
29
29
 
30
- const convertObjectToString = (v?: ObjectValue): string | undefined =>
31
- v !== undefined ? `${v.name}` : undefined;
30
+ const convertObjectToString = (v: ObjectValue): string => v.name;
32
31
 
33
- const convertObjectToId = (v?: ObjectValue): string | undefined =>
34
- v !== undefined ? `${v.name}${v.age}` : undefined;
32
+ const convertObjectToId = (v: ObjectValue): string => `${v.name}${v.age}`;
35
33
 
36
- const convertObjectToReactNode = (v?: ObjectValue): ReactNode | undefined =>
37
- v !== undefined ? (
38
- <span>
39
- <i>{v.name}</i>, {v.age}
40
- </span>
41
- ) : undefined;
34
+ const convertObjectToReactNode = (v: ObjectValue): ReactNode => (
35
+ <span>
36
+ <i>{v.name}</i>, {v.age}
37
+ </span>
38
+ );
39
+
40
+ const convertStringToReactNode = (v: string): ReactNode => <i>{v}</i>;
42
41
 
43
- const convertStringToReactNode = (v?: string): ReactNode | undefined =>
44
- v !== undefined ? <i>{v}</i> : undefined;
42
+ const isOptionDisabled = (option: string) => option.startsWith('Опция');
45
43
 
46
44
  const stringOptions = [
47
45
  'Опция 1',
@@ -76,6 +74,7 @@ interface ISelectWithCustomProps<T> extends ISelectProps<T> {
76
74
  shouldUsePopper?: boolean;
77
75
  shouldRenderInBody?: boolean;
78
76
  shouldHideOnScroll?: boolean;
77
+ shouldUseCustomIsDisabledFunction?: boolean;
79
78
  canBeFlipped?: boolean;
80
79
  scrollParent?: 'document' | 'auto';
81
80
  }
@@ -87,6 +86,7 @@ function SelectWithCustomProps<T>({
87
86
  shouldUsePopper,
88
87
  shouldRenderInBody,
89
88
  shouldHideOnScroll,
89
+ shouldUseCustomIsDisabledFunction,
90
90
  canBeFlipped,
91
91
  scrollParent,
92
92
  ...rest
@@ -165,6 +165,9 @@ function SelectWithCustomProps<T>({
165
165
  optionsMode={optionsMode}
166
166
  onType={async () => setDynamicOptions(await getOptions())}
167
167
  onOpen={handleOpen}
168
+ isOptionDisabled={
169
+ shouldUseCustomIsDisabledFunction ? isOptionDisabled : undefined
170
+ }
168
171
  dropdownOptions={{
169
172
  shouldUsePopper,
170
173
  shouldRenderInBody,
@@ -225,6 +228,7 @@ Default.args = {
225
228
  shouldUsePopper: false,
226
229
  shouldRenderInBody: false,
227
230
  shouldHideOnScroll: false,
231
+ shouldUseCustomIsDisabledFunction: false,
228
232
  canBeFlipped: false,
229
233
  scrollParent: 'document',
230
234
  };
@@ -1,5 +1,8 @@
1
- import React, {
1
+ import {
2
2
  ReactNode,
3
+ FocusEvent,
4
+ KeyboardEvent,
5
+ MouseEvent,
3
6
  useCallback,
4
7
  useEffect,
5
8
  useMemo,
@@ -11,8 +14,7 @@ import clsx from 'clsx';
11
14
  import { merge } from 'lodash';
12
15
  import { debounce } from 'ts-debounce';
13
16
  import { Portal } from 'react-overlays';
14
-
15
- import { SelectList, isOptionDisabled } from './SelectList';
17
+ import { SelectList } from './SelectList';
16
18
  import { IInputProps, Input } from '../Input';
17
19
  import { IIconType, Icon } from '../Icon';
18
20
  import {
@@ -27,8 +29,8 @@ import {
27
29
  defaultConvertFunction,
28
30
  defaultCompareFunction,
29
31
  getActiveValueIndex,
32
+ defaultIsOptionDisabled,
30
33
  } from './helpers';
31
-
32
34
  import { SelectStyles, styles } from './Select.styles';
33
35
 
34
36
  export interface ISelectProps<Value>
@@ -36,23 +38,21 @@ export interface ISelectProps<Value>
36
38
  tweakStyles?: SelectStyles;
37
39
  defaultOptionLabel?: string;
38
40
  noMatchesLabel?: string;
39
- loadingLabel?: React.ReactNode;
41
+ loadingLabel?: ReactNode;
40
42
  optionsMode?: 'search' | 'dynamic' | 'normal';
41
- onType?: (value: string) => Promise<void>;
42
43
  debounceTime?: number;
43
44
  minSymbolsCountToOpenList?: number;
44
45
  dropdownOptions?: IDropdownWithPopperOptions;
45
46
  dropdownIcon?: IIconType;
46
- onOpen?: () => void;
47
-
48
- optionsFilter?: (options: Value[], query: string) => Value[];
49
47
  options: Value[];
50
48
  value: Value | undefined;
51
49
  shouldScrollToList?: boolean;
50
+ isOptionDisabled?(option: Value): boolean;
52
51
  onChange(value: Value | undefined): void; // подумать как возвращать индекс
52
+ onType?(value: string): Promise<void>;
53
+ optionsFilter?(options: Value[], query: string): Value[];
54
+ onOpen?(): void;
53
55
  compareValuesOnChange?(v1: Value | undefined, v2: Value | undefined): boolean;
54
- // возможно делать какую-то индексацию опций
55
-
56
56
  // Для избежания проблем юзайте useCallback на эти функции
57
57
  // или выносите их из компонента (чтобы не было сайдэфектов от перерендеринга их)
58
58
  convertValueToString?(value: Value): string | undefined;
@@ -63,19 +63,9 @@ export interface ISelectProps<Value>
63
63
  export function Select<Value>({
64
64
  options,
65
65
  value,
66
- onChange,
67
- compareValuesOnChange = defaultCompareFunction,
68
- convertValueToString = defaultConvertFunction,
69
- convertValueToId,
70
- convertValueToReactNode,
71
66
  defaultOptionLabel,
72
- onFocus,
73
- onBlur,
74
- onType,
75
- onOpen,
76
67
  debounceTime = 400,
77
68
  optionsMode = 'normal',
78
- optionsFilter,
79
69
  noMatchesLabel,
80
70
  loadingLabel,
81
71
  tweakStyles,
@@ -85,6 +75,17 @@ export function Select<Value>({
85
75
  minSymbolsCountToOpenList = 0,
86
76
  dropdownIcon = 'chevron-down',
87
77
  shouldScrollToList = true,
78
+ onChange,
79
+ onFocus,
80
+ onBlur,
81
+ onType,
82
+ onOpen,
83
+ isOptionDisabled = defaultIsOptionDisabled,
84
+ compareValuesOnChange = defaultCompareFunction,
85
+ convertValueToString = defaultConvertFunction,
86
+ convertValueToId,
87
+ convertValueToReactNode,
88
+ optionsFilter,
88
89
  ...inputProps
89
90
  }: ISelectProps<Value>): JSX.Element {
90
91
  const { classes, componentStyles } = useTheme('Select', styles, tweakStyles);
@@ -144,7 +145,7 @@ export function Select<Value>({
144
145
  setIsListOpen(true);
145
146
  };
146
147
 
147
- const handleFocus = (event: React.FocusEvent<HTMLInputElement>) => {
148
+ const handleFocus = (event: FocusEvent<HTMLInputElement>) => {
148
149
  if (onFocus !== undefined) {
149
150
  onFocus(event);
150
151
  }
@@ -155,7 +156,7 @@ export function Select<Value>({
155
156
  handleListOpen();
156
157
  };
157
158
 
158
- const handleBlur = (event: React.FocusEvent<HTMLInputElement>) => {
159
+ const handleBlur = (event: FocusEvent<HTMLInputElement>) => {
159
160
  if (onBlur !== undefined) {
160
161
  onBlur(event);
161
162
  }
@@ -222,7 +223,7 @@ export function Select<Value>({
222
223
  setSearchValue(v);
223
224
  };
224
225
 
225
- const handleKeyDown = (event: React.KeyboardEvent) => {
226
+ const handleKeyDown = (event: KeyboardEvent) => {
226
227
  if (!isListOpen) {
227
228
  return;
228
229
  }
@@ -387,7 +388,7 @@ export function Select<Value>({
387
388
  {...inputProps}
388
389
  />
389
390
  <div
390
- onMouseDown={(event: React.MouseEvent) => {
391
+ onMouseDown={(event: MouseEvent) => {
391
392
  event.preventDefault();
392
393
  }}
393
394
  onClick={onArrowClick}
@@ -415,10 +416,6 @@ export function Select<Value>({
415
416
  {isOpen && (
416
417
  <SelectList
417
418
  options={filteredOptions}
418
- convertValueToString={convertValueToString}
419
- convertValueToReactNode={convertValueToReactNode}
420
- convertValueToId={convertValueToId}
421
- onOptionClick={handleOptionClick}
422
419
  defaultOptionLabel={
423
420
  hasDefaultOption && shouldShowDefaultOption
424
421
  ? defaultOptionLabel
@@ -437,6 +434,11 @@ export function Select<Value>({
437
434
  !shouldUsePopper &&
438
435
  !shouldHideOnScroll
439
436
  }
437
+ isOptionDisabled={isOptionDisabled}
438
+ convertValueToString={convertValueToString}
439
+ convertValueToReactNode={convertValueToReactNode}
440
+ convertValueToId={convertValueToId}
441
+ onOptionClick={handleOptionClick}
440
442
  />
441
443
  )}
442
444
  </div>
@@ -1,10 +1,9 @@
1
- import React, { ReactNode, useMemo } from 'react';
1
+ import { ReactNode, useMemo } from 'react';
2
2
  import clsx from 'clsx';
3
3
  import { ScrollIntoViewIfNeeded } from '../../ScrollIntoViewIfNeeded';
4
4
  import { useTheme } from '../../../hooks';
5
5
  import { ICommonProps } from '../../../types';
6
6
  import { isNotEmpty } from '../../../helpers';
7
-
8
7
  import { SelectListStyles, styles } from './SelectList.styles';
9
8
 
10
9
  export interface ISelectListProps<Value> extends ICommonProps {
@@ -14,41 +13,35 @@ export interface ISelectListProps<Value> extends ICommonProps {
14
13
  activeValue?: Value;
15
14
  noMatchesLabel?: string;
16
15
  isLoading?: boolean;
17
- loadingLabel?: React.ReactNode;
16
+ loadingLabel?: ReactNode;
18
17
  defaultOptionLabel?: string;
19
- onOptionClick: (index: number) => void;
20
18
  testId?: string;
21
19
  shouldScrollToList?: boolean;
22
- convertValueToString: (value: Value) => string | undefined;
23
- convertValueToReactNode?: (value: Value) => ReactNode;
24
- convertValueToId?: (value: Value) => string | undefined;
25
- }
26
-
27
- export function isOptionDisabled<Value>(option: Value): boolean {
28
- return (
29
- typeof option === 'object' &&
30
- option !== null &&
31
- ((option as { isDisabled?: boolean })?.isDisabled ?? false)
32
- );
20
+ onOptionClick(index: number): void;
21
+ isOptionDisabled(value: Value): boolean;
22
+ convertValueToString(value: Value): string | undefined;
23
+ convertValueToReactNode?(value: Value): ReactNode;
24
+ convertValueToId?(value: Value): string | undefined;
33
25
  }
34
26
 
35
27
  const DEFAULT_OPTION_INDEX = -1;
36
28
 
37
29
  export function SelectList<Value>({
38
30
  options,
39
- onOptionClick,
40
31
  focusedIndex,
41
32
  activeValue,
42
33
  defaultOptionLabel,
43
34
  noMatchesLabel = 'Совпадений не найдено',
44
35
  isLoading,
45
36
  loadingLabel = 'Загрузка...',
46
- convertValueToString,
47
- convertValueToReactNode,
48
- convertValueToId = convertValueToString,
49
37
  tweakStyles,
50
38
  testId,
51
39
  shouldScrollToList = true,
40
+ isOptionDisabled,
41
+ onOptionClick,
42
+ convertValueToString,
43
+ convertValueToReactNode,
44
+ convertValueToId = convertValueToString,
52
45
  }: ISelectListProps<Value>): JSX.Element {
53
46
  const { classes } = useTheme('SelectList', styles, tweakStyles);
54
47
  const activeValueId = isNotEmpty(activeValue)
@@ -1,5 +1,10 @@
1
1
  import { isNotEmpty } from '../../helpers';
2
2
 
3
+ export const defaultIsOptionDisabled = <Value>(option: Value): boolean =>
4
+ typeof option === 'object' &&
5
+ option !== null &&
6
+ ((option as { isDisabled?: boolean })?.isDisabled ?? false);
7
+
3
8
  export const defaultConvertFunction = (v: unknown) =>
4
9
  v === undefined ? undefined : String(v);
5
10