@koslibs/components 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/dist/components/Button/button.js +1 -0
  3. package/dist/components/Input/index.d.ts +2 -0
  4. package/dist/components/Input/index.js +1 -0
  5. package/dist/components/Input/index.module.js +25 -0
  6. package/dist/components/Input/index_module.css +312 -0
  7. package/dist/components/Input/input.d.ts +29 -0
  8. package/dist/components/Input/input.js +179 -0
  9. package/dist/components/Input/types.d.ts +115 -0
  10. package/dist/components/Input/types.js +0 -0
  11. package/dist/components/Input/vars.css +32 -0
  12. package/dist/components/Modal/colors.module.js +5 -0
  13. package/dist/components/Modal/colors_module.css +10 -0
  14. package/dist/components/Modal/components/content/index.d.ts +15 -0
  15. package/dist/components/Modal/components/content/index.js +19 -0
  16. package/dist/components/Modal/components/content/index.module.js +5 -0
  17. package/dist/components/Modal/components/content/index_module.css +12 -0
  18. package/dist/components/Modal/components/controls/index.d.ts +56 -0
  19. package/dist/components/Modal/components/controls/index.js +24 -0
  20. package/dist/components/Modal/components/controls/index.module.js +19 -0
  21. package/dist/components/Modal/components/controls/index_module.css +52 -0
  22. package/dist/components/Modal/components/footer/index.d.ts +15 -0
  23. package/dist/components/Modal/components/footer/index.js +19 -0
  24. package/dist/components/Modal/components/footer/index.module.js +5 -0
  25. package/dist/components/Modal/components/footer/index_module.css +9 -0
  26. package/dist/components/Modal/components/header/index.d.ts +43 -0
  27. package/dist/components/Modal/components/header/index.js +54 -0
  28. package/dist/components/Modal/components/header/index.module.js +8 -0
  29. package/dist/components/Modal/components/header/index_module.css +31 -0
  30. package/dist/components/Modal/components/modal-surface/index.d.ts +4 -0
  31. package/dist/components/Modal/components/modal-surface/index.js +81 -0
  32. package/dist/components/Modal/context.d.ts +6 -0
  33. package/dist/components/Modal/context.js +3 -0
  34. package/dist/components/Modal/index.d.ts +10 -0
  35. package/dist/components/Modal/index.js +5 -0
  36. package/dist/components/Modal/index.module.js +15 -0
  37. package/dist/components/Modal/index_module.css +46 -0
  38. package/dist/components/Modal/modal.d.ts +10 -0
  39. package/dist/components/Modal/modal.js +13 -0
  40. package/dist/components/Modal/types.d.ts +41 -0
  41. package/dist/components/Modal/types.js +0 -0
  42. package/dist/components/Modal/utils/lock-scroll.d.ts +1 -0
  43. package/dist/components/Modal/utils/lock-scroll.js +31 -0
  44. package/dist/components/Modal/vars.css +9 -0
  45. package/dist/components/Popover/popover.js +9 -7
  46. package/dist/components/Portal/index.d.ts +2 -0
  47. package/dist/components/Portal/index.js +1 -0
  48. package/dist/components/Portal/portal.d.ts +2 -0
  49. package/dist/components/Portal/portal.js +19 -0
  50. package/dist/components/Portal/types.d.ts +18 -0
  51. package/dist/components/Portal/types.js +0 -0
  52. package/dist/hooks/use-data-test-id.d.ts +5 -0
  53. package/dist/hooks/use-data-test-id.js +7 -0
  54. package/dist/index.d.ts +6 -0
  55. package/dist/index.js +3 -0
  56. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,58 @@
1
1
  # @koslibs/components
2
2
 
3
+ ## 1.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#6](https://github.com/koslibs/components/pull/6) [`360f774`](https://github.com/koslibs/components/commit/360f7746facda771d84165a16caeb6fe56abcc4a) Thanks [@holypower777](https://github.com/holypower777)! - Добавлен Input по дизайну Figma с view primary/secondary, размерами 40–72,
8
+ label внутри/снаружи, подсказками и ошибками, аддонами и очисткой.
9
+ Размер по умолчанию — 40.
10
+ Добавлен showValueLength для счётчика текущей длины и maxLength: внутри для inner,
11
+ снаружи рядом с label для outer. Поддержаны ввод, очистка и сброс формы.
12
+ Шрифт счётчика — 11 px; счётчик и label выровнены по базовой линии текста.
13
+ Сообщение ошибки заменяет hint; без hint отображается только красная рамка.
14
+ Поддержаны controlled/uncontrolled ввод, нативный ref и HTML-атрибуты,
15
+ disabled/readOnly и сброс формы. Добавлены Storybook и отдельный импорт.
16
+ Внутренний label поднимается при фокусе или заполнении поля; placeholder появляется
17
+ при фокусе, а после blur пустого поля label возвращается в центр.
18
+ Клики по отступам и декоративным аддонам фокусируют input, в том числе внутри
19
+ контейнеров с tabIndex; интерактивные аддоны сохраняют собственный фокус.
20
+ Формирование dataTestId частей Input и Modal унифицировано через общий внутренний
21
+ хук useDataTestId; существующие идентификаторы и наследование в Modal сохранены.
22
+ Убраны служебные ID сообщений и счётчика, автоматические aria-describedby и aria-invalid.
23
+ Обновлена зависимость @koslibs/icons до 1.2.0. В примерах Input используется
24
+ SearchIcon вместо локального SVG.
25
+
26
+ ## 1.4.0
27
+
28
+ ### Minor Changes
29
+
30
+ - [#5](https://github.com/koslibs/components/pull/5) [`68d3460`](https://github.com/koslibs/components/commit/68d34608d599582acf4115d31f64fb0168213edb) Thanks [@holypower777](https://github.com/holypower777)! - Перенесён Modal из GullEye core-components с Header, Content, Footer и Controls.
31
+ Добавлены прямой импорт `@koslibs/components/Modal`, размеры 480/600/720/960/fullscreen,
32
+ управляемое закрытие, блокировка прокрутки и поддержка вложенных окон.
33
+ Docs содержат вкладки документации, Props, CSS-переменных и истории изменений,
34
+ а также примеры длинного контента и Popover внутри нативного dialog.
35
+ Блокировка прокрутки учитывает `scrollbar-gutter: stable`, чтобы контент страницы
36
+ не смещался из-за двойной компенсации места под скроллбар.
37
+
38
+ Modal синхронизирован с документацией Figma: типографика Header 20 px semibold /
39
+ 14 px regular, крестик 18 px в области 48 × 32 px, Header без нижнего и Footer
40
+ без верхнего отступа. В строковых Controls две Button с block=true делят ширину
41
+ одной строки поровну с учётом gap; column растягивает кнопки по ширине вертикально.
42
+
43
+ Убран `Header.onClose`: крестик вызывает общий `Modal.onClose` через внутренний
44
+ React Context. Вложенный Header использует обработчик ближайшего Modal;
45
+ обработчик больше не нужно передавать отдельно в заголовок.
46
+
47
+ Header, Content, Footer и Controls наследуют `Modal.dataTestId` с суффиксами
48
+ `-header`, `-content`, `-footer`, `-controls`. Явный dataTestId части имеет приоритет;
49
+ вложенные окна используют только свой базовый идентификатор.
50
+
51
+ Добавлен отдельный Portal с `getPortalContainer`, `immediateMount`, ref на контейнер
52
+ и немедленным монтированием по умолчанию (`immediateMount=true`). Значение false
53
+ позволяет дождаться DOM-контейнера из ref. Modal и Popover используют
54
+ общий Portal; прямой импорт доступен через `@koslibs/components/Portal`.
55
+
3
56
  ## 1.3.0
4
57
 
5
58
  ### Minor Changes
@@ -76,6 +76,7 @@ const Button = /*#__PURE__*/ forwardRef(({ view = 'primary', shape = 'rectangula
76
76
  [colors_module.loading]: showLoader
77
77
  }, className),
78
78
  "data-test-id": dataTestId,
79
+ "data-block": block || void 0,
79
80
  type: type,
80
81
  disabled: disabled || showLoader,
81
82
  "aria-busy": showLoader,
@@ -0,0 +1,2 @@
1
+ export { Input } from './input.js';
2
+ export type { InputProps } from './types.js';
@@ -0,0 +1 @@
1
+ export { Input } from "./input.js";
@@ -0,0 +1,25 @@
1
+ import "./index_module.css";
2
+ const index_module = {
3
+ component: "component-aUdiT5",
4
+ "size-40": "size-40-afh8b8",
5
+ size40: "size-40-afh8b8",
6
+ "size-48": "size-48-MxoUiI",
7
+ size48: "size-48-MxoUiI",
8
+ "size-56": "size-56-p4fx5c",
9
+ size56: "size-56-p4fx5c",
10
+ "size-64": "size-64-p9mwzX",
11
+ size64: "size-64-p9mwzX",
12
+ "size-72": "size-72-csDcgy",
13
+ size72: "size-72-csDcgy",
14
+ field: "field-MFnvYv",
15
+ input: "input-IlmcAi",
16
+ value: "value-ehhHJ8",
17
+ header: "header-bcofZJ",
18
+ innerHeader: "innerHeader-Iga0Hb",
19
+ counter: "counter-C758Bk",
20
+ label: "label-tvCOwp",
21
+ addon: "addon-OXeKuK",
22
+ clear: "clear-A5Krz8",
23
+ message: "message-ArUnJU"
24
+ };
25
+ export default index_module;
@@ -0,0 +1,312 @@
1
+ @import "../../styles/theme.css";
2
+ @import "./vars.css";
3
+
4
+ .component-aUdiT5 {
5
+ --field-background: var(--input-primary-background-color);
6
+ --field-border: var(--input-border-color);
7
+ --field-color: var(--input-color);
8
+ --field-label-color: var(--input-label-color);
9
+ --field-placeholder-color: var(--input-placeholder-color);
10
+ --field-icon-color: var(--input-icon-color);
11
+ gap: var(--input-gap);
12
+ width: var(--input-width);
13
+ vertical-align: top;
14
+ min-width: 0;
15
+ max-width: 100%;
16
+ font-family: var(--font-primary);
17
+ color: var(--field-color);
18
+ flex-direction: column;
19
+ display: inline-flex;
20
+
21
+ &[data-block] {
22
+ width: 100%;
23
+ display: flex;
24
+ }
25
+
26
+ &[data-view="secondary"] {
27
+ --field-background: var(--input-secondary-background-color);
28
+ }
29
+
30
+ &[data-read-only] {
31
+ --field-border: var(--input-read-only-border-color);
32
+ }
33
+
34
+ &[data-error] {
35
+ --field-border: var(--input-error-border-color);
36
+ }
37
+
38
+ &[data-disabled] {
39
+ --field-background: var(--input-disabled-background-color);
40
+ --field-border: transparent;
41
+ --field-color: var(--input-disabled-color);
42
+ --field-label-color: var(--input-disabled-color);
43
+ --field-placeholder-color: var(--input-disabled-color);
44
+ --field-icon-color: var(--input-disabled-color);
45
+ }
46
+ }
47
+
48
+ .size-40-afh8b8 {
49
+ --field-height: 40px;
50
+ --field-padding: var(--input-padding-40);
51
+ --field-font-size: var(--input-font-size-40);
52
+ --field-line-height: 17px;
53
+ }
54
+
55
+ .size-48-MxoUiI {
56
+ --field-height: 48px;
57
+ --field-padding: var(--input-padding-48);
58
+ --field-font-size: var(--input-font-size-48);
59
+ --field-line-height: 17px;
60
+ }
61
+
62
+ .size-56-p4fx5c {
63
+ --field-height: 56px;
64
+ --field-padding: var(--input-padding-56);
65
+ --field-font-size: var(--input-font-size-56);
66
+ --field-line-height: 17px;
67
+ }
68
+
69
+ .size-64-p9mwzX {
70
+ --field-height: 64px;
71
+ --field-padding: var(--input-padding-64);
72
+ --field-font-size: var(--input-font-size-64);
73
+ --field-line-height: 17px;
74
+ }
75
+
76
+ .size-72-csDcgy {
77
+ --field-height: 72px;
78
+ --field-padding: var(--input-padding-72);
79
+ --field-font-size: var(--input-font-size-72);
80
+ --field-line-height: 20px;
81
+ }
82
+
83
+ .field-MFnvYv {
84
+ box-sizing: border-box;
85
+ align-items: center;
86
+ gap: var(--input-gap);
87
+ width: 100%;
88
+ height: var(--field-height);
89
+ padding: 0 var(--field-padding);
90
+ border-radius: var(--input-border-radius);
91
+ background: var(--field-background);
92
+ box-shadow: inset 0 0 0 1px var(--field-border);
93
+ cursor: text;
94
+ display: flex;
95
+ }
96
+
97
+ @media (hover: hover) {
98
+ .component-aUdiT5:not([data-disabled], [data-read-only], [data-error]) .field-MFnvYv:hover {
99
+ box-shadow: inset 0 0 0 1px var(--input-hover-border-color);
100
+ }
101
+ }
102
+
103
+ .component-aUdiT5:not([data-disabled]) .field-MFnvYv:focus-within {
104
+ box-shadow: none;
105
+ outline: 2px solid var(--input-focus-border-color);
106
+ outline-offset: 0;
107
+ }
108
+
109
+ .component-aUdiT5[data-error]:not([data-disabled]) .field-MFnvYv:focus-within {
110
+ outline-color: var(--input-error-border-color);
111
+ }
112
+
113
+ .component-aUdiT5[data-disabled] .field-MFnvYv, .input-IlmcAi:disabled {
114
+ cursor: not-allowed;
115
+ }
116
+
117
+ .value-ehhHJ8 {
118
+ flex-direction: column;
119
+ flex: 1;
120
+ min-width: 0;
121
+ display: flex;
122
+ position: relative;
123
+ }
124
+
125
+ .header-bcofZJ {
126
+ align-items: baseline;
127
+ gap: var(--input-gap);
128
+ min-width: 0;
129
+ display: flex;
130
+ }
131
+
132
+ .innerHeader-Iga0Hb {
133
+ width: 100%;
134
+ position: absolute;
135
+ top: 0;
136
+ left: 0;
137
+ }
138
+
139
+ .component-aUdiT5 .counter-C758Bk {
140
+ color: var(--field-label-color);
141
+ white-space: nowrap;
142
+ text-align: right;
143
+ font-variant-numeric: tabular-nums;
144
+ flex-shrink: 0;
145
+ margin-left: auto;
146
+ line-height: 16px;
147
+ }
148
+
149
+ .innerHeader-Iga0Hb .counter-C758Bk {
150
+ line-height: 15px;
151
+ }
152
+
153
+ .label-tvCOwp {
154
+ min-width: 0;
155
+ color: var(--field-label-color);
156
+ overflow-wrap: anywhere;
157
+ cursor: inherit;
158
+ flex: 1;
159
+ font-size: 13px;
160
+ line-height: 16px;
161
+ display: block;
162
+ }
163
+
164
+ .component-aUdiT5[data-inner-label] .label-tvCOwp {
165
+ white-space: nowrap;
166
+ text-overflow: ellipsis;
167
+ font-size: var(--field-font-size);
168
+ line-height: var(--field-line-height);
169
+ transition: transform .18s, font-size .18s, line-height .18s;
170
+ overflow: hidden;
171
+ transform: translateY(7.5px);
172
+
173
+ & > span {
174
+ font-size: inherit;
175
+ line-height: inherit;
176
+ }
177
+ }
178
+
179
+ .component-aUdiT5[data-inner-label][data-filled] .label-tvCOwp, .component-aUdiT5[data-inner-label]:not([data-disabled], [data-read-only]) .value-ehhHJ8:focus-within .label-tvCOwp {
180
+ font-size: 12px;
181
+ line-height: 15px;
182
+ transform: translateY(0);
183
+ }
184
+
185
+ .component-aUdiT5[data-inner-label] .value-ehhHJ8:has(.input-IlmcAi:autofill) .label-tvCOwp {
186
+ font-size: 12px;
187
+ line-height: 15px;
188
+ transform: translateY(0);
189
+ }
190
+
191
+ .component-aUdiT5[data-inner-label] .input-IlmcAi {
192
+ margin-top: 15px;
193
+
194
+ &::placeholder {
195
+ opacity: 0;
196
+ transition: opacity .18s;
197
+ }
198
+ }
199
+
200
+ .component-aUdiT5[data-inner-label]:not([data-disabled], [data-read-only]) .input-IlmcAi:focus::placeholder {
201
+ opacity: 1;
202
+ }
203
+
204
+ .component-aUdiT5[data-inner-counter]:not([data-inner-label]) .input-IlmcAi {
205
+ margin-top: 15px;
206
+ }
207
+
208
+ @media (prefers-reduced-motion: reduce) {
209
+ .component-aUdiT5[data-inner-label] .label-tvCOwp, .component-aUdiT5[data-inner-label] .input-IlmcAi::placeholder {
210
+ transition: none;
211
+ }
212
+ }
213
+
214
+ .input-IlmcAi {
215
+ box-sizing: border-box;
216
+ width: 100%;
217
+ min-width: 0;
218
+ height: var(--field-line-height);
219
+ color: var(--field-color);
220
+ font-family: var(--font-primary);
221
+ font-size: var(--field-font-size);
222
+ font-weight: 400;
223
+ line-height: var(--field-line-height);
224
+ text-overflow: ellipsis;
225
+ appearance: none;
226
+ background: none;
227
+ border: 0;
228
+ border-radius: 0;
229
+ outline: none;
230
+ margin: 0;
231
+ padding: 0;
232
+ display: block;
233
+
234
+ &:focus {
235
+ text-overflow: clip;
236
+ }
237
+
238
+ &::placeholder {
239
+ color: var(--field-placeholder-color);
240
+ opacity: 1;
241
+ }
242
+
243
+ &:disabled {
244
+ opacity: 1;
245
+ -webkit-text-fill-color: var(--field-color);
246
+ }
247
+
248
+ &:-webkit-autofill {
249
+ -webkit-text-fill-color: var(--field-color);
250
+ box-shadow: inset 0 0 0 1000px var(--field-background);
251
+ }
252
+
253
+ &::-webkit-search-cancel-button {
254
+ appearance: none;
255
+ }
256
+
257
+ &::-webkit-search-decoration {
258
+ appearance: none;
259
+ }
260
+ }
261
+
262
+ .addon-OXeKuK {
263
+ align-items: center;
264
+ gap: var(--input-gap);
265
+ color: var(--field-icon-color);
266
+ font-size: var(--field-font-size);
267
+ line-height: var(--field-line-height);
268
+ flex-shrink: 0;
269
+ display: flex;
270
+ }
271
+
272
+ .component-aUdiT5 .clear-A5Krz8 {
273
+ width: 24px;
274
+ min-width: 0;
275
+ height: 24px;
276
+ min-height: 0;
277
+ color: var(--field-icon-color);
278
+ background: none;
279
+ flex: 0 0 24px;
280
+ margin: 0 -4px;
281
+ padding: 0;
282
+
283
+ &:hover, &:active {
284
+ color: var(--field-icon-color);
285
+ }
286
+
287
+ &:focus-visible {
288
+ outline: 2px solid var(--input-focus-border-color);
289
+ outline-offset: 2px;
290
+ }
291
+
292
+ & svg {
293
+ width: var(--input-icon-size);
294
+ height: var(--input-icon-size);
295
+ display: block;
296
+ }
297
+ }
298
+
299
+ .component-aUdiT5 .message-ArUnJU {
300
+ color: var(--input-hint-color);
301
+ overflow-wrap: anywhere;
302
+ line-height: 15px;
303
+ }
304
+
305
+ .component-aUdiT5[data-error] .message-ArUnJU {
306
+ color: var(--input-error-message-color);
307
+ }
308
+
309
+ .component-aUdiT5[data-disabled] .message-ArUnJU {
310
+ color: var(--input-disabled-color);
311
+ }
312
+
@@ -0,0 +1,29 @@
1
+ import { type ChangeEvent, type MouseEvent } from 'react';
2
+ export declare const Input: import("react").ForwardRefExoticComponent<Omit<import("react").InputHTMLAttributes<HTMLInputElement>, "size" | "value" | "defaultValue" | "children" | "onChange" | "maxLength"> & {
3
+ value?: string;
4
+ defaultValue?: string;
5
+ maxLength?: number;
6
+ showValueLength?: boolean;
7
+ view?: "primary" | "secondary";
8
+ size?: 40 | 48 | 56 | 64 | 72;
9
+ block?: boolean;
10
+ label?: import("react").ReactNode;
11
+ labelView?: "outer" | "inner";
12
+ hint?: import("react").ReactNode;
13
+ error?: import("react").ReactNode | boolean;
14
+ leftAddon?: import("react").ReactNode;
15
+ rightAddon?: import("react").ReactNode;
16
+ clear?: boolean;
17
+ clearLabel?: string;
18
+ onChange?: (event: ChangeEvent<HTMLInputElement>, payload: {
19
+ value: string;
20
+ }) => void;
21
+ onClear?: (event: MouseEvent<HTMLButtonElement>) => void;
22
+ className?: string;
23
+ style?: import("react").CSSProperties;
24
+ fieldClassName?: string;
25
+ inputClassName?: string;
26
+ labelClassName?: string;
27
+ messageClassName?: string;
28
+ dataTestId?: string;
29
+ } & import("react").RefAttributes<HTMLInputElement>>;
@@ -0,0 +1,179 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { CrossHeavyMIcon } from "@koslibs/icons/CrossHeavyMIcon";
3
+ import classnames from "classnames";
4
+ import { forwardRef, useEffect, useId, useImperativeHandle, useRef, useState } from "react";
5
+ import { useDataTestId } from "../../hooks/use-data-test-id.js";
6
+ import { Button } from "../Button/index.js";
7
+ import { TypographyText } from "../Typography/text.js";
8
+ import index_module from "./index.module.js";
9
+ const Input = /*#__PURE__*/ forwardRef(({ view = 'primary', size = 40, block = false, label, labelView = 'outer', hint, error, leftAddon, rightAddon, clear = false, clearLabel = 'Очистить поле', value, defaultValue, maxLength, showValueLength = false, onChange, onClear, disabled = false, readOnly = false, type = 'text', id, className, style, fieldClassName, inputClassName, labelClassName, messageClassName, dataTestId, ...restProps }, ref)=>{
10
+ const generatedId = useId();
11
+ const inputId = id ?? generatedId;
12
+ const inputRef = useRef(null);
13
+ const [uncontrolledLength, setUncontrolledLength] = useState(defaultValue?.length ?? 0);
14
+ const controlled = void 0 !== value;
15
+ const valueLength = controlled ? value.length : uncontrolledLength;
16
+ const hasValue = valueLength > 0;
17
+ const showCounter = showValueLength && void 0 !== maxLength && Number.isInteger(maxLength) && maxLength >= 0;
18
+ const hasLabel = null != label && false !== label && '' !== label;
19
+ const hasError = Boolean(error);
20
+ const errorMessage = hint && 'boolean' != typeof error ? error : void 0;
21
+ const message = errorMessage || hint;
22
+ const hasMessage = Boolean(message);
23
+ const showClear = clear && hasValue && !disabled && !readOnly;
24
+ const getDataTestId = useDataTestId(dataTestId);
25
+ useImperativeHandle(ref, ()=>inputRef.current, []);
26
+ useEffect(()=>{
27
+ const input = inputRef.current;
28
+ const form = input?.form;
29
+ let active = true;
30
+ const handleReset = (event)=>{
31
+ queueMicrotask(()=>{
32
+ if (active && !event.defaultPrevented) setUncontrolledLength(input?.value.length ?? 0);
33
+ });
34
+ };
35
+ form?.addEventListener('reset', handleReset);
36
+ return ()=>{
37
+ active = false;
38
+ form?.removeEventListener('reset', handleReset);
39
+ };
40
+ }, [
41
+ restProps.form
42
+ ]);
43
+ const handleChange = (event)=>{
44
+ const nextValue = event.target.value;
45
+ if (!controlled) setUncontrolledLength(nextValue.length);
46
+ onChange?.(event, {
47
+ value: nextValue
48
+ });
49
+ };
50
+ const handleClear = (event)=>{
51
+ const input = inputRef.current;
52
+ if (!input || !showClear) return;
53
+ if (!controlled) {
54
+ input.value = '';
55
+ setUncontrolledLength(0);
56
+ }
57
+ onClear?.(event);
58
+ input.focus();
59
+ };
60
+ const handleFieldClick = (event)=>{
61
+ if (disabled || event.defaultPrevented || !(event.target instanceof Element)) return;
62
+ const interactiveTarget = event.target.closest('input, button, a, label, select, textarea, [role="button"], [contenteditable], [tabindex]');
63
+ if (interactiveTarget && event.currentTarget.contains(interactiveTarget)) return;
64
+ inputRef.current?.focus();
65
+ };
66
+ const labelElement = hasLabel && /*#__PURE__*/ jsx("label", {
67
+ htmlFor: inputId,
68
+ className: classnames(index_module.label, labelClassName),
69
+ "data-test-id": getDataTestId('label'),
70
+ children: /*#__PURE__*/ jsx(TypographyText, {
71
+ size: 'inner' === labelView ? 12 : 13,
72
+ weight: 'inner' === labelView ? 'regular' : 'medium',
73
+ children: label
74
+ })
75
+ });
76
+ const counterElement = showCounter && /*#__PURE__*/ jsxs(TypographyText, {
77
+ tag: "span",
78
+ size: 11,
79
+ className: index_module.counter,
80
+ style: {
81
+ minWidth: `${2 * String(maxLength).length + 1}ch`
82
+ },
83
+ dataTestId: getDataTestId('counter'),
84
+ children: [
85
+ valueLength,
86
+ "/",
87
+ maxLength
88
+ ]
89
+ });
90
+ return /*#__PURE__*/ jsxs("div", {
91
+ className: classnames(index_module.component, index_module[`size-${size}`], className),
92
+ style: style,
93
+ "data-view": view,
94
+ "data-block": block || void 0,
95
+ "data-disabled": disabled || void 0,
96
+ "data-read-only": readOnly || void 0,
97
+ "data-error": hasError || void 0,
98
+ "data-label-view": labelView,
99
+ "data-inner-label": 'inner' === labelView && hasLabel || void 0,
100
+ "data-inner-counter": 'inner' === labelView && showCounter || void 0,
101
+ "data-filled": hasValue || void 0,
102
+ "data-test-id": getDataTestId('form-control'),
103
+ children: [
104
+ 'outer' === labelView && (hasLabel || showCounter) && /*#__PURE__*/ jsxs("div", {
105
+ className: index_module.header,
106
+ children: [
107
+ labelElement,
108
+ counterElement
109
+ ]
110
+ }),
111
+ /*#__PURE__*/ jsxs("div", {
112
+ className: classnames(index_module.field, fieldClassName),
113
+ onClick: handleFieldClick,
114
+ "data-test-id": getDataTestId('field'),
115
+ children: [
116
+ leftAddon && /*#__PURE__*/ jsx("div", {
117
+ className: index_module.addon,
118
+ "data-test-id": getDataTestId('left-addon'),
119
+ children: leftAddon
120
+ }),
121
+ /*#__PURE__*/ jsxs("div", {
122
+ className: index_module.value,
123
+ children: [
124
+ 'inner' === labelView && (hasLabel || showCounter) && /*#__PURE__*/ jsxs("div", {
125
+ className: classnames(index_module.header, index_module.innerHeader),
126
+ children: [
127
+ labelElement,
128
+ counterElement
129
+ ]
130
+ }),
131
+ /*#__PURE__*/ jsx("input", {
132
+ ...restProps,
133
+ ref: inputRef,
134
+ id: inputId,
135
+ type: type,
136
+ value: value,
137
+ defaultValue: defaultValue,
138
+ maxLength: maxLength,
139
+ disabled: disabled,
140
+ readOnly: readOnly,
141
+ onChange: handleChange,
142
+ className: classnames(index_module.input, inputClassName),
143
+ "data-test-id": dataTestId
144
+ })
145
+ ]
146
+ }),
147
+ showClear && /*#__PURE__*/ jsx(Button, {
148
+ view: "text",
149
+ size: 32,
150
+ className: index_module.clear,
151
+ "aria-label": clearLabel,
152
+ onMouseDown: (event)=>event.preventDefault(),
153
+ onClick: handleClear,
154
+ dataTestId: getDataTestId('clear'),
155
+ children: /*#__PURE__*/ jsx(CrossHeavyMIcon, {
156
+ width: 16,
157
+ height: 16,
158
+ "aria-hidden": "true"
159
+ })
160
+ }),
161
+ rightAddon && /*#__PURE__*/ jsx("div", {
162
+ className: index_module.addon,
163
+ "data-test-id": getDataTestId('right-addon'),
164
+ children: rightAddon
165
+ })
166
+ ]
167
+ }),
168
+ hasMessage && /*#__PURE__*/ jsx(TypographyText, {
169
+ tag: "div",
170
+ size: 12,
171
+ className: classnames(index_module.message, messageClassName),
172
+ dataTestId: getDataTestId(errorMessage ? 'error' : 'hint'),
173
+ children: message
174
+ })
175
+ ]
176
+ });
177
+ });
178
+ Input.displayName = 'Input';
179
+ export { Input };