@true-engineering/true-react-common-ui-kit 3.0.0-alpha.1 → 3.0.0-alpha.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 (63) hide show
  1. package/LICENSE +201 -201
  2. package/dist/components/Checkbox/Checkbox.d.ts +1 -1
  3. package/dist/components/FiltersPane/components/FilterSelect/FilterSelect.d.ts +1 -5
  4. package/dist/components/FiltersPane/components/FiltersPaneSearch/FiltersPaneSearch.d.ts +1 -3
  5. package/dist/components/Flag/augment.d.ts +1 -1
  6. package/dist/components/FlexibleTable/FlexibleTable.d.ts +3 -0
  7. package/dist/components/FlexibleTable/FlexibleTable.styles.d.ts +1 -1
  8. package/dist/components/FlexibleTable/helpers.d.ts +1 -0
  9. package/dist/components/Icon/complexIcons/augment.d.ts +1 -1
  10. package/dist/components/MultiSelectList/MultiSelectList.d.ts +1 -2
  11. package/dist/components/Switch/Switch.d.ts +1 -1
  12. package/dist/helpers/phone.d.ts +1 -1
  13. package/dist/hooks/index.d.ts +1 -0
  14. package/dist/hooks/use-mixed-styles.d.ts +1 -0
  15. package/dist/true-react-common-ui-kit.js +714 -408
  16. package/dist/true-react-common-ui-kit.js.map +1 -1
  17. package/dist/true-react-common-ui-kit.umd.cjs +714 -408
  18. package/dist/true-react-common-ui-kit.umd.cjs.map +1 -1
  19. package/dist/vite-env.d.ts +1 -1
  20. package/package.json +1 -1
  21. package/src/components/AddButton/AddButton.stories.tsx +21 -21
  22. package/src/components/Checkbox/Checkbox.styles.ts +1 -0
  23. package/src/components/Checkbox/Checkbox.tsx +1 -1
  24. package/src/components/Colors/Colors.stories.tsx +7 -7
  25. package/src/components/DateInput/DateInput.tsx +1 -9
  26. package/src/components/DateInput/constants.ts +2 -2
  27. package/src/components/DatePicker/DatePicker.stories.tsx +1 -0
  28. package/src/components/DatePicker/DatePicker.tsx +1 -3
  29. package/src/components/FiltersPane/FiltersPane.stories.tsx +0 -8
  30. package/src/components/FiltersPane/components/FilterInterval/FilterInterval.styles.ts +2 -1
  31. package/src/components/FiltersPane/components/FilterSelect/FilterSelect.styles.ts +3 -1
  32. package/src/components/FiltersPane/components/FilterSelect/FilterSelect.tsx +1 -6
  33. package/src/components/FiltersPane/components/FilterWithDates/FilterWithDates.styles.ts +2 -1
  34. package/src/components/FiltersPane/components/FiltersPaneSearch/FiltersPaneSearch.styles.ts +1 -0
  35. package/src/components/FiltersPane/components/FiltersPaneSearch/FiltersPaneSearch.tsx +1 -4
  36. package/src/components/FiltersPane/types.ts +1 -1
  37. package/src/components/Flag/augment.d.ts +1 -1
  38. package/src/components/FlexibleTable/FlexibleTable.stories.tsx +14 -12
  39. package/src/components/FlexibleTable/FlexibleTable.styles.ts +4 -10
  40. package/src/components/FlexibleTable/FlexibleTable.tsx +22 -15
  41. package/src/components/FlexibleTable/components/FlexibleTableCell/FlexibleTableCell.styles.ts +4 -0
  42. package/src/components/FlexibleTable/helpers.ts +4 -0
  43. package/src/components/Icon/complexIcons/augment.d.ts +1 -1
  44. package/src/components/Icon/complexIcons/avatarGreen.svg +57 -57
  45. package/src/components/Icon/complexIcons/index.ts +1 -1
  46. package/src/components/MoreMenu/MoreMenu.stories.tsx +46 -46
  47. package/src/components/MultiSelectList/MultiSelectList.styles.ts +4 -0
  48. package/src/components/MultiSelectList/MultiSelectList.tsx +1 -3
  49. package/src/components/NumberInput/index.ts +1 -1
  50. package/src/components/PhoneInput/types.ts +16 -16
  51. package/src/components/ScrollIntoViewIfNeeded/index.ts +1 -1
  52. package/src/components/Select/constants.ts +2 -2
  53. package/src/components/Select/types.ts +1 -1
  54. package/src/components/Switch/Switch.tsx +2 -2
  55. package/src/components/TextWithTooltip/TextWithTooltip.stories.tsx +58 -58
  56. package/src/components/ThemedPreloader/components/DefaultPreloader/index.ts +1 -1
  57. package/src/components/Tooltip/types.ts +1 -1
  58. package/src/helpers/phone.ts +1 -1
  59. package/src/helpers/popper-helpers.ts +17 -17
  60. package/src/hooks/index.ts +1 -0
  61. package/src/hooks/use-is-mounted.ts +15 -15
  62. package/src/hooks/use-mixed-styles.ts +14 -0
  63. package/src/vite-env.d.ts +1 -1
@@ -1 +1 @@
1
- /// <reference types="vite/client" />
1
+ /// <reference types="vite/client" />
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@true-engineering/true-react-common-ui-kit",
3
- "version": "3.0.0-alpha.1",
3
+ "version": "3.0.0-alpha.11",
4
4
  "description": "True Engineering React UI Kit with theming support",
5
5
  "author": "True Engineering (https://trueengineering.ru)",
6
6
  "keywords": [
@@ -1,21 +1,21 @@
1
- import { ComponentStory } from '@storybook/react';
2
- import { AddButton } from './AddButton';
3
-
4
- export default {
5
- title: 'AddButton',
6
- component: AddButton,
7
- };
8
-
9
- const Template: ComponentStory<typeof AddButton> = (args) => (
10
- <AddButton {...args} onClick={console.log} />
11
- );
12
-
13
- export const Default = Template.bind({});
14
-
15
- Default.args = {
16
- text: 'Добавить билет',
17
- isDisabled: false,
18
- isFullWidth: false,
19
- };
20
-
21
- Default.parameters = { controls: { exclude: ['onClick'] } };
1
+ import { ComponentStory } from '@storybook/react';
2
+ import { AddButton } from './AddButton';
3
+
4
+ export default {
5
+ title: 'AddButton',
6
+ component: AddButton,
7
+ };
8
+
9
+ const Template: ComponentStory<typeof AddButton> = (args) => (
10
+ <AddButton {...args} onClick={console.log} />
11
+ );
12
+
13
+ export const Default = Template.bind({});
14
+
15
+ Default.args = {
16
+ text: 'Добавить билет',
17
+ isDisabled: false,
18
+ isFullWidth: false,
19
+ };
20
+
21
+ Default.parameters = { controls: { exclude: ['onClick'] } };
@@ -4,6 +4,7 @@ export const useStyles = createThemedStyles('Checkbox', {
4
4
  root: {
5
5
  cursor: 'pointer',
6
6
  display: 'flex',
7
+ alignItems: 'center',
7
8
  gap: 14,
8
9
  width: 'fit-content',
9
10
  },
@@ -12,7 +12,7 @@ import { useStyles, ICheckboxStyles } from './Checkbox.styles';
12
12
 
13
13
  export interface ICheckboxProps<V> extends ICommonProps<ICheckboxStyles> {
14
14
  children?: ReactNode;
15
- isChecked?: boolean;
15
+ isChecked: boolean | undefined;
16
16
  isSemiChecked?: boolean;
17
17
  isDisabled?: boolean;
18
18
  isReadonly?: boolean;
@@ -1,7 +1,7 @@
1
- import { Colors } from './Colors';
2
-
3
- export default {
4
- title: 'Colors',
5
- };
6
-
7
- export const Default = (): JSX.Element => <Colors />;
1
+ import { Colors } from './Colors';
2
+
3
+ export default {
4
+ title: 'Colors',
5
+ };
6
+
7
+ export const Default = (): JSX.Element => <Colors />;
@@ -1,6 +1,5 @@
1
1
  import { FormEvent, MouseEvent, forwardRef, ChangeEvent } from 'react';
2
2
  import clsx from 'clsx';
3
- import { addDataTestId, getTestId } from '@true-engineering/true-react-platform-helpers';
4
3
  import { addDataAttributes } from '../../helpers';
5
4
  import { useTweakStyles } from '../../hooks';
6
5
  import { ICommonProps } from '../../types';
@@ -33,7 +32,6 @@ export const DateInput = forwardRef<HTMLInputElement, IDateInputProps>(
33
32
  data,
34
33
  isRange,
35
34
  tweakStyles,
36
- testId,
37
35
  onClick,
38
36
  onChange,
39
37
  ...inputProps
@@ -70,12 +68,7 @@ export const DateInput = forwardRef<HTMLInputElement, IDateInputProps>(
70
68
  };
71
69
 
72
70
  return (
73
- <div
74
- className={clsx(classes.root, className)}
75
- onClick={onClick}
76
- {...addDataTestId(testId)}
77
- {...addDataAttributes(data)}
78
- >
71
+ <div className={clsx(classes.root, className)} onClick={onClick} {...addDataAttributes(data)}>
79
72
  <Input
80
73
  {...inputProps}
81
74
  ref={ref}
@@ -84,7 +77,6 @@ export const DateInput = forwardRef<HTMLInputElement, IDateInputProps>(
84
77
  placeholder={
85
78
  placeholder ?? (isRange ? EMPTY_DATE_RANGE_INPUT_VALUE : EMPTY_DATE_INPUT_VALUE)
86
79
  }
87
- testId={getTestId(testId, 'input')}
88
80
  tweakStyles={tweakInputStyles}
89
81
  onChange={handleChange}
90
82
  beforeMaskedStateChange={beforeMaskedStateChange}
@@ -1,2 +1,2 @@
1
- export const EMPTY_DATE_INPUT_VALUE = '__.__.____';
2
- export const EMPTY_DATE_RANGE_INPUT_VALUE = `${EMPTY_DATE_INPUT_VALUE} - ${EMPTY_DATE_INPUT_VALUE}`;
1
+ export const EMPTY_DATE_INPUT_VALUE = '__.__.____';
2
+ export const EMPTY_DATE_RANGE_INPUT_VALUE = `${EMPTY_DATE_INPUT_VALUE} - ${EMPTY_DATE_INPUT_VALUE}`;
@@ -47,6 +47,7 @@ const Template: ComponentStory<typeof DatePicker> = (args) => {
47
47
  <DatePicker
48
48
  {...args}
49
49
  locale={ru}
50
+ testId="datepicker"
50
51
  months={months}
51
52
  selectedDate={date}
52
53
  startDate={startDate}
@@ -4,7 +4,6 @@ import 'react-datepicker/dist/react-datepicker.css';
4
4
  import clsx from 'clsx';
5
5
  import { isAfter, isBefore, isValid } from 'date-fns';
6
6
  import {
7
- addDataTestId,
8
7
  isEmpty,
9
8
  isNotEmpty,
10
9
  isStringNotEmpty,
@@ -40,7 +39,6 @@ export const DatePicker = forwardRef<ReactDatePicker, IDatePickerProps>(
40
39
  (
41
40
  {
42
41
  data,
43
- testId,
44
42
  selectedDate = null,
45
43
  minDate,
46
44
  maxDate,
@@ -234,7 +232,7 @@ export const DatePicker = forwardRef<ReactDatePicker, IDatePickerProps>(
234
232
  }, [selectedDate, startDate, endDate]);
235
233
 
236
234
  return (
237
- <div className={classes.root} {...addDataTestId(testId)} {...addDataAttributes(data)}>
235
+ <div className={classes.root} {...addDataAttributes(data)}>
238
236
  <DatePickerComponent
239
237
  ref={ref}
240
238
  minDate={minDate}
@@ -72,7 +72,6 @@ type ConfigValues = {
72
72
 
73
73
  interface IFiltersPaneWithCustomProps<Values, Content> extends IFiltersPaneProps<Values, Content> {
74
74
  containerWidth: number;
75
- multiselectWidth: number;
76
75
  isSearchDisabled: boolean;
77
76
  isSearchAutosizeable: boolean;
78
77
  shouldShowSettingsButton: boolean;
@@ -83,7 +82,6 @@ interface IFiltersPaneWithCustomProps<Values, Content> extends IFiltersPaneProps
83
82
 
84
83
  function FiltersPaneWithCustomProps<Values, Content>({
85
84
  containerWidth,
86
- multiselectWidth,
87
85
  isSearchDisabled,
88
86
  isSearchAutosizeable,
89
87
  shouldShowSettingsButton,
@@ -141,7 +139,6 @@ function FiltersPaneWithCustomProps<Values, Content>({
141
139
  multiSelect: {
142
140
  name: 'multiSelect',
143
141
  type: 'multiSelect',
144
- width: multiselectWidth,
145
142
  pageSize: 15,
146
143
  checkboxPosition,
147
144
  isGroupingEnabled,
@@ -163,7 +160,6 @@ function FiltersPaneWithCustomProps<Values, Content>({
163
160
  isGroupingEnabled,
164
161
  checkboxPosition,
165
162
  searchMaxLength: 12,
166
- width: multiselectWidth,
167
163
  fetchOptions: (q?: string): Promise<Array<{ v: string }>> => {
168
164
  if (q === '' || q === 'undefined' || q === '123') {
169
165
  return new Promise((resolve) => setTimeout(() => resolve([])));
@@ -265,9 +261,6 @@ export default {
265
261
  containerWidth: {
266
262
  control: { type: 'range', min: 100, max: 1000, step: 100 },
267
263
  },
268
- multiselectWidth: {
269
- control: { type: 'range', min: 100, max: 400, step: 50 },
270
- },
271
264
  checkboxPosition: {
272
265
  control: 'inline-radio',
273
266
  options: ['left', 'right'],
@@ -288,7 +281,6 @@ Default.args = {
288
281
  hasClearButton: true,
289
282
  isDisabled: false,
290
283
  containerWidth: 400,
291
- multiselectWidth: 200,
292
284
  withFieldNameInLabel: true,
293
285
  isGroupingEnabled: true,
294
286
  checkboxPosition: 'left',
@@ -1,3 +1,4 @@
1
+ import cloneDeep from 'lodash-es/cloneDeep';
1
2
  import { colors, createThemedStyles, ITweakStyles } from '../../../../theme';
2
3
  import { IButtonStyles } from '../../../Button';
3
4
  import { IInputStyles } from '../../../Input';
@@ -49,7 +50,7 @@ export const inputStyles: IInputStyles = {
49
50
  },
50
51
  };
51
52
 
52
- export const clearButtonStyles = innerTextButtonStyles;
53
+ export const clearButtonStyles = cloneDeep(innerTextButtonStyles);
53
54
 
54
55
  export type IFilterIntervalStyles = ITweakStyles<
55
56
  typeof useStyles,
@@ -1,3 +1,4 @@
1
+ import cloneDeep from 'lodash-es/cloneDeep';
1
2
  import { colors, createThemedStyles, helpers, ITweakStyles } from '../../../../theme';
2
3
  import { IButtonStyles } from '../../../Button';
3
4
  import { ISearchInputStyles } from '../../../SearchInput';
@@ -8,6 +9,7 @@ const LIST_GAP = 12;
8
9
 
9
10
  export const useStyles = createThemedStyles('FilterSelect', {
10
11
  root: {
12
+ width: 220,
11
13
  background: colors.CLASSIC_WHITE,
12
14
  },
13
15
 
@@ -127,7 +129,7 @@ export const searchInputStyles: ISearchInputStyles = {
127
129
  },
128
130
  };
129
131
 
130
- export const clearButtonStyles = innerTextButtonStyles;
132
+ export const clearButtonStyles = cloneDeep(innerTextButtonStyles);
131
133
 
132
134
  export type IFilterSelectStyles = ITweakStyles<
133
135
  typeof useStyles,
@@ -30,10 +30,6 @@ export interface IFilterSelectProps<Value> extends ICommonProps<IFilterSelectSty
30
30
  * @default false
31
31
  */
32
32
  isGroupingEnabled?: boolean;
33
- /**
34
- * @default `220px`
35
- */
36
- width?: string | number;
37
33
  localeKey?: IFilterLocaleKey;
38
34
  locale?: Partial<ISelectLocale>;
39
35
  options?: Value[];
@@ -54,7 +50,6 @@ export function FilterSelect<Value>({
54
50
  value,
55
51
  isSearchEnabled = false,
56
52
  isGroupingEnabled = false,
57
- width = 220,
58
53
  localeKey,
59
54
  locale,
60
55
  onChange,
@@ -225,7 +220,7 @@ export function FilterSelect<Value>({
225
220
  }, []);
226
221
 
227
222
  return (
228
- <div className={classes.root} style={{ width }} {...addDataAttributes(data)}>
223
+ <div className={classes.root} {...addDataAttributes(data)}>
229
224
  {isSearchEnabled && (
230
225
  <div className={classes.dropdownInput}>
231
226
  <SearchInput
@@ -1,3 +1,4 @@
1
+ import cloneDeep from 'lodash-es/cloneDeep';
1
2
  import { colors, createThemedStyles, ITweakStyles } from '../../../../theme';
2
3
  import { IButtonStyles } from '../../../Button';
3
4
  import { IDatePickerStyles } from '../../../DatePicker';
@@ -31,7 +32,7 @@ export const useStyles = createThemedStyles('FilterWithDates', {
31
32
  datepicker: {},
32
33
  });
33
34
 
34
- export const clearButtonStyles = innerTextButtonStyles;
35
+ export const clearButtonStyles = cloneDeep(innerTextButtonStyles);
35
36
 
36
37
  export const backButtonStyles = innerTextButtonStyles;
37
38
 
@@ -104,6 +104,7 @@ export const selectStyles: ISelectStyles = {
104
104
  borderBottomLeftRadius: 6,
105
105
  borderBottomRightRadius: 6,
106
106
  boxShadow: 'none',
107
+ width: '100%',
107
108
  },
108
109
  };
109
110
 
@@ -7,7 +7,7 @@ import { Icon } from '../../../Icon';
7
7
  import { SearchInput } from '../../../SearchInput';
8
8
  import { getLocale } from '../../helpers';
9
9
  import { IFilterLocaleKey, IFiltersPaneSearchPayload, IPartialFilterLocale } from '../../types';
10
- import { FilterSelect, IFilterSelectProps } from '../FilterSelect';
10
+ import { FilterSelect } from '../FilterSelect';
11
11
  import {
12
12
  useStyles,
13
13
  IFiltersPaneSearchStyles,
@@ -26,7 +26,6 @@ export interface IFiltersPaneSearchProps<Value> extends ICommonProps<IFiltersPan
26
26
  getValueView?: (value: Value) => ReactNode;
27
27
  getValueId?: (value: Value) => string;
28
28
  getValueString?: (value: Value) => string;
29
- selectWidth?: IFilterSelectProps<Value>['width'];
30
29
  hasClearSelectButton?: boolean;
31
30
  isDisabled?: boolean;
32
31
  isSelectSearchEnabled?: boolean;
@@ -43,7 +42,6 @@ export function FiltersPaneSearch<Value>({
43
42
  getValueId,
44
43
  getValueView,
45
44
  getValueString,
46
- selectWidth = '100%',
47
45
  hasClearSelectButton,
48
46
  isDisabled = false,
49
47
  isSelectSearchEnabled = true,
@@ -155,7 +153,6 @@ export function FiltersPaneSearch<Value>({
155
153
  localeKey={localeKey}
156
154
  locale={translates}
157
155
  onChange={handleFieldsChange}
158
- width={selectWidth}
159
156
  isSearchEnabled={isSelectSearchEnabled}
160
157
  hasClearButton={hasClearSelectButton}
161
158
  testId={testId !== undefined ? `${testId}-dropdown` : undefined}
@@ -152,5 +152,5 @@ export type ISelectLocaleKey = keyof typeof SelectLocales;
152
152
 
153
153
  export type IFilterWithDateDatePickerProps = Omit<
154
154
  IDatePickerProps,
155
- 'onChange' | 'value' | 'locale' | 'months' | 'selectedDate' | 'tweakStyles' // TODO: rethink
155
+ 'onChange' | 'value' | 'locale' | 'months' | 'selectedDate' | 'tweakStyles'
156
156
  >;
@@ -1 +1 @@
1
- declare module 'country-flag-icons/react/3x2';
1
+ declare module 'country-flag-icons/react/3x2';
@@ -315,18 +315,20 @@ const tweak: IFlexibleTableStyles = {
315
315
  };
316
316
 
317
317
  const Template: ComponentStory<typeof FlexibleTable<ITableContent>> = (args) => (
318
- <FlexibleTable<ITableContent>
319
- {...args}
320
- uniqueField="contractCode"
321
- expandableRowComponent={(item, _, close) =>
322
- item.contractCode === 'OB_UT_M119' ? (
323
- <div onClick={close}>всем привет :) {item.contractCode}</div>
324
- ) : null
325
- }
326
- tweakStyles={tweak}
327
- content={content}
328
- config={config}
329
- />
318
+ <div style={{ width: 500, overflow: 'auto' }}>
319
+ <FlexibleTable<ITableContent>
320
+ {...args}
321
+ uniqueField="contractCode"
322
+ expandableRowComponent={(item, _, close) =>
323
+ item.contractCode === 'OB_UT_M119' ? (
324
+ <div onClick={close}>всем привет :) {item.contractCode}</div>
325
+ ) : null
326
+ }
327
+ tweakStyles={tweak}
328
+ content={content}
329
+ config={config}
330
+ />
331
+ </div>
330
332
  );
331
333
 
332
334
  export const Default = Template.bind({});
@@ -22,16 +22,6 @@ export const useStyles = createThemedStyles('FlexibleTable', {
22
22
  maxHeight: '100%',
23
23
  },
24
24
 
25
- horizontallyScrolled: {
26
- '& $cellSticky': {
27
- boxShadow: '4px 0 4px rgba(0, 0, 0, 0.05)',
28
- },
29
-
30
- '& $headerSticky::before': {
31
- boxShadow: '4px 0 4px rgba(0, 0, 0, 0.05)',
32
- },
33
- },
34
-
35
25
  loader: {
36
26
  position: 'sticky',
37
27
  left: 0,
@@ -75,6 +65,10 @@ export const useStyles = createThemedStyles('FlexibleTable', {
75
65
  pointerEvents: 'none',
76
66
  zIndex: 1,
77
67
  transition: ['box-shadow', '0.25s', 'ease-in-out'],
68
+
69
+ '[data-scrolled] &': {
70
+ boxShadow: '4px 0 4px rgba(0, 0, 0, 0.05)',
71
+ },
78
72
  },
79
73
 
80
74
  '&::after': {
@@ -1,10 +1,12 @@
1
1
  import { ReactNode, RefObject, useCallback, useEffect, useRef, useState } from 'react';
2
2
  import clsx from 'clsx';
3
+ import { addDataTestId, isNotEmpty } from '@true-engineering/true-react-platform-helpers';
3
4
  import { addDataAttributes } from '../../helpers';
4
5
  import { useTweakStyles } from '../../hooks';
5
6
  import { ICommonProps } from '../../types';
6
7
  import { ThemedPreloader } from '../ThemedPreloader';
7
8
  import { FlexibleTableRow } from './components';
9
+ import { hasHorizontalScrollBar } from './helpers';
8
10
  import { IFlexibleTableConfigType, IInfinityScrollConfig, ITitleComponent } from './types';
9
11
  import { useStyles, IFlexibleTableStyles } from './FlexibleTable.styles';
10
12
 
@@ -19,6 +21,9 @@ export interface IFlexibleTableProps<Values extends Record<string, any>>
19
21
  isHorizontallyScrollable?: boolean;
20
22
  isFirstColumnSticky?: boolean;
21
23
  infinityScrollConfig?: IInfinityScrollConfig;
24
+ /**
25
+ * @default Индекс строки
26
+ */
22
27
  uniqueField?: keyof Values;
23
28
  onHeadClick?: (column: keyof Values) => void;
24
29
  // TODO: Заменить string на Generic Values[uniqueField]
@@ -63,6 +68,7 @@ export function FlexibleTable<Values extends Record<string, any>>({
63
68
 
64
69
  const observer = useRef<IntersectionObserver>();
65
70
  const scrollRef = useRef<HTMLDivElement>(null);
71
+ const ref = refForScroll ?? scrollRef;
66
72
 
67
73
  const initIntersectionObserver = useCallback(
68
74
  (node: HTMLDivElement) => {
@@ -97,7 +103,7 @@ export function FlexibleTable<Values extends Record<string, any>>({
97
103
  );
98
104
 
99
105
  useEffect(() => {
100
- const scrollContainer = (refForScroll ?? scrollRef).current;
106
+ const scrollContainer = ref.current;
101
107
  if (scrollContainer === null || !isHorizontallyScrollable || !isFirstColumnSticky) {
102
108
  return;
103
109
  }
@@ -110,13 +116,15 @@ export function FlexibleTable<Values extends Record<string, any>>({
110
116
 
111
117
  return (
112
118
  <div
113
- ref={refForScroll ?? scrollRef}
114
- className={clsx(
115
- isHorizontallyScrollable && classes.scroll,
116
- isHorizontallyScrolled && classes.horizontallyScrolled,
117
- )}
119
+ ref={ref}
120
+ className={clsx({ [classes.scroll]: isHorizontallyScrollable })}
121
+ {...addDataAttributes({
122
+ scrolled: isHorizontallyScrolled ? true : undefined,
123
+ scrollable:
124
+ isHorizontallyScrollable && hasHorizontalScrollBar(ref.current) ? true : undefined,
125
+ })}
118
126
  >
119
- <table className={classes.root} data-testid={testId} {...addDataAttributes(data)}>
127
+ <table className={classes.root} {...addDataTestId(testId)} {...addDataAttributes(data)}>
120
128
  <thead>
121
129
  <tr className={classes.headerRow}>
122
130
  {(enabledColumns || Object.keys(content[0])).map((key, idx) => {
@@ -131,11 +139,10 @@ export function FlexibleTable<Values extends Record<string, any>>({
131
139
 
132
140
  return (
133
141
  <th
134
- className={clsx(
135
- classes.header,
136
- isFirstColumnSticky && idx === 0 && classes.headerSticky,
137
- isFirstColumnSticky && idx === 1 && classes.headerSecond,
138
- )}
142
+ className={clsx(classes.header, {
143
+ [classes.headerSticky]: isFirstColumnSticky && idx === 0,
144
+ [classes.headerSecond]: isFirstColumnSticky && idx === 1,
145
+ })}
139
146
  style={{
140
147
  minWidth: itemConfig?.minWidth,
141
148
  width: itemConfig?.width,
@@ -163,17 +170,17 @@ export function FlexibleTable<Values extends Record<string, any>>({
163
170
  </tr>
164
171
  )}
165
172
 
166
- {content.map((item, idx) => (
173
+ {content.map((item, i) => (
167
174
  <FlexibleTableRow
168
175
  item={item}
169
176
  uniqueField={uniqueField}
170
- isActive={activeRows?.includes(idx) ?? false}
177
+ isActive={activeRows?.includes(i) ?? false}
171
178
  isFirstColumnSticky={isFirstColumnSticky}
172
179
  onRowClick={onRowClick}
173
180
  onRowHover={onRowHover}
174
181
  enabledColumns={enabledColumns}
175
182
  config={config}
176
- key={uniqueField ? item[uniqueField] : idx}
183
+ key={isNotEmpty(uniqueField) ? item[uniqueField] : i}
177
184
  rowAttributes={rowAttributes}
178
185
  tweakStyles={tweakTableRowStyles}
179
186
  expandableRowComponent={expandableRowComponent}
@@ -18,6 +18,10 @@ export const useStyles = createThemedStyles('FlexibleTableCell', {
18
18
  paddingLeft: 24,
19
19
  paddingRight: 12,
20
20
  ...getTransition(['box-shadow']),
21
+
22
+ '[data-scrolled] &': {
23
+ boxShadow: '4px 0 4px rgba(0, 0, 0, 0.05)',
24
+ },
21
25
  },
22
26
 
23
27
  second: {
@@ -0,0 +1,4 @@
1
+ import { isNotEmpty } from '@true-engineering/true-react-platform-helpers';
2
+
3
+ export const hasHorizontalScrollBar = (el: HTMLElement | null | undefined): boolean =>
4
+ isNotEmpty(el) && el.scrollWidth !== el.clientWidth;
@@ -1 +1 @@
1
- declare module '*.svg?raw';
1
+ declare module '*.svg?raw';
@@ -1,58 +1,58 @@
1
- <svg
2
- width="100%"
3
- height="100%"
4
- viewBox="0 0 32 32"
5
- fill="none"
6
- xmlns="http://www.w3.org/2000/svg"
7
- >
8
- <circle opacity="0.5" cx="16" cy="16" r="16" fill="#DDE3ED" />
9
- <mask
10
- id="mask0_0_12744"
11
- style="mask-type: 'alpha';"
12
- maskUnits="userSpaceOnUse"
13
- x="0"
14
- y="0"
15
- width="32"
16
- height="32"
17
- >
18
- <circle cx="16" cy="16" r="16" fill="white" />
19
- </mask>
20
- <g mask="url(#mask0_0_12744)">
21
- <circle cx="16" cy="29" r="13" fill="url(#paint0_linear_0_12744)" />
22
- <mask
23
- id="mask1_0_12744"
24
- style="mask-type: 'alpha';"
25
- maskUnits="userSpaceOnUse"
26
- x="3"
27
- y="16"
28
- width="26"
29
- height="26"
30
- >
31
- <circle cx="16" cy="29" r="13" fill="white" />
32
- </mask>
33
- <g mask="url(#mask1_0_12744)">
34
- <ellipse
35
- cx="16"
36
- cy="17.5"
37
- rx="6"
38
- ry="7.5"
39
- fill="#505F79"
40
- fill-opacity="0.204983"
41
- />
42
- </g>
43
- </g>
44
- <ellipse cx="16" cy="13" rx="6" ry="7" fill="white" />
45
- <defs>
46
- <linearGradient
47
- id="paint0_linear_0_12744"
48
- x1="13.347"
49
- y1="46.279"
50
- x2="33.5318"
51
- y2="30.8088"
52
- gradientUnits="userSpaceOnUse"
53
- >
54
- <stop stop-color="#ABD229" />
55
- <stop offset="1" stop-color="#9CD03F" />
56
- </linearGradient>
57
- </defs>
1
+ <svg
2
+ width="100%"
3
+ height="100%"
4
+ viewBox="0 0 32 32"
5
+ fill="none"
6
+ xmlns="http://www.w3.org/2000/svg"
7
+ >
8
+ <circle opacity="0.5" cx="16" cy="16" r="16" fill="#DDE3ED" />
9
+ <mask
10
+ id="mask0_0_12744"
11
+ style="mask-type: 'alpha';"
12
+ maskUnits="userSpaceOnUse"
13
+ x="0"
14
+ y="0"
15
+ width="32"
16
+ height="32"
17
+ >
18
+ <circle cx="16" cy="16" r="16" fill="white" />
19
+ </mask>
20
+ <g mask="url(#mask0_0_12744)">
21
+ <circle cx="16" cy="29" r="13" fill="url(#paint0_linear_0_12744)" />
22
+ <mask
23
+ id="mask1_0_12744"
24
+ style="mask-type: 'alpha';"
25
+ maskUnits="userSpaceOnUse"
26
+ x="3"
27
+ y="16"
28
+ width="26"
29
+ height="26"
30
+ >
31
+ <circle cx="16" cy="29" r="13" fill="white" />
32
+ </mask>
33
+ <g mask="url(#mask1_0_12744)">
34
+ <ellipse
35
+ cx="16"
36
+ cy="17.5"
37
+ rx="6"
38
+ ry="7.5"
39
+ fill="#505F79"
40
+ fill-opacity="0.204983"
41
+ />
42
+ </g>
43
+ </g>
44
+ <ellipse cx="16" cy="13" rx="6" ry="7" fill="white" />
45
+ <defs>
46
+ <linearGradient
47
+ id="paint0_linear_0_12744"
48
+ x1="13.347"
49
+ y1="46.279"
50
+ x2="33.5318"
51
+ y2="30.8088"
52
+ gradientUnits="userSpaceOnUse"
53
+ >
54
+ <stop stop-color="#ABD229" />
55
+ <stop offset="1" stop-color="#9CD03F" />
56
+ </linearGradient>
57
+ </defs>
58
58
  </svg>
@@ -1 +1 @@
1
- export * from './icons';
1
+ export * from './icons';