@true-engineering/true-react-common-ui-kit 4.0.0-alpha65 → 4.0.0-alpha67

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 (35) hide show
  1. package/dist/components/DatePicker/types.d.ts +1 -1
  2. package/dist/components/FiltersPane/components/Filter/helpers.d.ts +1 -0
  3. package/dist/components/FiltersPane/components/FilterDateSingle/FilterDateSingle.d.ts +15 -0
  4. package/dist/components/FiltersPane/components/FilterDateSingle/FilterDateSingle.styles.d.ts +11 -0
  5. package/dist/components/FiltersPane/components/FilterDateSingle/index.d.ts +2 -0
  6. package/dist/components/FiltersPane/components/FilterWithDates/FilterWithDates.styles.d.ts +1 -5
  7. package/dist/components/FiltersPane/components/index.d.ts +1 -0
  8. package/dist/components/FiltersPane/types.d.ts +7 -2
  9. package/dist/components/Selector/Selector.styles.d.ts +1 -7
  10. package/dist/hooks/use-resize-ref.d.ts +3 -3
  11. package/dist/theme/types.d.ts +2 -1
  12. package/dist/true-react-common-ui-kit.js +303 -327
  13. package/dist/true-react-common-ui-kit.js.map +1 -1
  14. package/dist/true-react-common-ui-kit.umd.cjs +1 -1
  15. package/dist/true-react-common-ui-kit.umd.cjs.map +1 -1
  16. package/package.json +1 -1
  17. package/src/components/DatePicker/DatePicker.tsx +2 -0
  18. package/src/components/DatePicker/types.ts +1 -0
  19. package/src/components/FiltersPane/FiltersPane.stories.tsx +38 -23
  20. package/src/components/FiltersPane/components/Filter/Filter.tsx +19 -1
  21. package/src/components/FiltersPane/components/Filter/helpers.ts +1 -1
  22. package/src/components/FiltersPane/components/FilterDateSingle/FilterDateSingle.styles.ts +34 -0
  23. package/src/components/FiltersPane/components/FilterDateSingle/FilterDateSingle.tsx +103 -0
  24. package/src/components/FiltersPane/components/FilterDateSingle/index.ts +2 -0
  25. package/src/components/FiltersPane/components/FilterValueView/FilterValueView.tsx +2 -2
  26. package/src/components/FiltersPane/components/FilterWithDates/FilterWithDates.styles.ts +1 -24
  27. package/src/components/FiltersPane/components/FilterWithDates/FilterWithDates.tsx +6 -43
  28. package/src/components/FiltersPane/components/index.ts +1 -0
  29. package/src/components/FiltersPane/constants.ts +2 -0
  30. package/src/components/FiltersPane/types.ts +11 -1
  31. package/src/components/Selector/Selector.stories.tsx +4 -0
  32. package/src/components/Selector/Selector.styles.ts +31 -133
  33. package/src/components/Selector/Selector.tsx +35 -48
  34. package/src/hooks/use-resize-ref.ts +5 -5
  35. package/src/theme/types.ts +2 -0
@@ -1,165 +1,63 @@
1
- import { CSSProperties } from 'react';
2
- import { isNotEmpty } from '@true-engineering/true-react-platform-helpers';
3
- import { colors, dimensions, ITweakStyles, createThemedStyles, animations } from '../../theme';
4
-
5
- const SELECTOR_TOTAL_GAP = 4;
6
- const SELECTOR_BORDER_WIDTH = 1;
7
- export const SELECTOR_GAP = SELECTOR_TOTAL_GAP - SELECTOR_BORDER_WIDTH;
8
-
9
- export const getSelectorLineStyle = (activeElementData?: {
10
- clientWidth: number;
11
- offsetLeft: number;
12
- }): CSSProperties | undefined =>
13
- isNotEmpty(activeElementData)
14
- ? {
15
- width: activeElementData.clientWidth - SELECTOR_GAP * 2,
16
- transform: `translateX(${activeElementData.offsetLeft}px)`,
17
- }
18
- : undefined;
1
+ import { ITweakStyles, createThemedStyles, animations } from '../../theme';
19
2
 
20
3
  export const useStyles = createThemedStyles('Selector', {
21
- root: {
22
- display: 'flex',
23
- alignItems: 'center',
24
- listStyle: 'none',
4
+ selector: {
5
+ display: 'grid',
6
+ gridAutoFlow: 'column',
7
+ gridAutoColumns: 'auto',
8
+ boxSizing: 'border-box',
25
9
  position: 'relative',
26
- },
27
10
 
28
- required: {
29
- '&::before': {
30
- top: '50%',
31
- left: -12,
32
- width: 6,
33
- height: 6,
11
+ '&:has($active)::before': {
34
12
  content: '""',
35
13
  position: 'absolute',
36
- transform: 'translate(0, -50%)',
37
- borderRadius: '50%',
38
- backgroundColor: colors.ORANGE_FOCUS,
14
+ transition: animations.defaultTransition,
15
+ transitionProperty: 'left, width',
16
+ width: 'var(--active-element-width)',
17
+ height: 'var(--active-element-height)',
18
+ top: 'var(--active-element-top)',
19
+ left: 'var(--active-element-left)',
39
20
  },
40
21
  },
41
22
 
42
- invalid: {},
43
-
44
- optionWrapper: {
45
- height: '100%',
23
+ autoWidth: {
24
+ gridAutoColumns: '1fr',
46
25
  },
47
26
 
27
+ required: {},
28
+
29
+ invalid: {},
30
+
48
31
  option: {
32
+ appearance: 'none',
33
+ background: 'none',
34
+ border: 'none',
35
+
49
36
  display: 'flex',
50
37
  alignItems: 'center',
51
38
  justifyContent: 'center',
52
- appearance: 'none',
53
- borderRadius: 0,
54
- padding: 0,
55
- border: 'none',
56
- cursor: 'pointer',
57
- width: '100%',
58
- },
39
+ zIndex: 1,
59
40
 
60
- active: {
61
- cursor: 'default',
41
+ '$iconFromRight &': {
42
+ flexDirection: 'row-reverse',
43
+ },
62
44
  },
63
45
 
64
- disabled: {
65
- cursor: 'default',
46
+ active: {},
66
47
 
67
- '& $optionText': {
68
- color: colors.FONT_LABEL,
69
- },
70
- },
48
+ disabled: {},
71
49
 
72
- optionIcon: {
73
- width: 20,
74
- height: 20,
75
- },
50
+ optionIcon: {},
76
51
 
77
52
  optionText: {},
78
53
 
79
- iconFromRight: {
80
- '& $option': {
81
- flexDirection: 'row-reverse',
82
- },
83
- },
54
+ iconFromRight: {},
84
55
 
85
56
  s: {},
86
57
 
87
58
  m: {},
88
59
 
89
60
  l: {},
90
-
91
- line: {},
92
-
93
- selector: {
94
- display: 'grid',
95
- gridAutoFlow: 'column',
96
- gridAutoColumns: '1fr',
97
- borderRadius: dimensions.BORDER_RADIUS_SMALL,
98
- backgroundColor: colors.BORDER_LIGHT,
99
- width: 'fit-content',
100
- position: 'relative',
101
- border: ['solid', SELECTOR_BORDER_WIDTH, 'transparent'],
102
-
103
- '& $line': {
104
- content: '""',
105
- position: 'absolute',
106
- left: SELECTOR_GAP,
107
- height: `calc(100% - ${SELECTOR_GAP * 2}px)`,
108
- backgroundColor: colors.CLASSIC_WHITE,
109
- borderRadius: dimensions.BORDER_RADIUS_SMALL,
110
- transition: animations.defaultTransition,
111
- transitionProperty: 'transform, width',
112
- },
113
-
114
- '&$invalid': {
115
- borderColor: colors.RED_WARNING,
116
- },
117
-
118
- '& $option': {
119
- gap: 6,
120
- position: 'relative',
121
- zIndex: 1,
122
- height: '100%',
123
- color: colors.FONT_MEDIUM,
124
- fontSize: 16,
125
- transition: animations.defaultTransition,
126
- transitionProperty: 'color',
127
- background: 'none',
128
-
129
- '&$s': {
130
- padding: [4, 8],
131
- fontSize: 10,
132
- lineHeight: '14px',
133
- },
134
-
135
- '&$m': {
136
- padding: [14, 18],
137
- },
138
-
139
- '&$l': {
140
- padding: [16, 24],
141
- },
142
-
143
- '&:hover, &:focus': {
144
- color: colors.FONT_MAIN,
145
- },
146
-
147
- '&$active': {
148
- color: colors.FONT_MAIN,
149
- },
150
- },
151
- },
152
-
153
- autoWidth: {
154
- '&$selector': {
155
- gridAutoColumns: 'auto',
156
-
157
- '& $line': {
158
- width: 'unset',
159
- transform: 'unset',
160
- },
161
- },
162
- },
163
61
  });
164
62
 
165
63
  export type ISelectorStyles = ITweakStyles<typeof useStyles>;
@@ -1,16 +1,15 @@
1
- import { useEffect, useRef, useState } from 'react';
2
1
  import clsx from 'clsx';
3
2
  import {
4
3
  addDataTestId,
5
4
  addDataAttributes,
6
- hasDuplicates,
7
- isNotEmpty,
8
5
  isReactNodeNotEmpty,
6
+ isNotEmpty,
9
7
  } from '@true-engineering/true-react-platform-helpers';
8
+ import { useResizeRef } from '../../hooks';
10
9
  import { ICommonProps } from '../../types';
11
10
  import { renderIcon } from '../Icon';
12
11
  import { ISelectorOption, ISelectorValue } from './types';
13
- import { getSelectorLineStyle, ISelectorStyles, useStyles } from './Selector.styles';
12
+ import { ISelectorStyles, useStyles } from './Selector.styles';
14
13
 
15
14
  export interface ISelectorProps<V extends ISelectorValue> extends ICommonProps<ISelectorStyles> {
16
15
  options: Array<ISelectorOption<V>>;
@@ -44,67 +43,55 @@ export function Selector<V extends ISelectorValue>({
44
43
  tweakStyles,
45
44
  onChange,
46
45
  }: ISelectorProps<V>): JSX.Element {
47
- const classes = useStyles({ theme: tweakStyles });
48
- const optionsValues = options.map((opt) => opt.value);
49
-
50
- const [elementsData, setElementsData] = useState<HTMLElement[]>([]);
51
- const listRef = useRef<HTMLDivElement>(null);
46
+ const classes = useStyles({ tweakStyles });
52
47
 
53
- if (hasDuplicates(optionsValues)) {
54
- console.error('Selector: Значения options.value должны быть уникальными');
55
- }
56
-
57
- useEffect(() => {
58
- const listEl = listRef.current;
59
- if (listEl === null) {
60
- return;
48
+ const updateVariables = (active: HTMLElement | null): void => {
49
+ if (isNotEmpty(active?.parentElement)) {
50
+ active.parentElement.style.setProperty('--active-element-width', `${active.clientWidth}px`);
51
+ active.parentElement.style.setProperty('--active-element-height', `${active.clientHeight}px`);
52
+ active.parentElement.style.setProperty('--active-element-left', `${active.offsetLeft}px`);
53
+ active.parentElement.style.setProperty('--active-element-top', `${active.offsetTop}px`);
61
54
  }
55
+ };
62
56
 
63
- setElementsData([...listEl.querySelectorAll<HTMLElement>(`.${classes.optionWrapper}`)]);
64
- }, [options, size]);
65
-
66
- const activeElementData = isNotEmpty(value)
67
- ? elementsData[optionsValues.indexOf(value)]
68
- : undefined;
57
+ const resizeRef = useResizeRef<HTMLDivElement>({
58
+ onTargetChange: (target) => updateVariables(target.querySelector(`.${classes.active}`)),
59
+ });
69
60
 
70
61
  return (
71
62
  <div
72
- className={clsx(classes.root, classes.selector, {
63
+ ref={resizeRef}
64
+ className={clsx(classes.selector, classes[size], {
73
65
  [classes.iconFromRight]: iconPosition === 'right',
74
66
  [classes.invalid]: isInvalid,
75
67
  [classes.required]: isRequired,
76
68
  [classes.autoWidth]: hasSameOptionsWidth,
77
69
  })}
78
- ref={listRef}
79
70
  {...addDataAttributes(data, testId)}
80
71
  >
81
- {isNotEmpty(activeElementData) && (
82
- <div className={classes.line} style={getSelectorLineStyle(activeElementData)} />
83
- )}
84
-
85
72
  {options.map((option) => {
86
- const optionId = option.value.toString();
87
- const isDisabledOption = option.isDisabled ?? isDisabled;
73
+ const optionId = String(option.value);
74
+ const isDisabledOption = option.isDisabled || isDisabled;
88
75
  const isActiveOption = option.value === value;
89
76
 
90
77
  return (
91
- <div key={optionId} className={classes.optionWrapper}>
92
- <button
93
- type="button"
94
- className={clsx(classes.option, classes[size], {
95
- [classes.active]: isActiveOption,
96
- [classes.disabled]: isDisabledOption,
97
- })}
98
- disabled={isDisabledOption}
99
- onClick={!isDisabledOption ? () => onChange(option.value) : undefined}
100
- {...addDataTestId(testId, optionId)}
101
- >
102
- {isReactNodeNotEmpty(option.icon) && (
103
- <div className={classes.optionIcon}>{renderIcon(option.icon)}</div>
104
- )}
105
- <div className={classes.optionText}>{option.label}</div>
106
- </button>
107
- </div>
78
+ <button
79
+ ref={isActiveOption ? updateVariables : undefined}
80
+ key={optionId}
81
+ type="button"
82
+ className={clsx(classes.option, {
83
+ [classes.active]: isActiveOption,
84
+ [classes.disabled]: isDisabledOption,
85
+ })}
86
+ disabled={isDisabledOption}
87
+ onClick={!isDisabledOption ? () => onChange(option.value) : undefined}
88
+ {...addDataTestId(testId, optionId)}
89
+ >
90
+ {isReactNodeNotEmpty(option.icon) && (
91
+ <div className={classes.optionIcon}>{renderIcon(option.icon)}</div>
92
+ )}
93
+ <div className={classes.optionText}>{option.label}</div>
94
+ </button>
108
95
  );
109
96
  })}
110
97
  </div>
@@ -2,14 +2,14 @@ import { RefCallback, useMemo, useEffect } from 'react';
2
2
  import { isNotEmpty } from '@true-engineering/true-react-platform-helpers';
3
3
  import { useLatestRef } from './use-latest-ref';
4
4
 
5
- export interface IResizeRefOptions {
5
+ export interface IResizeRefOptions<T extends Element> {
6
6
  /** @default false */
7
7
  isDisabled?: boolean;
8
8
  onChange?: (entry: ResizeObserverEntry) => void;
9
- onTargetChange?: (target: Element) => void;
9
+ onTargetChange?: (target: T) => void;
10
10
  }
11
11
 
12
- export const useResizeRef = (options: IResizeRefOptions): RefCallback<Element> => {
12
+ export const useResizeRef = <T extends Element>(options: IResizeRefOptions<T>): RefCallback<T> => {
13
13
  const optionsRef = useLatestRef(options);
14
14
 
15
15
  const { ref, disconnect } = useMemo(() => {
@@ -17,11 +17,11 @@ export const useResizeRef = (options: IResizeRefOptions): RefCallback<Element> =
17
17
  const { current } = optionsRef;
18
18
  if (!current.isDisabled) {
19
19
  current.onChange?.(entry);
20
- current.onTargetChange?.(entry.target);
20
+ current.onTargetChange?.(entry.target as T);
21
21
  }
22
22
  });
23
23
 
24
- const observerRef: RefCallback<Element> = (node) => {
24
+ const observerRef: RefCallback<T> = (node) => {
25
25
  observer.disconnect();
26
26
  if (!isNotEmpty(node)) {
27
27
  return;
@@ -16,6 +16,7 @@ import type {
16
16
  IDotsPreloaderStyles,
17
17
  IFileInputStyles,
18
18
  IFileItemStyles,
19
+ IFilterDateSingleStyles,
19
20
  IFilterIntervalStyles,
20
21
  IFilterSelectStyles,
21
22
  IFiltersPaneSearchStyles,
@@ -103,6 +104,7 @@ export interface IComponentStyles {
103
104
  FileItem: IFileItemStyles;
104
105
  FilterValueView: IFilterValueViewStyles;
105
106
  FiltersPane: IFiltersPaneStyles;
107
+ FilterDateSingle: IFilterDateSingleStyles;
106
108
  FilterInterval: IFilterIntervalStyles;
107
109
  FilterSelect: IFilterSelectStyles;
108
110
  FilterWithDates: IFilterWithDatesStyles;