@serhii.olishevskyi/docs 1.1.6 → 1.1.7
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/dist/index.d.mts +37 -2
- package/dist/index.d.ts +37 -2
- package/dist/index.js +334 -15
- package/dist/index.mjs +340 -15
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React$1 from 'react';
|
|
2
2
|
import React__default, { ReactNode } from 'react';
|
|
3
|
-
import { TextFieldProps, IconButtonProps, TooltipProps, SxProps, Theme } from '@mui/material';
|
|
3
|
+
import { TextFieldProps, SelectProps, SelectChangeEvent, IconButtonProps, TooltipProps, SxProps, Theme } from '@mui/material';
|
|
4
4
|
import * as _supabase_supabase_js from '@supabase/supabase-js';
|
|
5
5
|
import { SupabaseClient, User, Session } from '@supabase/supabase-js';
|
|
6
6
|
|
|
@@ -70,6 +70,39 @@ type EmailInputComponentProps = Omit<TextFieldComponentProps, 'type'> & {
|
|
|
70
70
|
onValidationChange?: (isValid: boolean) => void;
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
+
interface SearchComponentProps extends Omit<TextFieldProps, 'placeholder'> {
|
|
74
|
+
overrideNamespace?: string;
|
|
75
|
+
label?: ReactNode;
|
|
76
|
+
placeholderKey?: string;
|
|
77
|
+
clearTooltip?: string;
|
|
78
|
+
onClear?: () => void;
|
|
79
|
+
debounceDelay?: number;
|
|
80
|
+
onDebounceChange?: (value: string) => void;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
interface SelectOption<T = string> {
|
|
84
|
+
value: T;
|
|
85
|
+
label: React__default.ReactNode;
|
|
86
|
+
isItalic?: boolean;
|
|
87
|
+
}
|
|
88
|
+
interface SelectComponentProps<T = string> extends Omit<SelectProps<T | T[]>, 'onChange' | 'value'> {
|
|
89
|
+
overrideNamespace?: string;
|
|
90
|
+
label: React__default.ReactNode;
|
|
91
|
+
value: T | T[];
|
|
92
|
+
options: SelectOption<T>[];
|
|
93
|
+
onChange?: (event: SelectChangeEvent<T | T[]>, child: React__default.ReactNode) => void;
|
|
94
|
+
id?: string;
|
|
95
|
+
fullWidth?: boolean;
|
|
96
|
+
size?: 'small' | 'medium';
|
|
97
|
+
multiple?: boolean;
|
|
98
|
+
withCheckboxes?: boolean;
|
|
99
|
+
clearable?: boolean;
|
|
100
|
+
maxSelect?: number;
|
|
101
|
+
maxDisplayedTags?: number;
|
|
102
|
+
helperText?: ReactNode;
|
|
103
|
+
defaultValueOnClear?: T;
|
|
104
|
+
}
|
|
105
|
+
|
|
73
106
|
interface CopyClipboardButtonComponentProps extends Omit<IconButtonProps, 'onClick'> {
|
|
74
107
|
overrideNamespace?: string;
|
|
75
108
|
/** Текст, який буде скопійовано в буфер обміну */
|
|
@@ -196,6 +229,8 @@ declare const UI: {
|
|
|
196
229
|
TextField: React$1.FC<TextFieldComponentProps>;
|
|
197
230
|
NumberField: React$1.FC<NumberInputComponentProps>;
|
|
198
231
|
EmailField: React$1.FC<EmailInputComponentProps>;
|
|
232
|
+
Search: React$1.FC<SearchComponentProps>;
|
|
233
|
+
Select: <T extends string | number>({ overrideNamespace, label, value, options, onChange, id, fullWidth, size, multiple, withCheckboxes, clearable, maxSelect, disabled, maxDisplayedTags, helperText, defaultValueOnClear, sx, ...restProps }: SelectComponentProps<T>) => React$1.JSX.Element;
|
|
199
234
|
Url: typeof UrlComponent;
|
|
200
235
|
};
|
|
201
236
|
Buttons: {
|
|
@@ -534,4 +569,4 @@ declare const Hooks: {
|
|
|
534
569
|
readonly useDebounce: typeof useDebounce;
|
|
535
570
|
};
|
|
536
571
|
|
|
537
|
-
export { type AIConfig, type AIGenerateOptions, AIProvider, type AIProviderProps, type AIProviderType, AppSettingsProvider, AuthProvider, BreadcrumbProvider, type ConfirmOptions, type ConfirmResult, ConfirmationProvider, type ConfirmationProviderProps, type CopyClipboardButtonComponentProps
|
|
572
|
+
export { type AIConfig, type AIGenerateOptions, AIProvider, type AIProviderProps, type AIProviderType, AppSettingsProvider, AuthProvider, BreadcrumbProvider, type ConfirmOptions, type ConfirmResult, ConfirmationProvider, type ConfirmationProviderProps, type CopyClipboardButtonComponentProps, type DialogSeverity, type DisplayState, type EmailInputComponentProps, Hooks, type Language, LocalizationProvider, type MyAvatarComponentProps, type NumberInputComponentProps, Providers, type SearchComponentProps, type SelectComponentProps, Services, type SupabaseConfig, SupabaseProvider, type SupabaseProviderProps, type TextFieldComponentProps, type ThemeColors, type ThemeConfig, type ThemeMode, ThemeProvider, ToastProvider, type ToastType, type TranslatableTooltipComponentProps, TranslateProvider, TranslateText, TranslationEditProvider, type TypographyConfig, UI, type UrlComponentProps as UrlProps, type UserAvatarComponentProps, type UserGroupedSessions, type UserPopoverComponentProps, type UserRoleChipComponentProps, type UserSessionItem, UserSettingsProvider, type UserStatusChipComponentProps, useAI, useAppSettings, useAppTheme, useAuth, useBreadcrumb, useConfirmation, useLocalization, useSupabase, useToast, useTranslationEdit, useTranslationNamespace, useUserSettings };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React$1 from 'react';
|
|
2
2
|
import React__default, { ReactNode } from 'react';
|
|
3
|
-
import { TextFieldProps, IconButtonProps, TooltipProps, SxProps, Theme } from '@mui/material';
|
|
3
|
+
import { TextFieldProps, SelectProps, SelectChangeEvent, IconButtonProps, TooltipProps, SxProps, Theme } from '@mui/material';
|
|
4
4
|
import * as _supabase_supabase_js from '@supabase/supabase-js';
|
|
5
5
|
import { SupabaseClient, User, Session } from '@supabase/supabase-js';
|
|
6
6
|
|
|
@@ -70,6 +70,39 @@ type EmailInputComponentProps = Omit<TextFieldComponentProps, 'type'> & {
|
|
|
70
70
|
onValidationChange?: (isValid: boolean) => void;
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
+
interface SearchComponentProps extends Omit<TextFieldProps, 'placeholder'> {
|
|
74
|
+
overrideNamespace?: string;
|
|
75
|
+
label?: ReactNode;
|
|
76
|
+
placeholderKey?: string;
|
|
77
|
+
clearTooltip?: string;
|
|
78
|
+
onClear?: () => void;
|
|
79
|
+
debounceDelay?: number;
|
|
80
|
+
onDebounceChange?: (value: string) => void;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
interface SelectOption<T = string> {
|
|
84
|
+
value: T;
|
|
85
|
+
label: React__default.ReactNode;
|
|
86
|
+
isItalic?: boolean;
|
|
87
|
+
}
|
|
88
|
+
interface SelectComponentProps<T = string> extends Omit<SelectProps<T | T[]>, 'onChange' | 'value'> {
|
|
89
|
+
overrideNamespace?: string;
|
|
90
|
+
label: React__default.ReactNode;
|
|
91
|
+
value: T | T[];
|
|
92
|
+
options: SelectOption<T>[];
|
|
93
|
+
onChange?: (event: SelectChangeEvent<T | T[]>, child: React__default.ReactNode) => void;
|
|
94
|
+
id?: string;
|
|
95
|
+
fullWidth?: boolean;
|
|
96
|
+
size?: 'small' | 'medium';
|
|
97
|
+
multiple?: boolean;
|
|
98
|
+
withCheckboxes?: boolean;
|
|
99
|
+
clearable?: boolean;
|
|
100
|
+
maxSelect?: number;
|
|
101
|
+
maxDisplayedTags?: number;
|
|
102
|
+
helperText?: ReactNode;
|
|
103
|
+
defaultValueOnClear?: T;
|
|
104
|
+
}
|
|
105
|
+
|
|
73
106
|
interface CopyClipboardButtonComponentProps extends Omit<IconButtonProps, 'onClick'> {
|
|
74
107
|
overrideNamespace?: string;
|
|
75
108
|
/** Текст, який буде скопійовано в буфер обміну */
|
|
@@ -196,6 +229,8 @@ declare const UI: {
|
|
|
196
229
|
TextField: React$1.FC<TextFieldComponentProps>;
|
|
197
230
|
NumberField: React$1.FC<NumberInputComponentProps>;
|
|
198
231
|
EmailField: React$1.FC<EmailInputComponentProps>;
|
|
232
|
+
Search: React$1.FC<SearchComponentProps>;
|
|
233
|
+
Select: <T extends string | number>({ overrideNamespace, label, value, options, onChange, id, fullWidth, size, multiple, withCheckboxes, clearable, maxSelect, disabled, maxDisplayedTags, helperText, defaultValueOnClear, sx, ...restProps }: SelectComponentProps<T>) => React$1.JSX.Element;
|
|
199
234
|
Url: typeof UrlComponent;
|
|
200
235
|
};
|
|
201
236
|
Buttons: {
|
|
@@ -534,4 +569,4 @@ declare const Hooks: {
|
|
|
534
569
|
readonly useDebounce: typeof useDebounce;
|
|
535
570
|
};
|
|
536
571
|
|
|
537
|
-
export { type AIConfig, type AIGenerateOptions, AIProvider, type AIProviderProps, type AIProviderType, AppSettingsProvider, AuthProvider, BreadcrumbProvider, type ConfirmOptions, type ConfirmResult, ConfirmationProvider, type ConfirmationProviderProps, type CopyClipboardButtonComponentProps
|
|
572
|
+
export { type AIConfig, type AIGenerateOptions, AIProvider, type AIProviderProps, type AIProviderType, AppSettingsProvider, AuthProvider, BreadcrumbProvider, type ConfirmOptions, type ConfirmResult, ConfirmationProvider, type ConfirmationProviderProps, type CopyClipboardButtonComponentProps, type DialogSeverity, type DisplayState, type EmailInputComponentProps, Hooks, type Language, LocalizationProvider, type MyAvatarComponentProps, type NumberInputComponentProps, Providers, type SearchComponentProps, type SelectComponentProps, Services, type SupabaseConfig, SupabaseProvider, type SupabaseProviderProps, type TextFieldComponentProps, type ThemeColors, type ThemeConfig, type ThemeMode, ThemeProvider, ToastProvider, type ToastType, type TranslatableTooltipComponentProps, TranslateProvider, TranslateText, TranslationEditProvider, type TypographyConfig, UI, type UrlComponentProps as UrlProps, type UserAvatarComponentProps, type UserGroupedSessions, type UserPopoverComponentProps, type UserRoleChipComponentProps, type UserSessionItem, UserSettingsProvider, type UserStatusChipComponentProps, useAI, useAppSettings, useAppTheme, useAuth, useBreadcrumb, useConfirmation, useLocalization, useSupabase, useToast, useTranslationEdit, useTranslationNamespace, useUserSettings };
|
package/dist/index.js
CHANGED
|
@@ -3979,12 +3979,346 @@ var PublicLanguageSelector = () => {
|
|
|
3979
3979
|
] });
|
|
3980
3980
|
};
|
|
3981
3981
|
|
|
3982
|
+
// src/UI/components/inputs/SearchComponent.tsx
|
|
3983
|
+
var import_react26 = require("react");
|
|
3984
|
+
var import_react_i18next6 = require("react-i18next");
|
|
3985
|
+
var import_material18 = require("@mui/material");
|
|
3986
|
+
var import_Translate4 = __toESM(require("@mui/icons-material/Translate"));
|
|
3987
|
+
var import_Clear2 = __toESM(require("@mui/icons-material/Clear"));
|
|
3988
|
+
init_context();
|
|
3989
|
+
init_translation_service();
|
|
3990
|
+
init_TranslationDialog();
|
|
3991
|
+
init_TranslatableTooltipComponent();
|
|
3992
|
+
|
|
3993
|
+
// src/hooks/useDebounce.ts
|
|
3994
|
+
var import_react25 = require("react");
|
|
3995
|
+
function useDebounce(value, delay = 500) {
|
|
3996
|
+
const [debouncedValue, setDebouncedValue] = (0, import_react25.useState)(value);
|
|
3997
|
+
(0, import_react25.useEffect)(() => {
|
|
3998
|
+
const timer = setTimeout(() => {
|
|
3999
|
+
setDebouncedValue(value);
|
|
4000
|
+
}, delay);
|
|
4001
|
+
return () => {
|
|
4002
|
+
clearTimeout(timer);
|
|
4003
|
+
};
|
|
4004
|
+
}, [value, delay]);
|
|
4005
|
+
return debouncedValue;
|
|
4006
|
+
}
|
|
4007
|
+
|
|
4008
|
+
// src/UI/components/inputs/SearchComponent.tsx
|
|
4009
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
4010
|
+
var SearchComponent = ({
|
|
4011
|
+
overrideNamespace,
|
|
4012
|
+
label = "",
|
|
4013
|
+
value = "",
|
|
4014
|
+
onChange,
|
|
4015
|
+
onClear,
|
|
4016
|
+
placeholderKey,
|
|
4017
|
+
clearTooltip = "Clear",
|
|
4018
|
+
debounceDelay = 500,
|
|
4019
|
+
onDebounceChange,
|
|
4020
|
+
slotProps,
|
|
4021
|
+
...restProps
|
|
4022
|
+
}) => {
|
|
4023
|
+
const supabase = useSupabase();
|
|
4024
|
+
const namespace = useTranslationNamespace();
|
|
4025
|
+
const { t, i18n: i18n2 } = (0, import_react_i18next6.useTranslation)(namespace);
|
|
4026
|
+
const { isTranslationMode } = useTranslationEdit();
|
|
4027
|
+
const [isDialogOpen, setIsDialogOpen] = (0, import_react26.useState)(false);
|
|
4028
|
+
const [localValue, setLocalValue] = (0, import_react26.useState)(String(value ?? ""));
|
|
4029
|
+
const debouncedValue = useDebounce(localValue, debounceDelay);
|
|
4030
|
+
(0, import_react26.useEffect)(() => {
|
|
4031
|
+
setLocalValue(String(value ?? ""));
|
|
4032
|
+
}, [value]);
|
|
4033
|
+
(0, import_react26.useEffect)(() => {
|
|
4034
|
+
if (onDebounceChange) {
|
|
4035
|
+
onDebounceChange(debouncedValue);
|
|
4036
|
+
}
|
|
4037
|
+
if (onChange && debouncedValue !== String(value ?? "")) {
|
|
4038
|
+
const syntheticEvent = {
|
|
4039
|
+
target: { value: debouncedValue },
|
|
4040
|
+
currentTarget: { value: debouncedValue }
|
|
4041
|
+
};
|
|
4042
|
+
onChange(syntheticEvent);
|
|
4043
|
+
}
|
|
4044
|
+
}, [debouncedValue]);
|
|
4045
|
+
const hasValue = localValue.length > 0;
|
|
4046
|
+
const handleChange = (e) => {
|
|
4047
|
+
setLocalValue(e.target.value);
|
|
4048
|
+
};
|
|
4049
|
+
const handleClear = (e) => {
|
|
4050
|
+
e.stopPropagation();
|
|
4051
|
+
setLocalValue("");
|
|
4052
|
+
if (onClear) {
|
|
4053
|
+
onClear();
|
|
4054
|
+
}
|
|
4055
|
+
if (onChange) {
|
|
4056
|
+
const syntheticEvent = {
|
|
4057
|
+
...e,
|
|
4058
|
+
target: { ...e.target, value: "" },
|
|
4059
|
+
currentTarget: { ...e.currentTarget, value: "" }
|
|
4060
|
+
};
|
|
4061
|
+
onChange(syntheticEvent);
|
|
4062
|
+
}
|
|
4063
|
+
};
|
|
4064
|
+
const translatedPlaceholder = placeholderKey ? t(placeholderKey) : void 0;
|
|
4065
|
+
const handleSaveTranslations = async (newValues, contextHint) => {
|
|
4066
|
+
if (!placeholderKey) return;
|
|
4067
|
+
const upsertData = Object.entries(newValues).map(([langCode, text]) => ({
|
|
4068
|
+
lang_code: langCode,
|
|
4069
|
+
namespace,
|
|
4070
|
+
key: placeholderKey,
|
|
4071
|
+
value: text,
|
|
4072
|
+
context_hint: contextHint
|
|
4073
|
+
}));
|
|
4074
|
+
const { error } = await supabase.from("translations").upsert(upsertData, { onConflict: "lang_code,namespace,key" });
|
|
4075
|
+
if (error) {
|
|
4076
|
+
alert("\u041F\u043E\u043C\u0438\u043B\u043A\u0430 \u043F\u0456\u0434 \u0447\u0430\u0441 \u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043D\u043D\u044F \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043D\u0438\u0445");
|
|
4077
|
+
throw error;
|
|
4078
|
+
}
|
|
4079
|
+
await translationService.incrementVersion(supabase, namespace, Object.keys(newValues));
|
|
4080
|
+
Object.entries(newValues).forEach(([langCode, text]) => {
|
|
4081
|
+
i18n2.addResource(langCode, namespace, placeholderKey, text);
|
|
4082
|
+
});
|
|
4083
|
+
};
|
|
4084
|
+
const renderEndAdornment = () => {
|
|
4085
|
+
const rawInputProps = slotProps?.input;
|
|
4086
|
+
const isInputObject = typeof rawInputProps === "object" && rawInputProps !== null;
|
|
4087
|
+
const existingEndAdornment = isInputObject && "endAdornment" in rawInputProps ? rawInputProps.endAdornment : void 0;
|
|
4088
|
+
if (!hasValue && (!isTranslationMode || !placeholderKey)) {
|
|
4089
|
+
return existingEndAdornment;
|
|
4090
|
+
}
|
|
4091
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
4092
|
+
existingEndAdornment,
|
|
4093
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_material18.InputAdornment, { position: "end", children: [
|
|
4094
|
+
hasValue && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TranslatableTooltipComponent, { title: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TranslateText, { overrideNamespace, children: clearTooltip }), children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
4095
|
+
import_material18.IconButton,
|
|
4096
|
+
{
|
|
4097
|
+
size: "small",
|
|
4098
|
+
onClick: handleClear,
|
|
4099
|
+
edge: "end",
|
|
4100
|
+
"aria-label": "clear input",
|
|
4101
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_Clear2.default, { fontSize: "small" })
|
|
4102
|
+
}
|
|
4103
|
+
) }),
|
|
4104
|
+
isTranslationMode && placeholderKey && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_material18.Tooltip, { title: `Translate placeholder: "${placeholderKey}"`, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
4105
|
+
import_material18.IconButton,
|
|
4106
|
+
{
|
|
4107
|
+
size: "small",
|
|
4108
|
+
onClick: (e) => {
|
|
4109
|
+
e.preventDefault();
|
|
4110
|
+
e.stopPropagation();
|
|
4111
|
+
setIsDialogOpen(true);
|
|
4112
|
+
},
|
|
4113
|
+
sx: {
|
|
4114
|
+
color: "#d97706",
|
|
4115
|
+
backgroundColor: "rgba(254, 243, 199, 0.6)",
|
|
4116
|
+
border: "1px dashed #f59e0b",
|
|
4117
|
+
p: "3px",
|
|
4118
|
+
ml: 0.5,
|
|
4119
|
+
"&:hover": {
|
|
4120
|
+
backgroundColor: "#fef08a"
|
|
4121
|
+
}
|
|
4122
|
+
},
|
|
4123
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_Translate4.default, { fontSize: "small" })
|
|
4124
|
+
}
|
|
4125
|
+
) })
|
|
4126
|
+
] })
|
|
4127
|
+
] });
|
|
4128
|
+
};
|
|
4129
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
4130
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
4131
|
+
import_material18.TextField,
|
|
4132
|
+
{
|
|
4133
|
+
...restProps,
|
|
4134
|
+
label: typeof label === "string" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(TranslateText, { overrideNamespace, children: label }) : label,
|
|
4135
|
+
value: localValue,
|
|
4136
|
+
onChange: handleChange,
|
|
4137
|
+
placeholder: translatedPlaceholder,
|
|
4138
|
+
slotProps: {
|
|
4139
|
+
...slotProps,
|
|
4140
|
+
input: {
|
|
4141
|
+
...slotProps?.input,
|
|
4142
|
+
endAdornment: renderEndAdornment()
|
|
4143
|
+
}
|
|
4144
|
+
}
|
|
4145
|
+
}
|
|
4146
|
+
),
|
|
4147
|
+
placeholderKey && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
4148
|
+
TranslationDialog,
|
|
4149
|
+
{
|
|
4150
|
+
open: isDialogOpen,
|
|
4151
|
+
onClose: () => setIsDialogOpen(false),
|
|
4152
|
+
translationKey: placeholderKey,
|
|
4153
|
+
namespace,
|
|
4154
|
+
onSave: handleSaveTranslations
|
|
4155
|
+
}
|
|
4156
|
+
)
|
|
4157
|
+
] });
|
|
4158
|
+
};
|
|
4159
|
+
|
|
4160
|
+
// src/UI/components/inputs/SelectComponent.tsx
|
|
4161
|
+
var import_material19 = require("@mui/material");
|
|
4162
|
+
var import_Close = __toESM(require("@mui/icons-material/Close"));
|
|
4163
|
+
init_context();
|
|
4164
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
4165
|
+
var SelectComponent = ({
|
|
4166
|
+
overrideNamespace,
|
|
4167
|
+
label,
|
|
4168
|
+
value,
|
|
4169
|
+
options,
|
|
4170
|
+
onChange,
|
|
4171
|
+
id = "translated-select",
|
|
4172
|
+
fullWidth,
|
|
4173
|
+
size = "medium",
|
|
4174
|
+
multiple = false,
|
|
4175
|
+
withCheckboxes = false,
|
|
4176
|
+
clearable = true,
|
|
4177
|
+
maxSelect,
|
|
4178
|
+
disabled,
|
|
4179
|
+
maxDisplayedTags = 2,
|
|
4180
|
+
helperText,
|
|
4181
|
+
defaultValueOnClear,
|
|
4182
|
+
sx,
|
|
4183
|
+
...restProps
|
|
4184
|
+
}) => {
|
|
4185
|
+
const labelId = `${id}-label`;
|
|
4186
|
+
const safeValue = multiple ? Array.isArray(value) ? value : [] : value ?? "";
|
|
4187
|
+
const selectedArray = multiple ? safeValue : [];
|
|
4188
|
+
const isLimitReached = Boolean(multiple && maxSelect && selectedArray.length >= maxSelect);
|
|
4189
|
+
const hasValue = multiple ? selectedArray.length > 0 : safeValue !== "" && safeValue !== null && safeValue !== void 0;
|
|
4190
|
+
const handleChange = (event, child) => {
|
|
4191
|
+
if (multiple && maxSelect) {
|
|
4192
|
+
const newValue = event.target.value;
|
|
4193
|
+
if (newValue.length > maxSelect) {
|
|
4194
|
+
return;
|
|
4195
|
+
}
|
|
4196
|
+
}
|
|
4197
|
+
onChange?.(event, child);
|
|
4198
|
+
};
|
|
4199
|
+
const handleClear = (e) => {
|
|
4200
|
+
e.stopPropagation();
|
|
4201
|
+
if (!onChange) return;
|
|
4202
|
+
const emptyValue = multiple ? [] : "";
|
|
4203
|
+
const targetValue = defaultValueOnClear !== void 0 ? defaultValueOnClear : emptyValue;
|
|
4204
|
+
const syntheticEvent = {
|
|
4205
|
+
target: {
|
|
4206
|
+
value: targetValue,
|
|
4207
|
+
name: restProps.name
|
|
4208
|
+
}
|
|
4209
|
+
};
|
|
4210
|
+
onChange(syntheticEvent, null);
|
|
4211
|
+
};
|
|
4212
|
+
const renderValueHandler = (selected) => {
|
|
4213
|
+
if (!multiple) return void 0;
|
|
4214
|
+
const currentSelected = selected;
|
|
4215
|
+
if (currentSelected.length === 0) return null;
|
|
4216
|
+
const selectedOptions = options.filter((opt) => currentSelected.includes(opt.value));
|
|
4217
|
+
const visibleLabels = selectedOptions.slice(0, maxDisplayedTags).map((opt) => typeof opt.label === "string" ? opt.label : String(opt.value));
|
|
4218
|
+
const hiddenCount = selectedOptions.length - maxDisplayedTags;
|
|
4219
|
+
if (hiddenCount > 0) {
|
|
4220
|
+
return `${visibleLabels.join(", ")} (+${hiddenCount})`;
|
|
4221
|
+
}
|
|
4222
|
+
return visibleLabels.join(", ");
|
|
4223
|
+
};
|
|
4224
|
+
const isSmall = size === "small";
|
|
4225
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
4226
|
+
import_material19.Tooltip,
|
|
4227
|
+
{
|
|
4228
|
+
title: multiple ? Array.isArray(value) ? options.filter((opt) => value.includes(opt.value)).map((opt) => typeof opt.label === "string" ? opt.label : String(opt.value)).join(", ") : "" : options.find((opt) => opt.value === value)?.label ?? String(value ?? ""),
|
|
4229
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material19.FormControl, { fullWidth, size, sx: { mt: 1 }, children: [
|
|
4230
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material19.InputLabel, { id: labelId, size: isSmall ? "small" : "medium", children: typeof label === "string" ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TranslateText, { overrideNamespace, children: label }) : label }),
|
|
4231
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
4232
|
+
import_material19.Select,
|
|
4233
|
+
{
|
|
4234
|
+
labelId,
|
|
4235
|
+
id,
|
|
4236
|
+
value: safeValue,
|
|
4237
|
+
label: typeof label === "string" ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TranslateText, { overrideNamespace, children: label }) : label,
|
|
4238
|
+
size,
|
|
4239
|
+
multiple,
|
|
4240
|
+
disabled,
|
|
4241
|
+
onChange: handleChange,
|
|
4242
|
+
renderValue: multiple ? renderValueHandler : void 0,
|
|
4243
|
+
...restProps,
|
|
4244
|
+
endAdornment: clearable && hasValue && !disabled ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material19.InputAdornment, { position: "end", sx: { mr: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
4245
|
+
import_material19.IconButton,
|
|
4246
|
+
{
|
|
4247
|
+
size: "small",
|
|
4248
|
+
onClick: handleClear,
|
|
4249
|
+
"aria-label": "clear selection",
|
|
4250
|
+
edge: "end",
|
|
4251
|
+
sx: { p: 0.5 },
|
|
4252
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_Close.default, { fontSize: "small" })
|
|
4253
|
+
}
|
|
4254
|
+
) }) : null,
|
|
4255
|
+
sx: {
|
|
4256
|
+
// 1. Задаем фиксированную высоту для всего контейнера инпута
|
|
4257
|
+
height: isSmall ? "40px" : "56px",
|
|
4258
|
+
minHeight: isSmall ? "40px" : "56px",
|
|
4259
|
+
// 2. Выравниваем внутренний класс текстового поля
|
|
4260
|
+
"& .MuiSelect-select": {
|
|
4261
|
+
display: "flex",
|
|
4262
|
+
alignItems: "center",
|
|
4263
|
+
boxSizing: "border-box",
|
|
4264
|
+
height: "100%",
|
|
4265
|
+
minHeight: "100% !important",
|
|
4266
|
+
py: 0,
|
|
4267
|
+
lineHeight: "normal",
|
|
4268
|
+
overflow: "hidden",
|
|
4269
|
+
textOverflow: "ellipsis",
|
|
4270
|
+
whiteSpace: "nowrap",
|
|
4271
|
+
paddingRight: clearable && hasValue ? "64px !important" : "32px !important"
|
|
4272
|
+
},
|
|
4273
|
+
// 3. Корректируем иконку стрелки выпадающего списка
|
|
4274
|
+
"& .MuiSelect-icon": {
|
|
4275
|
+
top: "calc(50% - 12px)"
|
|
4276
|
+
},
|
|
4277
|
+
// 4. Корректируем расположение иконки очистки
|
|
4278
|
+
"& .MuiInputAdornment-root": {
|
|
4279
|
+
maxHeight: "100%",
|
|
4280
|
+
height: "100%",
|
|
4281
|
+
alignItems: "center"
|
|
4282
|
+
},
|
|
4283
|
+
...sx
|
|
4284
|
+
},
|
|
4285
|
+
children: options.map((option) => {
|
|
4286
|
+
const isSelected = multiple && selectedArray.includes(option.value);
|
|
4287
|
+
const isDisabled = Boolean(isLimitReached && !isSelected);
|
|
4288
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
4289
|
+
import_material19.MenuItem,
|
|
4290
|
+
{
|
|
4291
|
+
value: option.value,
|
|
4292
|
+
disabled: isDisabled,
|
|
4293
|
+
children: [
|
|
4294
|
+
multiple && withCheckboxes && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material19.Checkbox, { checked: isSelected, size, disabled: isDisabled }),
|
|
4295
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
4296
|
+
import_material19.ListItemText,
|
|
4297
|
+
{
|
|
4298
|
+
primary: option.isItalic ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("em", { children: option.label }) : option.label
|
|
4299
|
+
}
|
|
4300
|
+
)
|
|
4301
|
+
]
|
|
4302
|
+
},
|
|
4303
|
+
String(option.value)
|
|
4304
|
+
);
|
|
4305
|
+
})
|
|
4306
|
+
}
|
|
4307
|
+
),
|
|
4308
|
+
helperText && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material19.FormHelperText, { children: helperText })
|
|
4309
|
+
] })
|
|
4310
|
+
}
|
|
4311
|
+
);
|
|
4312
|
+
};
|
|
4313
|
+
|
|
3982
4314
|
// src/UI/index.ts
|
|
3983
4315
|
var UI = {
|
|
3984
4316
|
Inputs: {
|
|
3985
4317
|
TextField: TextFieldComponent,
|
|
3986
4318
|
NumberField: NumberInputComponent,
|
|
3987
4319
|
EmailField: EmailInputComponent,
|
|
4320
|
+
Search: SearchComponent,
|
|
4321
|
+
Select: SelectComponent,
|
|
3988
4322
|
Url: UrlComponent
|
|
3989
4323
|
},
|
|
3990
4324
|
Buttons: {
|
|
@@ -4026,21 +4360,6 @@ var Services = {
|
|
|
4026
4360
|
}
|
|
4027
4361
|
};
|
|
4028
4362
|
|
|
4029
|
-
// src/hooks/useDebounce.ts
|
|
4030
|
-
var import_react25 = require("react");
|
|
4031
|
-
function useDebounce(value, delay = 500) {
|
|
4032
|
-
const [debouncedValue, setDebouncedValue] = (0, import_react25.useState)(value);
|
|
4033
|
-
(0, import_react25.useEffect)(() => {
|
|
4034
|
-
const timer = setTimeout(() => {
|
|
4035
|
-
setDebouncedValue(value);
|
|
4036
|
-
}, delay);
|
|
4037
|
-
return () => {
|
|
4038
|
-
clearTimeout(timer);
|
|
4039
|
-
};
|
|
4040
|
-
}, [value, delay]);
|
|
4041
|
-
return debouncedValue;
|
|
4042
|
-
}
|
|
4043
|
-
|
|
4044
4363
|
// src/hooks/index.ts
|
|
4045
4364
|
var Hooks = {
|
|
4046
4365
|
useDebounce
|
package/dist/index.mjs
CHANGED
|
@@ -1247,12 +1247,352 @@ var PublicLanguageSelector = () => {
|
|
|
1247
1247
|
] });
|
|
1248
1248
|
};
|
|
1249
1249
|
|
|
1250
|
+
// src/UI/components/inputs/SearchComponent.tsx
|
|
1251
|
+
import { useState as useState9, useEffect as useEffect5 } from "react";
|
|
1252
|
+
import { useTranslation as useTranslation3 } from "react-i18next";
|
|
1253
|
+
import { TextField as TextField3, InputAdornment as InputAdornment4, IconButton as IconButton5, Tooltip as Tooltip5 } from "@mui/material";
|
|
1254
|
+
import TranslateIcon2 from "@mui/icons-material/Translate";
|
|
1255
|
+
import ClearIcon2 from "@mui/icons-material/Clear";
|
|
1256
|
+
|
|
1257
|
+
// src/hooks/useDebounce.ts
|
|
1258
|
+
import { useEffect as useEffect4, useState as useState8 } from "react";
|
|
1259
|
+
function useDebounce(value, delay = 500) {
|
|
1260
|
+
const [debouncedValue, setDebouncedValue] = useState8(value);
|
|
1261
|
+
useEffect4(() => {
|
|
1262
|
+
const timer = setTimeout(() => {
|
|
1263
|
+
setDebouncedValue(value);
|
|
1264
|
+
}, delay);
|
|
1265
|
+
return () => {
|
|
1266
|
+
clearTimeout(timer);
|
|
1267
|
+
};
|
|
1268
|
+
}, [value, delay]);
|
|
1269
|
+
return debouncedValue;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
// src/UI/components/inputs/SearchComponent.tsx
|
|
1273
|
+
import { Fragment as Fragment7, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1274
|
+
var SearchComponent = ({
|
|
1275
|
+
overrideNamespace,
|
|
1276
|
+
label = "",
|
|
1277
|
+
value = "",
|
|
1278
|
+
onChange,
|
|
1279
|
+
onClear,
|
|
1280
|
+
placeholderKey,
|
|
1281
|
+
clearTooltip = "Clear",
|
|
1282
|
+
debounceDelay = 500,
|
|
1283
|
+
onDebounceChange,
|
|
1284
|
+
slotProps,
|
|
1285
|
+
...restProps
|
|
1286
|
+
}) => {
|
|
1287
|
+
const supabase = useSupabase();
|
|
1288
|
+
const namespace = useTranslationNamespace();
|
|
1289
|
+
const { t, i18n } = useTranslation3(namespace);
|
|
1290
|
+
const { isTranslationMode } = useTranslationEdit();
|
|
1291
|
+
const [isDialogOpen, setIsDialogOpen] = useState9(false);
|
|
1292
|
+
const [localValue, setLocalValue] = useState9(String(value ?? ""));
|
|
1293
|
+
const debouncedValue = useDebounce(localValue, debounceDelay);
|
|
1294
|
+
useEffect5(() => {
|
|
1295
|
+
setLocalValue(String(value ?? ""));
|
|
1296
|
+
}, [value]);
|
|
1297
|
+
useEffect5(() => {
|
|
1298
|
+
if (onDebounceChange) {
|
|
1299
|
+
onDebounceChange(debouncedValue);
|
|
1300
|
+
}
|
|
1301
|
+
if (onChange && debouncedValue !== String(value ?? "")) {
|
|
1302
|
+
const syntheticEvent = {
|
|
1303
|
+
target: { value: debouncedValue },
|
|
1304
|
+
currentTarget: { value: debouncedValue }
|
|
1305
|
+
};
|
|
1306
|
+
onChange(syntheticEvent);
|
|
1307
|
+
}
|
|
1308
|
+
}, [debouncedValue]);
|
|
1309
|
+
const hasValue = localValue.length > 0;
|
|
1310
|
+
const handleChange = (e) => {
|
|
1311
|
+
setLocalValue(e.target.value);
|
|
1312
|
+
};
|
|
1313
|
+
const handleClear = (e) => {
|
|
1314
|
+
e.stopPropagation();
|
|
1315
|
+
setLocalValue("");
|
|
1316
|
+
if (onClear) {
|
|
1317
|
+
onClear();
|
|
1318
|
+
}
|
|
1319
|
+
if (onChange) {
|
|
1320
|
+
const syntheticEvent = {
|
|
1321
|
+
...e,
|
|
1322
|
+
target: { ...e.target, value: "" },
|
|
1323
|
+
currentTarget: { ...e.currentTarget, value: "" }
|
|
1324
|
+
};
|
|
1325
|
+
onChange(syntheticEvent);
|
|
1326
|
+
}
|
|
1327
|
+
};
|
|
1328
|
+
const translatedPlaceholder = placeholderKey ? t(placeholderKey) : void 0;
|
|
1329
|
+
const handleSaveTranslations = async (newValues, contextHint) => {
|
|
1330
|
+
if (!placeholderKey) return;
|
|
1331
|
+
const upsertData = Object.entries(newValues).map(([langCode, text]) => ({
|
|
1332
|
+
lang_code: langCode,
|
|
1333
|
+
namespace,
|
|
1334
|
+
key: placeholderKey,
|
|
1335
|
+
value: text,
|
|
1336
|
+
context_hint: contextHint
|
|
1337
|
+
}));
|
|
1338
|
+
const { error } = await supabase.from("translations").upsert(upsertData, { onConflict: "lang_code,namespace,key" });
|
|
1339
|
+
if (error) {
|
|
1340
|
+
alert("\u041F\u043E\u043C\u0438\u043B\u043A\u0430 \u043F\u0456\u0434 \u0447\u0430\u0441 \u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043D\u043D\u044F \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043D\u0438\u0445");
|
|
1341
|
+
throw error;
|
|
1342
|
+
}
|
|
1343
|
+
await translationService.incrementVersion(supabase, namespace, Object.keys(newValues));
|
|
1344
|
+
Object.entries(newValues).forEach(([langCode, text]) => {
|
|
1345
|
+
i18n.addResource(langCode, namespace, placeholderKey, text);
|
|
1346
|
+
});
|
|
1347
|
+
};
|
|
1348
|
+
const renderEndAdornment = () => {
|
|
1349
|
+
const rawInputProps = slotProps?.input;
|
|
1350
|
+
const isInputObject = typeof rawInputProps === "object" && rawInputProps !== null;
|
|
1351
|
+
const existingEndAdornment = isInputObject && "endAdornment" in rawInputProps ? rawInputProps.endAdornment : void 0;
|
|
1352
|
+
if (!hasValue && (!isTranslationMode || !placeholderKey)) {
|
|
1353
|
+
return existingEndAdornment;
|
|
1354
|
+
}
|
|
1355
|
+
return /* @__PURE__ */ jsxs7(Fragment7, { children: [
|
|
1356
|
+
existingEndAdornment,
|
|
1357
|
+
/* @__PURE__ */ jsxs7(InputAdornment4, { position: "end", children: [
|
|
1358
|
+
hasValue && /* @__PURE__ */ jsx8(TranslatableTooltipComponent, { title: /* @__PURE__ */ jsx8(TranslateText, { overrideNamespace, children: clearTooltip }), children: /* @__PURE__ */ jsx8(
|
|
1359
|
+
IconButton5,
|
|
1360
|
+
{
|
|
1361
|
+
size: "small",
|
|
1362
|
+
onClick: handleClear,
|
|
1363
|
+
edge: "end",
|
|
1364
|
+
"aria-label": "clear input",
|
|
1365
|
+
children: /* @__PURE__ */ jsx8(ClearIcon2, { fontSize: "small" })
|
|
1366
|
+
}
|
|
1367
|
+
) }),
|
|
1368
|
+
isTranslationMode && placeholderKey && /* @__PURE__ */ jsx8(Tooltip5, { title: `Translate placeholder: "${placeholderKey}"`, children: /* @__PURE__ */ jsx8(
|
|
1369
|
+
IconButton5,
|
|
1370
|
+
{
|
|
1371
|
+
size: "small",
|
|
1372
|
+
onClick: (e) => {
|
|
1373
|
+
e.preventDefault();
|
|
1374
|
+
e.stopPropagation();
|
|
1375
|
+
setIsDialogOpen(true);
|
|
1376
|
+
},
|
|
1377
|
+
sx: {
|
|
1378
|
+
color: "#d97706",
|
|
1379
|
+
backgroundColor: "rgba(254, 243, 199, 0.6)",
|
|
1380
|
+
border: "1px dashed #f59e0b",
|
|
1381
|
+
p: "3px",
|
|
1382
|
+
ml: 0.5,
|
|
1383
|
+
"&:hover": {
|
|
1384
|
+
backgroundColor: "#fef08a"
|
|
1385
|
+
}
|
|
1386
|
+
},
|
|
1387
|
+
children: /* @__PURE__ */ jsx8(TranslateIcon2, { fontSize: "small" })
|
|
1388
|
+
}
|
|
1389
|
+
) })
|
|
1390
|
+
] })
|
|
1391
|
+
] });
|
|
1392
|
+
};
|
|
1393
|
+
return /* @__PURE__ */ jsxs7(Fragment7, { children: [
|
|
1394
|
+
/* @__PURE__ */ jsx8(
|
|
1395
|
+
TextField3,
|
|
1396
|
+
{
|
|
1397
|
+
...restProps,
|
|
1398
|
+
label: typeof label === "string" ? /* @__PURE__ */ jsx8(TranslateText, { overrideNamespace, children: label }) : label,
|
|
1399
|
+
value: localValue,
|
|
1400
|
+
onChange: handleChange,
|
|
1401
|
+
placeholder: translatedPlaceholder,
|
|
1402
|
+
slotProps: {
|
|
1403
|
+
...slotProps,
|
|
1404
|
+
input: {
|
|
1405
|
+
...slotProps?.input,
|
|
1406
|
+
endAdornment: renderEndAdornment()
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
),
|
|
1411
|
+
placeholderKey && /* @__PURE__ */ jsx8(
|
|
1412
|
+
TranslationDialog,
|
|
1413
|
+
{
|
|
1414
|
+
open: isDialogOpen,
|
|
1415
|
+
onClose: () => setIsDialogOpen(false),
|
|
1416
|
+
translationKey: placeholderKey,
|
|
1417
|
+
namespace,
|
|
1418
|
+
onSave: handleSaveTranslations
|
|
1419
|
+
}
|
|
1420
|
+
)
|
|
1421
|
+
] });
|
|
1422
|
+
};
|
|
1423
|
+
|
|
1424
|
+
// src/UI/components/inputs/SelectComponent.tsx
|
|
1425
|
+
import {
|
|
1426
|
+
FormControl,
|
|
1427
|
+
InputLabel,
|
|
1428
|
+
Select,
|
|
1429
|
+
MenuItem as MenuItem2,
|
|
1430
|
+
Checkbox,
|
|
1431
|
+
ListItemText,
|
|
1432
|
+
IconButton as IconButton6,
|
|
1433
|
+
InputAdornment as InputAdornment5,
|
|
1434
|
+
Tooltip as Tooltip6,
|
|
1435
|
+
FormHelperText
|
|
1436
|
+
} from "@mui/material";
|
|
1437
|
+
import CloseIcon from "@mui/icons-material/Close";
|
|
1438
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1439
|
+
var SelectComponent = ({
|
|
1440
|
+
overrideNamespace,
|
|
1441
|
+
label,
|
|
1442
|
+
value,
|
|
1443
|
+
options,
|
|
1444
|
+
onChange,
|
|
1445
|
+
id = "translated-select",
|
|
1446
|
+
fullWidth,
|
|
1447
|
+
size = "medium",
|
|
1448
|
+
multiple = false,
|
|
1449
|
+
withCheckboxes = false,
|
|
1450
|
+
clearable = true,
|
|
1451
|
+
maxSelect,
|
|
1452
|
+
disabled,
|
|
1453
|
+
maxDisplayedTags = 2,
|
|
1454
|
+
helperText,
|
|
1455
|
+
defaultValueOnClear,
|
|
1456
|
+
sx,
|
|
1457
|
+
...restProps
|
|
1458
|
+
}) => {
|
|
1459
|
+
const labelId = `${id}-label`;
|
|
1460
|
+
const safeValue = multiple ? Array.isArray(value) ? value : [] : value ?? "";
|
|
1461
|
+
const selectedArray = multiple ? safeValue : [];
|
|
1462
|
+
const isLimitReached = Boolean(multiple && maxSelect && selectedArray.length >= maxSelect);
|
|
1463
|
+
const hasValue = multiple ? selectedArray.length > 0 : safeValue !== "" && safeValue !== null && safeValue !== void 0;
|
|
1464
|
+
const handleChange = (event, child) => {
|
|
1465
|
+
if (multiple && maxSelect) {
|
|
1466
|
+
const newValue = event.target.value;
|
|
1467
|
+
if (newValue.length > maxSelect) {
|
|
1468
|
+
return;
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
onChange?.(event, child);
|
|
1472
|
+
};
|
|
1473
|
+
const handleClear = (e) => {
|
|
1474
|
+
e.stopPropagation();
|
|
1475
|
+
if (!onChange) return;
|
|
1476
|
+
const emptyValue = multiple ? [] : "";
|
|
1477
|
+
const targetValue = defaultValueOnClear !== void 0 ? defaultValueOnClear : emptyValue;
|
|
1478
|
+
const syntheticEvent = {
|
|
1479
|
+
target: {
|
|
1480
|
+
value: targetValue,
|
|
1481
|
+
name: restProps.name
|
|
1482
|
+
}
|
|
1483
|
+
};
|
|
1484
|
+
onChange(syntheticEvent, null);
|
|
1485
|
+
};
|
|
1486
|
+
const renderValueHandler = (selected) => {
|
|
1487
|
+
if (!multiple) return void 0;
|
|
1488
|
+
const currentSelected = selected;
|
|
1489
|
+
if (currentSelected.length === 0) return null;
|
|
1490
|
+
const selectedOptions = options.filter((opt) => currentSelected.includes(opt.value));
|
|
1491
|
+
const visibleLabels = selectedOptions.slice(0, maxDisplayedTags).map((opt) => typeof opt.label === "string" ? opt.label : String(opt.value));
|
|
1492
|
+
const hiddenCount = selectedOptions.length - maxDisplayedTags;
|
|
1493
|
+
if (hiddenCount > 0) {
|
|
1494
|
+
return `${visibleLabels.join(", ")} (+${hiddenCount})`;
|
|
1495
|
+
}
|
|
1496
|
+
return visibleLabels.join(", ");
|
|
1497
|
+
};
|
|
1498
|
+
const isSmall = size === "small";
|
|
1499
|
+
return /* @__PURE__ */ jsx9(
|
|
1500
|
+
Tooltip6,
|
|
1501
|
+
{
|
|
1502
|
+
title: multiple ? Array.isArray(value) ? options.filter((opt) => value.includes(opt.value)).map((opt) => typeof opt.label === "string" ? opt.label : String(opt.value)).join(", ") : "" : options.find((opt) => opt.value === value)?.label ?? String(value ?? ""),
|
|
1503
|
+
children: /* @__PURE__ */ jsxs8(FormControl, { fullWidth, size, sx: { mt: 1 }, children: [
|
|
1504
|
+
/* @__PURE__ */ jsx9(InputLabel, { id: labelId, size: isSmall ? "small" : "medium", children: typeof label === "string" ? /* @__PURE__ */ jsx9(TranslateText, { overrideNamespace, children: label }) : label }),
|
|
1505
|
+
/* @__PURE__ */ jsx9(
|
|
1506
|
+
Select,
|
|
1507
|
+
{
|
|
1508
|
+
labelId,
|
|
1509
|
+
id,
|
|
1510
|
+
value: safeValue,
|
|
1511
|
+
label: typeof label === "string" ? /* @__PURE__ */ jsx9(TranslateText, { overrideNamespace, children: label }) : label,
|
|
1512
|
+
size,
|
|
1513
|
+
multiple,
|
|
1514
|
+
disabled,
|
|
1515
|
+
onChange: handleChange,
|
|
1516
|
+
renderValue: multiple ? renderValueHandler : void 0,
|
|
1517
|
+
...restProps,
|
|
1518
|
+
endAdornment: clearable && hasValue && !disabled ? /* @__PURE__ */ jsx9(InputAdornment5, { position: "end", sx: { mr: 1 }, children: /* @__PURE__ */ jsx9(
|
|
1519
|
+
IconButton6,
|
|
1520
|
+
{
|
|
1521
|
+
size: "small",
|
|
1522
|
+
onClick: handleClear,
|
|
1523
|
+
"aria-label": "clear selection",
|
|
1524
|
+
edge: "end",
|
|
1525
|
+
sx: { p: 0.5 },
|
|
1526
|
+
children: /* @__PURE__ */ jsx9(CloseIcon, { fontSize: "small" })
|
|
1527
|
+
}
|
|
1528
|
+
) }) : null,
|
|
1529
|
+
sx: {
|
|
1530
|
+
// 1. Задаем фиксированную высоту для всего контейнера инпута
|
|
1531
|
+
height: isSmall ? "40px" : "56px",
|
|
1532
|
+
minHeight: isSmall ? "40px" : "56px",
|
|
1533
|
+
// 2. Выравниваем внутренний класс текстового поля
|
|
1534
|
+
"& .MuiSelect-select": {
|
|
1535
|
+
display: "flex",
|
|
1536
|
+
alignItems: "center",
|
|
1537
|
+
boxSizing: "border-box",
|
|
1538
|
+
height: "100%",
|
|
1539
|
+
minHeight: "100% !important",
|
|
1540
|
+
py: 0,
|
|
1541
|
+
lineHeight: "normal",
|
|
1542
|
+
overflow: "hidden",
|
|
1543
|
+
textOverflow: "ellipsis",
|
|
1544
|
+
whiteSpace: "nowrap",
|
|
1545
|
+
paddingRight: clearable && hasValue ? "64px !important" : "32px !important"
|
|
1546
|
+
},
|
|
1547
|
+
// 3. Корректируем иконку стрелки выпадающего списка
|
|
1548
|
+
"& .MuiSelect-icon": {
|
|
1549
|
+
top: "calc(50% - 12px)"
|
|
1550
|
+
},
|
|
1551
|
+
// 4. Корректируем расположение иконки очистки
|
|
1552
|
+
"& .MuiInputAdornment-root": {
|
|
1553
|
+
maxHeight: "100%",
|
|
1554
|
+
height: "100%",
|
|
1555
|
+
alignItems: "center"
|
|
1556
|
+
},
|
|
1557
|
+
...sx
|
|
1558
|
+
},
|
|
1559
|
+
children: options.map((option) => {
|
|
1560
|
+
const isSelected = multiple && selectedArray.includes(option.value);
|
|
1561
|
+
const isDisabled = Boolean(isLimitReached && !isSelected);
|
|
1562
|
+
return /* @__PURE__ */ jsxs8(
|
|
1563
|
+
MenuItem2,
|
|
1564
|
+
{
|
|
1565
|
+
value: option.value,
|
|
1566
|
+
disabled: isDisabled,
|
|
1567
|
+
children: [
|
|
1568
|
+
multiple && withCheckboxes && /* @__PURE__ */ jsx9(Checkbox, { checked: isSelected, size, disabled: isDisabled }),
|
|
1569
|
+
/* @__PURE__ */ jsx9(
|
|
1570
|
+
ListItemText,
|
|
1571
|
+
{
|
|
1572
|
+
primary: option.isItalic ? /* @__PURE__ */ jsx9("em", { children: option.label }) : option.label
|
|
1573
|
+
}
|
|
1574
|
+
)
|
|
1575
|
+
]
|
|
1576
|
+
},
|
|
1577
|
+
String(option.value)
|
|
1578
|
+
);
|
|
1579
|
+
})
|
|
1580
|
+
}
|
|
1581
|
+
),
|
|
1582
|
+
helperText && /* @__PURE__ */ jsx9(FormHelperText, { children: helperText })
|
|
1583
|
+
] })
|
|
1584
|
+
}
|
|
1585
|
+
);
|
|
1586
|
+
};
|
|
1587
|
+
|
|
1250
1588
|
// src/UI/index.ts
|
|
1251
1589
|
var UI = {
|
|
1252
1590
|
Inputs: {
|
|
1253
1591
|
TextField: TextFieldComponent,
|
|
1254
1592
|
NumberField: NumberInputComponent,
|
|
1255
1593
|
EmailField: EmailInputComponent,
|
|
1594
|
+
Search: SearchComponent,
|
|
1595
|
+
Select: SelectComponent,
|
|
1256
1596
|
Url: UrlComponent
|
|
1257
1597
|
},
|
|
1258
1598
|
Buttons: {
|
|
@@ -1289,21 +1629,6 @@ var Services = {
|
|
|
1289
1629
|
}
|
|
1290
1630
|
};
|
|
1291
1631
|
|
|
1292
|
-
// src/hooks/useDebounce.ts
|
|
1293
|
-
import { useEffect as useEffect4, useState as useState8 } from "react";
|
|
1294
|
-
function useDebounce(value, delay = 500) {
|
|
1295
|
-
const [debouncedValue, setDebouncedValue] = useState8(value);
|
|
1296
|
-
useEffect4(() => {
|
|
1297
|
-
const timer = setTimeout(() => {
|
|
1298
|
-
setDebouncedValue(value);
|
|
1299
|
-
}, delay);
|
|
1300
|
-
return () => {
|
|
1301
|
-
clearTimeout(timer);
|
|
1302
|
-
};
|
|
1303
|
-
}, [value, delay]);
|
|
1304
|
-
return debouncedValue;
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
1632
|
// src/hooks/index.ts
|
|
1308
1633
|
var Hooks = {
|
|
1309
1634
|
useDebounce
|