@true-engineering/true-react-common-ui-kit 4.0.0-alpha0 → 4.0.0-alpha10
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/README.md +11 -567
- package/dist/components/Button/Button.styles.d.ts +1 -1
- package/dist/components/Checkbox/Checkbox.styles.d.ts +1 -1
- package/dist/components/ControlWrapper/ControlWrapper.styles.d.ts +1 -1
- package/dist/components/DatePicker/DatePicker.d.ts +2 -2
- package/dist/components/DatePicker/helpers.d.ts +3 -0
- package/dist/components/DatePicker/types.d.ts +3 -1
- package/dist/components/FiltersPane/FiltersPane.d.ts +4 -2
- package/dist/components/FiltersPane/FiltersPane.stories.d.ts +3 -3
- package/dist/components/FiltersPane/components/Filter/Filter.d.ts +2 -2
- package/dist/components/FiltersPane/components/Filter/helpers.d.ts +4 -0
- package/dist/components/FiltersPane/components/FilterInterval/FilterInterval.styles.d.ts +1 -1
- package/dist/components/FiltersPane/components/FilterSelect/FilterSelect.styles.d.ts +1 -1
- package/dist/components/FiltersPane/components/FilterValueView/FilterValueView.d.ts +3 -1
- package/dist/components/FiltersPane/components/FilterWithDates/FilterWithDates.styles.d.ts +2 -2
- package/dist/components/FiltersPane/components/FilterWrapper/FilterWrapper.d.ts +2 -2
- package/dist/components/FiltersPane/types.d.ts +15 -5
- package/dist/components/Flag/customFlags/customFlags.d.ts +10 -0
- package/dist/components/Flag/customFlags/index.d.ts +1 -0
- package/dist/components/FlexibleTable/FlexibleTable.d.ts +4 -2
- package/dist/components/FlexibleTable/components/FlexibleTableRow/FlexibleTableRow.d.ts +6 -6
- package/dist/components/FlexibleTable/constants.d.ts +18 -2
- package/dist/components/FlexibleTable/types.d.ts +1 -1
- package/dist/components/Input/Input.d.ts +3 -3
- package/dist/components/Input/Input.stories.d.ts +2 -2
- package/dist/components/Input/Input.styles.d.ts +3 -3
- package/dist/components/List/List.d.ts +1 -1
- package/dist/components/List/index.d.ts +2 -1
- package/dist/components/List/types.d.ts +4 -0
- package/dist/components/SearchInput/SearchInput.d.ts +2 -2
- package/dist/components/SearchInput/SearchInput.stories.d.ts +3 -12
- package/dist/components/SearchInput/SearchInput.styles.d.ts +3 -5
- package/dist/components/Select/Select.d.ts +5 -3
- package/dist/components/Select/Select.styles.d.ts +8 -8
- package/dist/components/Select/index.d.ts +1 -1
- package/dist/components/TextArea/TextArea.d.ts +2 -2
- package/dist/components/TextArea/TextArea.styles.d.ts +3 -3
- package/dist/components/Tooltip/Tooltip.d.ts +1 -1
- package/dist/components/Tooltip/Tooltip.styles.d.ts +1 -1
- package/dist/components/WithMessages/WithMessages.d.ts +10 -0
- package/dist/components/{ControlGroup/ControlGroup.stories.d.ts → WithMessages/WithMessages.stories.d.ts} +2 -2
- package/dist/components/WithMessages/WithMessages.styles.d.ts +3 -0
- package/dist/components/WithMessages/index.d.ts +2 -0
- package/dist/components/WithPopup/WithPopup.d.ts +21 -6
- package/dist/components/WithPopup/WithPopup.styles.d.ts +1 -1
- package/dist/components/WithPopup/helpers.d.ts +2 -0
- package/dist/components/WithPopup/types.d.ts +3 -0
- package/dist/components/WithTooltip/WithTooltip.styles.d.ts +1 -0
- package/dist/components/index.d.ts +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/use-merge.d.ts +1 -0
- package/dist/hooks/use-mixed-styles.d.ts +3 -1
- package/dist/hooks/use-tweak-styles.d.ts +5 -5
- package/dist/theme/Provider.d.ts +6 -3
- package/dist/theme/common.d.ts +4 -2
- package/dist/theme/create-themed-styles.d.ts +2 -0
- package/dist/theme/helpers.d.ts +9 -3
- package/dist/theme/index.d.ts +2 -0
- package/dist/theme/true-jss/ThemedStylesManager.d.ts +18 -0
- package/dist/theme/true-jss/TweakStylesManager.d.ts +34 -0
- package/dist/theme/true-jss/index.d.ts +2 -0
- package/dist/theme/true-jss/jss-context.d.ts +9 -0
- package/dist/theme/types.d.ts +6 -4
- package/dist/true-react-common-ui-kit.js +7304 -6380
- package/dist/true-react-common-ui-kit.js.map +1 -1
- package/dist/true-react-common-ui-kit.umd.cjs +7071 -6148
- package/dist/true-react-common-ui-kit.umd.cjs.map +1 -1
- package/dist/types.d.ts +2 -1
- package/package.json +1 -1
- package/src/components/ControlWrapper/ControlWrapper.styles.ts +5 -5
- package/src/components/ControlWrapper/ControlWrapper.tsx +1 -1
- package/src/components/DatePicker/DatePicker.tsx +9 -4
- package/src/components/DatePicker/components/DatePickerHeader/DatePickerHeader.styles.ts +1 -1
- package/src/components/DatePicker/helpers.ts +13 -1
- package/src/components/DatePicker/types.ts +4 -1
- package/src/components/FiltersPane/FiltersPane.stories.tsx +4 -2
- package/src/components/FiltersPane/FiltersPane.tsx +14 -9
- package/src/components/FiltersPane/components/Filter/Filter.tsx +24 -17
- package/src/components/FiltersPane/components/Filter/helpers.ts +18 -0
- package/src/components/FiltersPane/components/FilterInterval/FilterInterval.styles.ts +1 -1
- package/src/components/FiltersPane/components/FilterInterval/FilterInterval.tsx +6 -1
- package/src/components/FiltersPane/components/FilterSelect/FilterSelect.styles.ts +2 -2
- package/src/components/FiltersPane/components/FilterValueView/FilterValueView.tsx +27 -22
- package/src/components/FiltersPane/components/FilterWithDates/FilterWithDates.styles.ts +1 -0
- package/src/components/FiltersPane/components/FilterWithPeriod/FilterWithPeriod.tsx +1 -1
- package/src/components/FiltersPane/components/FilterWrapper/FilterWrapper.tsx +7 -5
- package/src/components/FiltersPane/components/FiltersPaneSearch/FiltersPaneSearch.styles.ts +8 -2
- package/src/components/FiltersPane/types.ts +23 -5
- package/src/components/Flag/Flag.stories.tsx +2 -1
- package/src/components/Flag/Flag.styles.ts +4 -0
- package/src/components/Flag/Flag.tsx +23 -9
- package/src/components/Flag/customFlags/AB.svg +1 -0
- package/src/components/Flag/customFlags/OS.svg +1 -0
- package/src/components/Flag/customFlags/augment.d.ts +1 -0
- package/src/components/Flag/customFlags/customFlags.ts +13 -0
- package/src/components/Flag/customFlags/index.ts +1 -0
- package/src/components/FlexibleTable/FlexibleTable.tsx +13 -12
- package/src/components/FlexibleTable/components/FlexibleTableRow/FlexibleTableRow.tsx +9 -8
- package/src/components/FlexibleTable/constants.ts +6 -3
- package/src/components/FlexibleTable/types.ts +1 -5
- package/src/components/IncrementInput/IncrementInput.styles.ts +1 -1
- package/src/components/Input/Input.styles.ts +5 -2
- package/src/components/Input/Input.tsx +9 -8
- package/src/components/Input/InputBase.tsx +2 -1
- package/src/components/List/List.tsx +5 -2
- package/src/components/List/index.ts +2 -1
- package/src/components/List/types.ts +5 -0
- package/src/components/MultiSelectList/MultiSelectList.styles.ts +1 -1
- package/src/components/PhoneInput/PhoneInput.stories.tsx +2 -1
- package/src/components/PhoneInput/PhoneInput.styles.ts +2 -2
- package/src/components/PhoneInput/PhoneInput.tsx +5 -2
- package/src/components/PhoneInput/components/PhoneInputCountryList/PhoneInputCountryList.styles.ts +1 -1
- package/src/components/SearchInput/SearchInput.styles.ts +17 -30
- package/src/components/SearchInput/SearchInput.tsx +17 -30
- package/src/components/Select/CustomSelect.stories.tsx +2 -2
- package/src/components/Select/Select.styles.ts +8 -2
- package/src/components/Select/Select.tsx +19 -31
- package/src/components/Select/components/SelectList/SelectList.tsx +1 -1
- package/src/components/Select/index.ts +1 -1
- package/src/components/TextArea/TextArea.styles.ts +7 -3
- package/src/components/TextArea/TextArea.tsx +16 -11
- package/src/components/Tooltip/Tooltip.styles.ts +2 -0
- package/src/components/Tooltip/Tooltip.tsx +1 -1
- package/src/components/{ControlGroup/ControlGroup.stories.tsx → WithMessages/WithMessages.stories.tsx} +10 -10
- package/src/components/{ControlGroup/ControlGroup.styles.ts → WithMessages/WithMessages.styles.ts} +4 -3
- package/src/components/{ControlGroup/ControlGroup.tsx → WithMessages/WithMessages.tsx} +13 -9
- package/src/components/WithMessages/index.ts +2 -0
- package/src/components/WithPopup/WithPopup.stories.tsx +1 -0
- package/src/components/WithPopup/WithPopup.styles.ts +2 -0
- package/src/components/WithPopup/WithPopup.tsx +64 -16
- package/src/components/WithPopup/helpers.ts +9 -0
- package/src/components/WithPopup/types.ts +7 -0
- package/src/components/WithTooltip/WithTooltip.styles.ts +6 -0
- package/src/components/WithTooltip/WithTooltip.tsx +7 -2
- package/src/components/index.ts +1 -1
- package/src/constants/phone-info.ts +20 -33
- package/src/helpers/phone.ts +19 -15
- package/src/hooks/index.ts +1 -0
- package/src/hooks/use-merge.ts +8 -0
- package/src/hooks/use-mixed-styles.ts +9 -11
- package/src/hooks/use-tweak-styles.ts +49 -27
- package/src/theme/Provider.tsx +10 -5
- package/src/theme/common.ts +5 -2
- package/src/theme/create-themed-styles.ts +78 -0
- package/src/theme/helpers.ts +39 -39
- package/src/theme/index.ts +2 -0
- package/src/theme/true-jss/ThemedStylesManager.ts +92 -0
- package/src/theme/true-jss/TweakStylesManager.ts +157 -0
- package/src/theme/true-jss/index.ts +2 -0
- package/src/theme/true-jss/jss-context.tsx +34 -0
- package/src/theme/types.ts +6 -4
- package/src/types.ts +2 -1
- package/dist/components/ControlGroup/ControlGroup.d.ts +0 -10
- package/dist/components/ControlGroup/ControlGroup.styles.d.ts +0 -3
- package/dist/components/ControlGroup/index.d.ts +0 -2
- package/src/components/ControlGroup/index.ts +0 -2
|
@@ -4,7 +4,7 @@ import { useTweakStyles } from '../../hooks';
|
|
|
4
4
|
import { ICommonProps } from '../../types';
|
|
5
5
|
import { ITooltipProps, Tooltip } from '../Tooltip';
|
|
6
6
|
import { IWithPopupProps, WithPopup } from '../WithPopup';
|
|
7
|
-
import { IWithTooltipStyles } from './WithTooltip.styles';
|
|
7
|
+
import { IWithTooltipStyles, withPopupStyles } from './WithTooltip.styles';
|
|
8
8
|
|
|
9
9
|
export interface IWithTooltipProps
|
|
10
10
|
extends Omit<
|
|
@@ -32,17 +32,21 @@ export const WithTooltip: FC<IWithTooltipProps> = ({
|
|
|
32
32
|
tooltipView = 'tooltip',
|
|
33
33
|
tooltipType = 'info',
|
|
34
34
|
isDisabled = false,
|
|
35
|
+
popupData,
|
|
35
36
|
tweakStyles,
|
|
36
37
|
...restProps
|
|
37
38
|
}) => {
|
|
38
39
|
const tweakWithPopupStyles = useTweakStyles({
|
|
40
|
+
innerStyles: withPopupStyles,
|
|
39
41
|
tweakStyles,
|
|
40
42
|
className: 'tweakWithPopup',
|
|
43
|
+
currentComponentName: 'WithTooltip',
|
|
41
44
|
});
|
|
42
45
|
|
|
43
46
|
const tweakTooltipStyles = useTweakStyles({
|
|
44
47
|
tweakStyles,
|
|
45
48
|
className: 'tweakTooltip',
|
|
49
|
+
currentComponentName: 'WithTooltip',
|
|
46
50
|
});
|
|
47
51
|
|
|
48
52
|
return (
|
|
@@ -50,8 +54,9 @@ export const WithTooltip: FC<IWithTooltipProps> = ({
|
|
|
50
54
|
trigger={children}
|
|
51
55
|
placement={placement}
|
|
52
56
|
eventType={eventType}
|
|
53
|
-
|
|
57
|
+
popupData={{ ...popupData, tooltipView }}
|
|
54
58
|
isDisabled={isDisabled || !isReactNodeNotEmpty(tooltipText)}
|
|
59
|
+
isTriggerWrapped
|
|
55
60
|
tweakStyles={tweakWithPopupStyles}
|
|
56
61
|
{...restProps}
|
|
57
62
|
>
|
package/src/components/index.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import type { IPhoneInfo } from '../components';
|
|
2
2
|
|
|
3
3
|
export const phoneInfo: IPhoneInfo[] = [
|
|
4
|
+
{
|
|
5
|
+
countryEn: 'Abkhazia',
|
|
6
|
+
countryRu: 'Абхазия',
|
|
7
|
+
countryCode: 'AB',
|
|
8
|
+
phoneMask: '(999) 999-99-99',
|
|
9
|
+
dialCode: '7',
|
|
10
|
+
dialCodePriority: 1,
|
|
11
|
+
fullCodes: ['7'],
|
|
12
|
+
},
|
|
4
13
|
{
|
|
5
14
|
countryEn: 'Afghanistan',
|
|
6
15
|
countryRu: 'Афганистан',
|
|
@@ -785,40 +794,9 @@ export const phoneInfo: IPhoneInfo[] = [
|
|
|
785
794
|
countryRu: 'Казахстан',
|
|
786
795
|
countryCode: 'KZ',
|
|
787
796
|
dialCode: '7',
|
|
788
|
-
phoneMask: '999 999-99-99',
|
|
797
|
+
phoneMask: '(999) 999-99-99',
|
|
789
798
|
dialCodePriority: 1,
|
|
790
|
-
|
|
791
|
-
'310',
|
|
792
|
-
'311',
|
|
793
|
-
'312',
|
|
794
|
-
'313',
|
|
795
|
-
'315',
|
|
796
|
-
'318',
|
|
797
|
-
'321',
|
|
798
|
-
'324',
|
|
799
|
-
'325',
|
|
800
|
-
'326',
|
|
801
|
-
'327',
|
|
802
|
-
'336',
|
|
803
|
-
'7172',
|
|
804
|
-
'73622',
|
|
805
|
-
],
|
|
806
|
-
fullCodes: [
|
|
807
|
-
'7310',
|
|
808
|
-
'7311',
|
|
809
|
-
'7312',
|
|
810
|
-
'7313',
|
|
811
|
-
'7315',
|
|
812
|
-
'7318',
|
|
813
|
-
'7321',
|
|
814
|
-
'7324',
|
|
815
|
-
'7325',
|
|
816
|
-
'7326',
|
|
817
|
-
'7327',
|
|
818
|
-
'7336',
|
|
819
|
-
'77172',
|
|
820
|
-
'773622',
|
|
821
|
-
],
|
|
799
|
+
fullCodes: ['7'],
|
|
822
800
|
},
|
|
823
801
|
{
|
|
824
802
|
countryEn: 'Kenya',
|
|
@@ -1404,6 +1382,15 @@ export const phoneInfo: IPhoneInfo[] = [
|
|
|
1404
1382
|
phoneMask: '999 9999 9999',
|
|
1405
1383
|
fullCodes: ['82'],
|
|
1406
1384
|
},
|
|
1385
|
+
{
|
|
1386
|
+
countryCode: 'OS',
|
|
1387
|
+
countryEn: 'South Ossetia',
|
|
1388
|
+
countryRu: 'Южная Осетия',
|
|
1389
|
+
phoneMask: '(999) 999-99-99',
|
|
1390
|
+
dialCode: '7',
|
|
1391
|
+
dialCodePriority: 1,
|
|
1392
|
+
fullCodes: ['7'],
|
|
1393
|
+
},
|
|
1407
1394
|
{
|
|
1408
1395
|
countryEn: 'South Sudan',
|
|
1409
1396
|
countryRu: 'Южный Судан',
|
package/src/helpers/phone.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isNotEmpty,
|
|
1
|
+
import { isNotEmpty, isStringEmpty } from '@true-engineering/true-react-platform-helpers';
|
|
2
2
|
import type { IPhoneInfo, IPhoneValue } from '../components';
|
|
3
3
|
import { phoneInfo } from '../constants';
|
|
4
4
|
|
|
@@ -46,22 +46,26 @@ export const getFullPhone = (phone?: IPhoneValue): string =>
|
|
|
46
46
|
(phone?.dialCode ?? '') + (phone?.phoneNumber ?? '');
|
|
47
47
|
|
|
48
48
|
export const getCountryCodeFromPhone = (phoneWithCode: string): string | undefined => {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
info.fullCodes.some((code) => phoneWithCode.startsWith(code)),
|
|
52
|
-
)?.countryCode;
|
|
53
|
-
|
|
54
|
-
if (isEmpty(countryCode) && isNotEmpty(phoneWithCode)) {
|
|
55
|
-
// если не нашли уникальный fullCode (dialCode + arealCode),
|
|
56
|
-
// то пробуем найти dialCode и выбираем с наименьшим Priority
|
|
57
|
-
countryCode = phoneInfo
|
|
58
|
-
.filter((info) => phoneWithCode.startsWith(info.dialCode))
|
|
59
|
-
.sort(
|
|
60
|
-
(infoA, infoB) => (infoA.dialCodePriority ?? 1000) - (infoB.dialCodePriority ?? 1000),
|
|
61
|
-
)[0]?.countryCode;
|
|
49
|
+
if (isStringEmpty(phoneWithCode)) {
|
|
50
|
+
return;
|
|
62
51
|
}
|
|
63
52
|
|
|
64
|
-
|
|
53
|
+
// ищем страны, для которых phoneWithCode начинается с fullCode (dialCode + areaCode)
|
|
54
|
+
const matchedCountries = phoneInfo.filter((info) =>
|
|
55
|
+
info.fullCodes.some((fullCode) => phoneWithCode.startsWith(fullCode)),
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
// если нашлась всего одна — ок, выдаём её
|
|
59
|
+
if (matchedCountries.length === 1) {
|
|
60
|
+
return matchedCountries[0].countryCode;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// если нашлось несколько, выбираем страну с наименьшим dialCodePriority (0 — самая приоритетная)
|
|
64
|
+
const highestPriorityCountries = phoneInfo
|
|
65
|
+
.filter((info) => phoneWithCode.startsWith(info.dialCode))
|
|
66
|
+
.sort((a, b) => (a.dialCodePriority ?? 1000) - (b.dialCodePriority ?? 1000));
|
|
67
|
+
|
|
68
|
+
return highestPriorityCountries.at(0)?.countryCode;
|
|
65
69
|
};
|
|
66
70
|
|
|
67
71
|
export const getPhoneObjFromString = (fullPhone: string, countryCode?: string): IPhoneValue => {
|
package/src/hooks/index.ts
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { isNotEmpty, mergeStyles } from '@true-engineering/true-react-platform-helpers';
|
|
3
|
+
|
|
4
|
+
export const useMerge = <T>(one?: T, two?: T): T | undefined =>
|
|
5
|
+
useMemo(
|
|
6
|
+
() => (isNotEmpty(one) && isNotEmpty(two) ? mergeStyles(one, two) : one ?? two),
|
|
7
|
+
[one, two],
|
|
8
|
+
);
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { isObject } from '@true-engineering/true-react-platform-helpers';
|
|
3
|
+
import type { IMixedStyles } from '../theme';
|
|
4
|
+
|
|
5
|
+
export const mixStyles = <T>(...tweakStyles: Array<IMixedStyles<T>>): Array<NonNullable<T>> =>
|
|
6
|
+
tweakStyles.flat().filter(isObject) as Array<NonNullable<T>>;
|
|
3
7
|
|
|
4
8
|
export const useMixedStyles = <StyleSheet>(
|
|
5
|
-
baseStyles?: StyleSheet
|
|
6
|
-
tweakStyles?: StyleSheet
|
|
7
|
-
): StyleSheet
|
|
8
|
-
useMemo(
|
|
9
|
-
() =>
|
|
10
|
-
isNotEmpty(baseStyles) && isNotEmpty(tweakStyles)
|
|
11
|
-
? mergeStyles(baseStyles, tweakStyles)
|
|
12
|
-
: baseStyles ?? tweakStyles,
|
|
13
|
-
[baseStyles, tweakStyles],
|
|
14
|
-
);
|
|
9
|
+
baseStyles?: IMixedStyles<StyleSheet>,
|
|
10
|
+
tweakStyles?: IMixedStyles<StyleSheet>,
|
|
11
|
+
): Array<NonNullable<StyleSheet>> =>
|
|
12
|
+
useMemo(() => mixStyles(baseStyles, tweakStyles), [baseStyles, tweakStyles]);
|
|
@@ -1,11 +1,24 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { useContext, useMemo } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
isArrayNotEmpty,
|
|
4
|
+
isNotEmpty,
|
|
5
|
+
mergeStyles,
|
|
6
|
+
} from '@true-engineering/true-react-platform-helpers';
|
|
7
|
+
import {
|
|
8
|
+
areStylesThemed,
|
|
9
|
+
themedStyles,
|
|
10
|
+
IComponentName,
|
|
11
|
+
IMaybeArray,
|
|
12
|
+
useTheme,
|
|
13
|
+
JssContext,
|
|
14
|
+
IMixedStyles,
|
|
15
|
+
} from '../theme';
|
|
16
|
+
import { mixStyles } from './use-mixed-styles';
|
|
4
17
|
|
|
5
18
|
// TODO: Можно усилить типы
|
|
6
19
|
export const useTweakStyles = <StyleSheet, ClassName extends keyof StyleSheet & `tweak${string}`>({
|
|
7
20
|
innerStyles,
|
|
8
|
-
tweakStyles
|
|
21
|
+
tweakStyles,
|
|
9
22
|
className,
|
|
10
23
|
currentComponentName,
|
|
11
24
|
}: {
|
|
@@ -13,12 +26,12 @@ export const useTweakStyles = <StyleSheet, ClassName extends keyof StyleSheet &
|
|
|
13
26
|
* Это tweakStyles, определенные в родительском компоненте
|
|
14
27
|
* (например, стили для Input, определенные в стилях компонента Select)
|
|
15
28
|
*/
|
|
16
|
-
innerStyles?: StyleSheet[ClassName]
|
|
29
|
+
innerStyles?: IMixedStyles<StyleSheet[ClassName]>;
|
|
17
30
|
/**
|
|
18
31
|
* Пропса tweakStyles из родительского компонента
|
|
19
32
|
* (это уже непосредственно ISelectProps.tweakStyles)
|
|
20
33
|
*/
|
|
21
|
-
tweakStyles?: StyleSheet
|
|
34
|
+
tweakStyles?: IMaybeArray<StyleSheet>;
|
|
22
35
|
/**
|
|
23
36
|
* Класс для переопределения tweakStyles из-вне. (Например, 'tweakInput')
|
|
24
37
|
*/
|
|
@@ -27,31 +40,40 @@ export const useTweakStyles = <StyleSheet, ClassName extends keyof StyleSheet &
|
|
|
27
40
|
* Название компонента который вызывает useTweakStyles. (В данном примере 'Select')
|
|
28
41
|
*/
|
|
29
42
|
currentComponentName?: IComponentName;
|
|
30
|
-
}): StyleSheet[ClassName] =>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
43
|
+
}): Array<NonNullable<StyleSheet[ClassName]>> => {
|
|
44
|
+
const theme = useTheme();
|
|
45
|
+
const isMergeDisabled = isNotEmpty(useContext(JssContext).tweakStylesArch);
|
|
46
|
+
|
|
47
|
+
return useMemo(() => {
|
|
34
48
|
const themeStyles = isNotEmpty(currentComponentName)
|
|
35
|
-
? (theme.components?.[currentComponentName]
|
|
49
|
+
? (theme.components?.[currentComponentName] as StyleSheet)
|
|
36
50
|
: undefined;
|
|
37
|
-
const tweakStyles = currentComponentTweakStyles?.[className];
|
|
38
51
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
52
|
+
const resultStyles = mixStyles(
|
|
53
|
+
innerStyles,
|
|
54
|
+
mixStyles(themeStyles, tweakStyles).map((style) => style[className]),
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
if (isMergeDisabled || resultStyles.length < 2) {
|
|
58
|
+
return resultStyles;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const [maybeInnerStyles, maybeThemeStyles, ...rest] = resultStyles;
|
|
62
|
+
|
|
63
|
+
if (
|
|
64
|
+
maybeThemeStyles !== themeStyles?.[className] || // Если нет themeStyles или innerStyles
|
|
65
|
+
isArrayNotEmpty(rest) // Или есть tweakStyles
|
|
66
|
+
) {
|
|
67
|
+
// Мёржим как есть
|
|
68
|
+
return [mergeStyles(maybeInnerStyles, maybeThemeStyles, ...rest)];
|
|
43
69
|
}
|
|
44
70
|
|
|
45
|
-
//
|
|
46
|
-
if (
|
|
47
|
-
|
|
71
|
+
// Иначе мёржим themeStyles в innerStyles
|
|
72
|
+
if (!areStylesThemed(maybeInnerStyles)) {
|
|
73
|
+
themedStyles(maybeInnerStyles, maybeThemeStyles);
|
|
48
74
|
}
|
|
49
75
|
|
|
50
|
-
//
|
|
51
|
-
return
|
|
52
|
-
}, [
|
|
53
|
-
|
|
54
|
-
className,
|
|
55
|
-
currentComponentName,
|
|
56
|
-
currentComponentTweakStyles,
|
|
57
|
-
]) as StyleSheet[ClassName];
|
|
76
|
+
// И возвращаем только innerStyles
|
|
77
|
+
return [maybeInnerStyles];
|
|
78
|
+
}, [innerStyles, className, currentComponentName, tweakStyles, theme, isMergeDisabled]);
|
|
79
|
+
};
|
package/src/theme/Provider.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createContext, FC, ReactNode } from 'react';
|
|
1
|
+
import { createContext, FC, ReactNode, useContext, useMemo } from 'react';
|
|
2
2
|
import { common } from './common';
|
|
3
|
-
import { IUiKitTheme } from './types';
|
|
3
|
+
import type { IUiKitTheme } from './types';
|
|
4
4
|
|
|
5
5
|
export interface IThemedProviderProps {
|
|
6
6
|
theme: IUiKitTheme;
|
|
@@ -11,11 +11,16 @@ let globalTheme: IUiKitTheme;
|
|
|
11
11
|
|
|
12
12
|
export const getTheme = (): IUiKitTheme => globalTheme;
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
interface ThemeContextValue {
|
|
15
15
|
theme: IUiKitTheme;
|
|
16
|
-
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const ThemeContext = createContext<ThemeContextValue>({ theme: common });
|
|
17
19
|
|
|
18
20
|
export const ThemeProvider: FC<IThemedProviderProps> = ({ theme, children }) => {
|
|
19
21
|
globalTheme = theme;
|
|
20
|
-
|
|
22
|
+
const value: ThemeContextValue = useMemo(() => ({ theme }), [theme]);
|
|
23
|
+
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
|
|
21
24
|
};
|
|
25
|
+
|
|
26
|
+
export const useTheme = (): IUiKitTheme => useContext(ThemeContext).theme;
|
package/src/theme/common.ts
CHANGED
|
@@ -91,9 +91,12 @@ export const helpers = {
|
|
|
91
91
|
|
|
92
92
|
// Chromium
|
|
93
93
|
'@supports selector(::-webkit-scrollbar)': {
|
|
94
|
+
'--webkit-scrollbar-width': '10px',
|
|
95
|
+
'--webkit-scrollbar-height': '10px',
|
|
96
|
+
|
|
94
97
|
'&::-webkit-scrollbar': {
|
|
95
|
-
|
|
96
|
-
|
|
98
|
+
width: 'var(--webkit-scrollbar-width)',
|
|
99
|
+
height: 'var(--webkit-scrollbar-height)',
|
|
97
100
|
|
|
98
101
|
'&-thumb': {
|
|
99
102
|
width: 6,
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { useContext, useInsertionEffect, useMemo } from 'react';
|
|
2
|
+
import { createUseStyles, Styles } from 'react-jss';
|
|
3
|
+
import { isNotEmpty, mergeStyles } from '@true-engineering/true-react-platform-helpers';
|
|
4
|
+
import { mixStyles } from '../hooks/use-mixed-styles';
|
|
5
|
+
import { getTheme, useTheme } from './Provider';
|
|
6
|
+
import {
|
|
7
|
+
checkStyles,
|
|
8
|
+
cleanStyles,
|
|
9
|
+
getTweakStylesCache,
|
|
10
|
+
isStylesNotEmpty,
|
|
11
|
+
mergeTweakStyles,
|
|
12
|
+
} from './helpers';
|
|
13
|
+
import { ThemedStylesManager, JssContext } from './true-jss';
|
|
14
|
+
import { IComponentName, IStyles, IUseStyles } from './types';
|
|
15
|
+
|
|
16
|
+
const DEFAULT_NAME = 'LocalComponent';
|
|
17
|
+
|
|
18
|
+
export function createThemedStyles<C extends string>(
|
|
19
|
+
...args: [IStyles<C>] | [IComponentName, IStyles<C>]
|
|
20
|
+
): IUseStyles<C> {
|
|
21
|
+
const [componentName, styles] = args.length === 2 ? args : [undefined, args[0]];
|
|
22
|
+
const name = componentName ?? DEFAULT_NAME;
|
|
23
|
+
|
|
24
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
25
|
+
checkStyles(name, styles);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const tweakStylesManager = new ThemedStylesManager({ styles, name });
|
|
29
|
+
const tweakStylesCache = getTweakStylesCache();
|
|
30
|
+
|
|
31
|
+
const useStyles = createUseStyles<C>((tweakStyles) => {
|
|
32
|
+
const theme = getTheme();
|
|
33
|
+
return mergeStyles(
|
|
34
|
+
styles as Styles<C>,
|
|
35
|
+
isNotEmpty(componentName) ? (theme?.components?.[componentName] as Styles<C>) : undefined,
|
|
36
|
+
tweakStyles,
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return (data) => {
|
|
41
|
+
const jssContext = useContext(JssContext);
|
|
42
|
+
|
|
43
|
+
const tweakStyles = useMemo(
|
|
44
|
+
() => mixStyles(data?.theme).filter(isStylesNotEmpty),
|
|
45
|
+
[data?.theme],
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
if (jssContext.tweakStylesArch !== 'true-jss') {
|
|
49
|
+
const tweakStylesStrategy =
|
|
50
|
+
jssContext.tweakStylesArch === 'react-jss' ? tweakStylesCache : mergeTweakStyles;
|
|
51
|
+
|
|
52
|
+
const theme = useMemo(
|
|
53
|
+
() => cleanStyles(tweakStylesStrategy(tweakStyles)),
|
|
54
|
+
[tweakStylesStrategy, tweakStyles],
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
return useStyles(isNotEmpty(data) ? { ...data, theme } : data);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const { components } = useTheme();
|
|
61
|
+
|
|
62
|
+
const themeStyles = isNotEmpty(componentName) ? components?.[componentName] : undefined;
|
|
63
|
+
|
|
64
|
+
const classes = tweakStylesManager.getClasses(themeStyles, tweakStyles, jssContext);
|
|
65
|
+
|
|
66
|
+
useInsertionEffect(() => {
|
|
67
|
+
const unmanage = tweakStylesManager.manage(themeStyles);
|
|
68
|
+
return unmanage;
|
|
69
|
+
}, [themeStyles]);
|
|
70
|
+
|
|
71
|
+
useInsertionEffect(() => {
|
|
72
|
+
const unmanage = tweakStylesManager.manageTweak(themeStyles, tweakStyles);
|
|
73
|
+
return unmanage;
|
|
74
|
+
}, [themeStyles, classes]);
|
|
75
|
+
|
|
76
|
+
return classes;
|
|
77
|
+
};
|
|
78
|
+
}
|
package/src/theme/helpers.ts
CHANGED
|
@@ -1,29 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import merge from 'lodash-es/merge';
|
|
1
|
+
import { merge } from 'lodash-es';
|
|
3
2
|
import {
|
|
4
3
|
isArrayNotEmpty,
|
|
5
4
|
isNotEmpty,
|
|
6
5
|
mergeStyles,
|
|
7
6
|
} from '@true-engineering/true-react-platform-helpers';
|
|
8
|
-
import {
|
|
9
|
-
import { IComponentName, IStyles, IUseStyles } from './types';
|
|
7
|
+
import { IMaybeArray } from './types';
|
|
10
8
|
|
|
11
9
|
const EMPTY_STYLES = {};
|
|
12
10
|
|
|
13
|
-
const isTweakStyle = (key: string): boolean => key.startsWith('tweak');
|
|
11
|
+
export const isTweakStyle = (key: string): boolean => key.startsWith('tweak');
|
|
14
12
|
|
|
15
|
-
const
|
|
16
|
-
isNotEmpty(tweakStyles) && Object.keys(tweakStyles).
|
|
17
|
-
? tweakStyles
|
|
18
|
-
: (EMPTY_STYLES as T);
|
|
13
|
+
export const isStylesNotEmpty = <T>(tweakStyles?: T): tweakStyles is NonNullable<T> =>
|
|
14
|
+
isNotEmpty(tweakStyles) && !Object.keys(tweakStyles).every(isTweakStyle);
|
|
19
15
|
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return
|
|
26
|
-
}
|
|
16
|
+
export const cleanStyles = <T>(tweakStyles?: T): T =>
|
|
17
|
+
isStylesNotEmpty(tweakStyles) ? tweakStyles : (EMPTY_STYLES as T);
|
|
18
|
+
|
|
19
|
+
export const mergeTweakStyles = <T>(tweakStyles?: IMaybeArray<T>): T | undefined => {
|
|
20
|
+
if (!Array.isArray(tweakStyles)) {
|
|
21
|
+
return tweakStyles;
|
|
22
|
+
}
|
|
23
|
+
const [first, ...rest] = tweakStyles;
|
|
24
|
+
return isArrayNotEmpty(rest) ? mergeStyles(first, ...rest) : first;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const checkStyles = (componentName: string, styles: Record<string, unknown>): void => {
|
|
28
|
+
const invalidClasses = Object.keys(styles).filter(isTweakStyle);
|
|
27
29
|
|
|
28
30
|
if (isArrayNotEmpty(invalidClasses)) {
|
|
29
31
|
console.error(
|
|
@@ -47,30 +49,28 @@ export const themedStyles = <T>(styles: T, themeComponentStyles: T): T => {
|
|
|
47
49
|
return styles;
|
|
48
50
|
};
|
|
49
51
|
|
|
50
|
-
|
|
52
|
+
type TweakStylesCache = (styles: object[], prev?: object[]) => object | undefined;
|
|
53
|
+
export const getTweakStylesCache = (): TweakStylesCache => {
|
|
54
|
+
let mergedStyles: object | undefined;
|
|
55
|
+
const cache = new WeakMap<object, TweakStylesCache>();
|
|
51
56
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
const getNext = (next: object) => {
|
|
58
|
+
if (!cache.has(next)) {
|
|
59
|
+
cache.set(next, getTweakStylesCache());
|
|
60
|
+
}
|
|
61
|
+
return cache.get(next)!; // eslint-disable-line @typescript-eslint/no-non-null-assertion
|
|
62
|
+
};
|
|
56
63
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
64
|
+
return (styles, prev = []) => {
|
|
65
|
+
const [next, ...rest] = styles;
|
|
66
|
+
if (isNotEmpty(next)) {
|
|
67
|
+
return getNext(next)(rest, prev.concat(next));
|
|
68
|
+
}
|
|
62
69
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const useStyles = createUseStyles<C, P>((tweakStyles) => {
|
|
67
|
-
const theme = getTheme();
|
|
68
|
-
return mergeStyles(
|
|
69
|
-
styles as Styles<C, P>,
|
|
70
|
-
isNotEmpty(componentName) ? (theme?.components?.[componentName] as Styles<C, P>) : undefined,
|
|
71
|
-
tweakStyles,
|
|
72
|
-
);
|
|
73
|
-
});
|
|
70
|
+
if (isNotEmpty(mergedStyles)) {
|
|
71
|
+
return mergedStyles;
|
|
72
|
+
}
|
|
74
73
|
|
|
75
|
-
|
|
76
|
-
}
|
|
74
|
+
return (mergedStyles = mergeTweakStyles(prev));
|
|
75
|
+
};
|
|
76
|
+
};
|
package/src/theme/index.ts
CHANGED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { jss } from 'react-jss';
|
|
2
|
+
import type { Classes, StyleSheet } from 'jss';
|
|
3
|
+
import { isNotEmpty, mergeStyles } from '@true-engineering/true-react-platform-helpers';
|
|
4
|
+
import { IStyles } from '../types';
|
|
5
|
+
import { IPartialStyle, TweakStylesManager } from './TweakStylesManager';
|
|
6
|
+
import { IJssContext } from './jss-context';
|
|
7
|
+
|
|
8
|
+
interface IStyleSheet<C extends string> {
|
|
9
|
+
manager: TweakStylesManager<C>;
|
|
10
|
+
refs: number;
|
|
11
|
+
sheet: StyleSheet<C>;
|
|
12
|
+
detachTimeout?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const NO_THEME_STYLES: IPartialStyle = {};
|
|
16
|
+
|
|
17
|
+
interface IThemedStylesManagerOptions<C extends string> {
|
|
18
|
+
styles: IStyles<C>;
|
|
19
|
+
name: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class ThemedStylesManager<C extends string> {
|
|
23
|
+
#styleSheetMap = new Map<IPartialStyle, IStyleSheet<C>>();
|
|
24
|
+
#styles: IStyles<C>;
|
|
25
|
+
#name: string;
|
|
26
|
+
|
|
27
|
+
constructor({ styles, name }: IThemedStylesManagerOptions<C>) {
|
|
28
|
+
this.#styles = styles;
|
|
29
|
+
this.#name = name;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public getClasses(
|
|
33
|
+
theme = NO_THEME_STYLES,
|
|
34
|
+
tweak: IPartialStyle[],
|
|
35
|
+
jssContext: IJssContext,
|
|
36
|
+
): Classes<C> {
|
|
37
|
+
return this.getOrCreate(theme, jssContext).manager.getClasses(tweak);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public manageTweak(theme = NO_THEME_STYLES, tweak: IPartialStyle[]): VoidFunction | undefined {
|
|
41
|
+
this.#styleSheetMap.get(theme)?.manager.manage(tweak);
|
|
42
|
+
|
|
43
|
+
return () => this.#styleSheetMap.get(theme)?.manager.unmanage(tweak);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public manage(theme = NO_THEME_STYLES): VoidFunction | undefined {
|
|
47
|
+
const value = this.#styleSheetMap.get(theme);
|
|
48
|
+
if (!isNotEmpty(value)) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (isNotEmpty(value.detachTimeout)) {
|
|
52
|
+
clearTimeout(value.detachTimeout);
|
|
53
|
+
value.detachTimeout = undefined;
|
|
54
|
+
}
|
|
55
|
+
value.refs += 1;
|
|
56
|
+
if (value.refs > 0) {
|
|
57
|
+
value.sheet.attach();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return () => this.unmanage(theme);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private unmanage(theme = NO_THEME_STYLES): void {
|
|
64
|
+
const value = this.#styleSheetMap.get(theme);
|
|
65
|
+
if (!isNotEmpty(value) || value.refs === 0) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
value.refs -= 1;
|
|
69
|
+
if (value.refs === 0 && !isNotEmpty(value.detachTimeout)) {
|
|
70
|
+
value.detachTimeout = window.setTimeout(() => {
|
|
71
|
+
if (value.refs === 0) {
|
|
72
|
+
value.sheet.detach();
|
|
73
|
+
}
|
|
74
|
+
}, 100);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private getOrCreate(theme: IPartialStyle, jssContext: IJssContext): IStyleSheet<C> {
|
|
79
|
+
if (!this.#styleSheetMap.has(theme)) {
|
|
80
|
+
const sheet = jss.createStyleSheet(mergeStyles(this.#styles, theme), {
|
|
81
|
+
link: true,
|
|
82
|
+
meta: this.#name,
|
|
83
|
+
generateId: jssContext.generateId,
|
|
84
|
+
});
|
|
85
|
+
const classes = { ...sheet.classes };
|
|
86
|
+
const manager = new TweakStylesManager({ sheet, classes });
|
|
87
|
+
this.#styleSheetMap.set(theme, { sheet, manager, refs: 0 });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return this.#styleSheetMap.get(theme)!; // eslint-disable-line @typescript-eslint/no-non-null-assertion
|
|
91
|
+
}
|
|
92
|
+
}
|